ant-design-vue
Version:
An enterprise-class UI design language and Vue-based implementation
565 lines (564 loc) • 22.7 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.tabNavListProps = exports.default = void 0;
var _vue = require("vue");
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _useRaf = require("../hooks/useRaf");
var _TabNode = _interopRequireDefault(require("./TabNode"));
var _useOffsets = _interopRequireDefault(require("../hooks/useOffsets"));
var _OperationNode = _interopRequireDefault(require("./OperationNode"));
var _TabContext = require("../TabContext");
var _useTouchMove = _interopRequireDefault(require("../hooks/useTouchMove"));
var _AddButton = _interopRequireDefault(require("./AddButton"));
var _vueTypes = _interopRequireDefault(require("../../../_util/vue-types"));
var _useSyncState5 = _interopRequireDefault(require("../hooks/useSyncState"));
var _useState17 = _interopRequireDefault(require("../../../_util/hooks/useState"));
var _raf = _interopRequireDefault(require("../../../_util/raf"));
var _classNames3 = _interopRequireDefault(require("../../../_util/classNames"));
var _vcResizeObserver = _interopRequireDefault(require("../../../vc-resize-observer"));
var _util = require("../../../_util/util");
var _useRefs3 = _interopRequireDefault(require("../../../_util/hooks/useRefs"));
var _pick = _interopRequireDefault(require("lodash/pick"));
var DEFAULT_SIZE = {
width: 0,
height: 0,
left: 0,
top: 0,
right: 0
};
var tabNavListProps = function tabNavListProps() {
return {
id: {
type: String
},
tabPosition: {
type: String
},
activeKey: {
type: [String, Number]
},
rtl: {
type: Boolean
},
animated: {
type: Object,
default: undefined
},
editable: {
type: Object
},
moreIcon: _vueTypes.default.any,
moreTransitionName: {
type: String
},
mobile: {
type: Boolean
},
tabBarGutter: {
type: Number
},
renderTabBar: {
type: Function
},
locale: {
type: Object,
default: undefined
},
onTabClick: {
type: Function
},
onTabScroll: {
type: Function
}
};
};
exports.tabNavListProps = tabNavListProps;
var _default2 = (0, _vue.defineComponent)({
compatConfig: {
MODE: 3
},
name: 'TabNavList',
inheritAttrs: false,
props: tabNavListProps(),
slots: ['moreIcon', 'leftExtra', 'rightExtra', 'tabBarExtraContent'],
emits: ['tabClick', 'tabScroll'],
setup: function setup(props, _ref) {
var attrs = _ref.attrs,
slots = _ref.slots;
var _useInjectTabs = (0, _TabContext.useInjectTabs)(),
tabs = _useInjectTabs.tabs,
prefixCls = _useInjectTabs.prefixCls;
var tabsWrapperRef = (0, _vue.ref)();
var tabListRef = (0, _vue.ref)();
var operationsRef = (0, _vue.ref)();
var innerAddButtonRef = (0, _vue.ref)();
var _useRefs = (0, _useRefs3.default)(),
_useRefs2 = (0, _slicedToArray2.default)(_useRefs, 2),
setRef = _useRefs2[0],
btnRefs = _useRefs2[1];
var tabPositionTopOrBottom = (0, _vue.computed)(function () {
return props.tabPosition === 'top' || props.tabPosition === 'bottom';
});
var _useSyncState = (0, _useSyncState5.default)(0, function (next, prev) {
if (tabPositionTopOrBottom.value && props.onTabScroll) {
props.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.value && props.onTabScroll) {
props.onTabScroll({
direction: next > prev ? 'top' : 'bottom'
});
}
}),
_useSyncState4 = (0, _slicedToArray2.default)(_useSyncState3, 2),
transformTop = _useSyncState4[0],
setTransformTop = _useSyncState4[1];
var _useState = (0, _useState17.default)(0),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
wrapperScrollWidth = _useState2[0],
setWrapperScrollWidth = _useState2[1];
var _useState3 = (0, _useState17.default)(0),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
wrapperScrollHeight = _useState4[0],
setWrapperScrollHeight = _useState4[1];
var _useState5 = (0, _useState17.default)(null),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
wrapperWidth = _useState6[0],
setWrapperWidth = _useState6[1];
var _useState7 = (0, _useState17.default)(null),
_useState8 = (0, _slicedToArray2.default)(_useState7, 2),
wrapperHeight = _useState8[0],
setWrapperHeight = _useState8[1];
var _useState9 = (0, _useState17.default)(0),
_useState10 = (0, _slicedToArray2.default)(_useState9, 2),
addWidth = _useState10[0],
setAddWidth = _useState10[1];
var _useState11 = (0, _useState17.default)(0),
_useState12 = (0, _slicedToArray2.default)(_useState11, 2),
addHeight = _useState12[0],
setAddHeight = _useState12[1];
var _useRafState = (0, _useRaf.useRafState)(new Map()),
_useRafState2 = (0, _slicedToArray2.default)(_useRafState, 2),
tabSizes = _useRafState2[0],
setTabSizes = _useRafState2[1];
var tabOffsets = (0, _useOffsets.default)(tabs, tabSizes);
// ========================== Util =========================
var operationsHiddenClassName = (0, _vue.computed)(function () {
return "".concat(prefixCls.value, "-nav-operations-hidden");
});
var transformMin = (0, _vue.ref)(0);
var transformMax = (0, _vue.ref)(0);
(0, _vue.watchEffect)(function () {
if (!tabPositionTopOrBottom.value) {
transformMin.value = Math.min(0, wrapperHeight.value - wrapperScrollHeight.value);
transformMax.value = 0;
} else if (props.rtl) {
transformMin.value = 0;
transformMax.value = Math.max(0, wrapperScrollWidth.value - wrapperWidth.value);
} else {
transformMin.value = Math.min(0, wrapperWidth.value - wrapperScrollWidth.value);
transformMax.value = 0;
}
});
var alignInRange = function alignInRange(value) {
if (value < transformMin.value) {
return transformMin.value;
}
if (value > transformMax.value) {
return transformMax.value;
}
return value;
};
// ========================= Mobile ========================
var touchMovingRef = (0, _vue.ref)();
var _useState13 = (0, _useState17.default)(),
_useState14 = (0, _slicedToArray2.default)(_useState13, 2),
lockAnimation = _useState14[0],
setLockAnimation = _useState14[1];
var doLockAnimation = function doLockAnimation() {
setLockAnimation(Date.now());
};
var clearTouchMoving = function clearTouchMoving() {
clearTimeout(touchMovingRef.value);
};
var doMove = function doMove(setState, offset) {
setState(function (value) {
var newValue = alignInRange(value + offset);
return newValue;
});
};
(0, _useTouchMove.default)(tabsWrapperRef, function (offsetX, offsetY) {
if (tabPositionTopOrBottom.value) {
// Skip scroll if place is enough
if (wrapperWidth.value >= wrapperScrollWidth.value) {
return false;
}
doMove(setTransformLeft, offsetX);
} else {
if (wrapperHeight.value >= wrapperScrollHeight.value) {
return false;
}
doMove(setTransformTop, offsetY);
}
clearTouchMoving();
doLockAnimation();
return true;
});
(0, _vue.watch)(lockAnimation, function () {
clearTouchMoving();
if (lockAnimation.value) {
touchMovingRef.value = setTimeout(function () {
setLockAnimation(0);
}, 100);
}
});
// ========================= Scroll ========================
var scrollToTab = function scrollToTab() {
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : props.activeKey;
var tabOffset = tabOffsets.value.get(key) || {
width: 0,
height: 0,
left: 0,
right: 0,
top: 0
};
if (tabPositionTopOrBottom.value) {
// ============ Align with top & bottom ============
var newTransform = transformLeft.value;
// RTL
if (props.rtl) {
if (tabOffset.right < transformLeft.value) {
newTransform = tabOffset.right;
} else if (tabOffset.right + tabOffset.width > transformLeft.value + wrapperWidth.value) {
newTransform = tabOffset.right + tabOffset.width - wrapperWidth.value;
}
}
// LTR
else if (tabOffset.left < -transformLeft.value) {
newTransform = -tabOffset.left;
} else if (tabOffset.left + tabOffset.width > -transformLeft.value + wrapperWidth.value) {
newTransform = -(tabOffset.left + tabOffset.width - wrapperWidth.value);
}
setTransformTop(0);
setTransformLeft(alignInRange(newTransform));
} else {
// ============ Align with left & right ============
var _newTransform = transformTop.value;
if (tabOffset.top < -transformTop.value) {
_newTransform = -tabOffset.top;
} else if (tabOffset.top + tabOffset.height > -transformTop.value + wrapperHeight.value) {
_newTransform = -(tabOffset.top + tabOffset.height - wrapperHeight.value);
}
setTransformLeft(0);
setTransformTop(alignInRange(_newTransform));
}
};
var visibleStart = (0, _vue.ref)(0);
var visibleEnd = (0, _vue.ref)(0);
(0, _vue.watchEffect)(function () {
var _ref3;
var unit;
var position;
var transformSize;
var basicSize;
var tabContentSize;
var addSize;
var tabOffsetsValue = tabOffsets.value;
if (['top', 'bottom'].includes(props.tabPosition)) {
unit = 'width';
basicSize = wrapperWidth.value;
tabContentSize = wrapperScrollWidth.value;
addSize = addWidth.value;
position = props.rtl ? 'right' : 'left';
transformSize = Math.abs(transformLeft.value);
} else {
unit = 'height';
basicSize = wrapperHeight.value;
tabContentSize = wrapperScrollWidth.value;
addSize = addHeight.value;
position = 'top';
transformSize = -transformTop.value;
}
var mergedBasicSize = basicSize;
if (tabContentSize + addSize > basicSize && tabContentSize < basicSize) {
mergedBasicSize = basicSize - addSize;
}
var tabsVal = tabs.value;
if (!tabsVal.length) {
var _ref2;
return _ref2 = [0, 0], visibleStart.value = _ref2[0], visibleEnd.value = _ref2[1], _ref2;
}
var len = tabsVal.length;
var endIndex = len;
for (var i = 0; i < len; i += 1) {
var offset = tabOffsetsValue.get(tabsVal[i].key) || DEFAULT_SIZE;
if (offset[position] + offset[unit] > transformSize + mergedBasicSize) {
endIndex = i - 1;
break;
}
}
var startIndex = 0;
for (var _i = len - 1; _i >= 0; _i -= 1) {
var _offset = tabOffsetsValue.get(tabsVal[_i].key) || DEFAULT_SIZE;
if (_offset[position] < transformSize) {
startIndex = _i + 1;
break;
}
}
return _ref3 = [startIndex, endIndex], visibleStart.value = _ref3[0], visibleEnd.value = _ref3[1], _ref3;
});
var onListHolderResize = function onListHolderResize() {
var _tabsWrapperRef$value, _tabsWrapperRef$value2, _innerAddButtonRef$va, _tabListRef$value, _tabListRef$value2;
// Update wrapper records
var offsetWidth = ((_tabsWrapperRef$value = tabsWrapperRef.value) === null || _tabsWrapperRef$value === void 0 ? void 0 : _tabsWrapperRef$value.offsetWidth) || 0;
var offsetHeight = ((_tabsWrapperRef$value2 = tabsWrapperRef.value) === null || _tabsWrapperRef$value2 === void 0 ? void 0 : _tabsWrapperRef$value2.offsetHeight) || 0;
var addDom = ((_innerAddButtonRef$va = innerAddButtonRef.value) === null || _innerAddButtonRef$va === void 0 ? void 0 : _innerAddButtonRef$va.$el) || {};
var newAddWidth = addDom.offsetWidth || 0;
var newAddHeight = addDom.offsetHeight || 0;
setWrapperWidth(offsetWidth);
setWrapperHeight(offsetHeight);
setAddWidth(newAddWidth);
setAddHeight(newAddHeight);
var newWrapperScrollWidth = (((_tabListRef$value = tabListRef.value) === null || _tabListRef$value === void 0 ? void 0 : _tabListRef$value.offsetWidth) || 0) - newAddWidth;
var newWrapperScrollHeight = (((_tabListRef$value2 = tabListRef.value) === null || _tabListRef$value2 === void 0 ? void 0 : _tabListRef$value2.offsetHeight) || 0) - newAddHeight;
setWrapperScrollWidth(newWrapperScrollWidth);
setWrapperScrollHeight(newWrapperScrollHeight);
// Update buttons records
setTabSizes(function () {
var newSizes = new Map();
tabs.value.forEach(function (_ref4) {
var key = _ref4.key;
var btnRef = btnRefs.value.get(key);
var btnNode = (btnRef === null || btnRef === void 0 ? void 0 : btnRef.$el) || btnRef;
if (btnNode) {
newSizes.set(key, {
width: btnNode.offsetWidth,
height: btnNode.offsetHeight,
left: btnNode.offsetLeft,
top: btnNode.offsetTop
});
}
});
return newSizes;
});
};
// ======================== Dropdown =======================
var hiddenTabs = (0, _vue.computed)(function () {
return [].concat((0, _toConsumableArray2.default)(tabs.value.slice(0, visibleStart.value)), (0, _toConsumableArray2.default)(tabs.value.slice(visibleEnd.value + 1)));
});
// =================== Link & Operations ===================
var _useState15 = (0, _useState17.default)(),
_useState16 = (0, _slicedToArray2.default)(_useState15, 2),
inkStyle = _useState16[0],
setInkStyle = _useState16[1];
var activeTabOffset = (0, _vue.computed)(function () {
return tabOffsets.value.get(props.activeKey);
});
// Delay set ink style to avoid remove tab blink
var inkBarRafRef = (0, _vue.ref)();
var cleanInkBarRaf = function cleanInkBarRaf() {
_raf.default.cancel(inkBarRafRef.value);
};
(0, _vue.watch)([activeTabOffset, tabPositionTopOrBottom, function () {
return props.rtl;
}], function () {
var newInkStyle = {};
if (activeTabOffset.value) {
if (tabPositionTopOrBottom.value) {
if (props.rtl) {
newInkStyle.right = (0, _util.toPx)(activeTabOffset.value.right);
} else {
newInkStyle.left = (0, _util.toPx)(activeTabOffset.value.left);
}
newInkStyle.width = (0, _util.toPx)(activeTabOffset.value.width);
} else {
newInkStyle.top = (0, _util.toPx)(activeTabOffset.value.top);
newInkStyle.height = (0, _util.toPx)(activeTabOffset.value.height);
}
}
cleanInkBarRaf();
inkBarRafRef.value = (0, _raf.default)(function () {
setInkStyle(newInkStyle);
});
});
(0, _vue.watch)([function () {
return props.activeKey;
}, activeTabOffset, tabOffsets, tabPositionTopOrBottom], function () {
scrollToTab();
}, {
flush: 'post'
});
(0, _vue.watch)([function () {
return props.rtl;
}, function () {
return props.tabBarGutter;
}, function () {
return props.activeKey;
}, function () {
return tabs.value;
}], function () {
onListHolderResize();
}, {
flush: 'post'
});
var ExtraContent = function ExtraContent(_ref5) {
var position = _ref5.position,
prefixCls = _ref5.prefixCls,
extra = _ref5.extra;
if (!extra) return null;
var content = extra === null || extra === void 0 ? void 0 : extra({
position: position
});
return content ? (0, _vue.createVNode)("div", {
"class": "".concat(prefixCls, "-extra-content")
}, [content]) : null;
};
(0, _vue.onBeforeUnmount)(function () {
clearTouchMoving();
cleanInkBarRaf();
});
return function () {
var _classNames;
var id = props.id,
animated = props.animated,
activeKey = props.activeKey,
rtl = props.rtl,
editable = props.editable,
locale = props.locale,
tabPosition = props.tabPosition,
tabBarGutter = props.tabBarGutter,
onTabClick = props.onTabClick;
var className = attrs.class,
style = attrs.style;
var pre = prefixCls.value;
// ========================= Render ========================
var hasDropdown = !!hiddenTabs.value.length;
var wrapPrefix = "".concat(pre, "-nav-wrap");
var pingLeft;
var pingRight;
var pingTop;
var pingBottom;
if (tabPositionTopOrBottom.value) {
if (rtl) {
pingRight = transformLeft.value > 0;
pingLeft = transformLeft.value + wrapperWidth.value < wrapperScrollWidth.value;
} else {
pingLeft = transformLeft.value < 0;
pingRight = -transformLeft.value + wrapperWidth.value < wrapperScrollWidth.value;
}
} else {
pingTop = transformTop.value < 0;
pingBottom = -transformTop.value + wrapperHeight.value < wrapperScrollHeight.value;
}
var tabNodeStyle = {};
if (tabPosition === 'top' || tabPosition === 'bottom') {
tabNodeStyle[rtl ? 'marginRight' : 'marginLeft'] = typeof tabBarGutter === 'number' ? "".concat(tabBarGutter, "px") : tabBarGutter;
} else {
tabNodeStyle.marginTop = typeof tabBarGutter === 'number' ? "".concat(tabBarGutter, "px") : tabBarGutter;
}
var tabNodes = tabs.value.map(function (tab, i) {
var key = tab.key;
return (0, _vue.createVNode)(_TabNode.default, {
"id": id,
"prefixCls": pre,
"key": key,
"tab": tab,
"style": i === 0 ? undefined : tabNodeStyle,
"closable": tab.closable,
"editable": editable,
"active": key === activeKey,
"removeAriaLabel": locale === null || locale === void 0 ? void 0 : locale.removeAriaLabel,
"ref": setRef(key),
"onClick": function onClick(e) {
onTabClick(key, e);
},
"onFocus": function onFocus() {
scrollToTab(key);
doLockAnimation();
if (!tabsWrapperRef.value) {
return;
}
// Focus element will make scrollLeft change which we should reset back
if (!rtl) {
tabsWrapperRef.value.scrollLeft = 0;
}
tabsWrapperRef.value.scrollTop = 0;
}
}, slots);
});
return (0, _vue.createVNode)("div", {
"role": "tablist",
"class": (0, _classNames3.default)("".concat(pre, "-nav"), className),
"style": style,
"onKeydown": function onKeydown() {
// No need animation when use keyboard
doLockAnimation();
}
}, [(0, _vue.createVNode)(ExtraContent, {
"position": "left",
"prefixCls": pre,
"extra": slots.leftExtra
}, null), (0, _vue.createVNode)(_vcResizeObserver.default, {
"onResize": onListHolderResize
}, {
default: function _default() {
return [(0, _vue.createVNode)("div", {
"class": (0, _classNames3.default)(wrapPrefix, (_classNames = {}, (0, _defineProperty2.default)(_classNames, "".concat(wrapPrefix, "-ping-left"), pingLeft), (0, _defineProperty2.default)(_classNames, "".concat(wrapPrefix, "-ping-right"), pingRight), (0, _defineProperty2.default)(_classNames, "".concat(wrapPrefix, "-ping-top"), pingTop), (0, _defineProperty2.default)(_classNames, "".concat(wrapPrefix, "-ping-bottom"), pingBottom), _classNames)),
"ref": tabsWrapperRef
}, [(0, _vue.createVNode)(_vcResizeObserver.default, {
"onResize": onListHolderResize
}, {
default: function _default() {
return [(0, _vue.createVNode)("div", {
"ref": tabListRef,
"class": "".concat(pre, "-nav-list"),
"style": {
transform: "translate(".concat(transformLeft.value, "px, ").concat(transformTop.value, "px)"),
transition: lockAnimation.value ? 'none' : undefined
}
}, [tabNodes, (0, _vue.createVNode)(_AddButton.default, {
"ref": innerAddButtonRef,
"prefixCls": pre,
"locale": locale,
"editable": editable,
"style": (0, _objectSpread2.default)((0, _objectSpread2.default)({}, tabNodes.length === 0 ? undefined : tabNodeStyle), {}, {
visibility: hasDropdown ? 'hidden' : null
})
}, null), (0, _vue.createVNode)("div", {
"class": (0, _classNames3.default)("".concat(pre, "-ink-bar"), (0, _defineProperty2.default)({}, "".concat(pre, "-ink-bar-animated"), animated.inkBar)),
"style": inkStyle.value
}, null)])];
}
})])];
}
}), (0, _vue.createVNode)(_OperationNode.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), {}, {
"removeAriaLabel": locale === null || locale === void 0 ? void 0 : locale.removeAriaLabel,
"ref": operationsRef,
"prefixCls": pre,
"tabs": hiddenTabs.value,
"class": !hasDropdown && operationsHiddenClassName.value
}), (0, _pick.default)(slots, ['moreIcon'])), (0, _vue.createVNode)(ExtraContent, {
"position": "right",
"prefixCls": pre,
"extra": slots.rightExtra
}, null), (0, _vue.createVNode)(ExtraContent, {
"position": "right",
"prefixCls": pre,
"extra": slots.tabBarExtraContent
}, null)]);
};
}
});
exports.default = _default2;
;