1 | import _extends from "@babel/runtime/helpers/esm/extends";
|
2 | import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
3 | import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
4 | import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
5 | import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
6 | import _typeof from "@babel/runtime/helpers/esm/typeof";
|
7 | import * as React from 'react';
|
8 | import { useState, useRef, useEffect } from 'react';
|
9 | import classNames from 'classnames';
|
10 | import raf from "rc-util/es/raf";
|
11 | import ResizeObserver from 'rc-resize-observer';
|
12 | import useRaf, { useRafState } from '../hooks/useRaf';
|
13 | import TabNode from './TabNode';
|
14 | import useOffsets from '../hooks/useOffsets';
|
15 | import useVisibleRange from '../hooks/useVisibleRange';
|
16 | import OperationNode from './OperationNode';
|
17 | import TabContext from '../TabContext';
|
18 | import useTouchMove from '../hooks/useTouchMove';
|
19 | import useRefs from '../hooks/useRefs';
|
20 | import AddButton from './AddButton';
|
21 | import useSyncState from '../hooks/useSyncState';
|
22 |
|
23 | var ExtraContent = function ExtraContent(_ref) {
|
24 | var position = _ref.position,
|
25 | prefixCls = _ref.prefixCls,
|
26 | extra = _ref.extra;
|
27 | if (!extra) return null;
|
28 | var content;
|
29 |
|
30 | var assertExtra = {};
|
31 |
|
32 | if (extra && _typeof(extra) === 'object' && ! React.isValidElement(extra)) {
|
33 | assertExtra = extra;
|
34 | } else {
|
35 | assertExtra.right = extra;
|
36 | }
|
37 |
|
38 | if (position === 'right') {
|
39 | content = assertExtra.right;
|
40 | }
|
41 |
|
42 | if (position === 'left') {
|
43 | content = assertExtra.left;
|
44 | }
|
45 |
|
46 | return content ? React.createElement("div", {
|
47 | className: "".concat(prefixCls, "-extra-content")
|
48 | }, content) : null;
|
49 | };
|
50 |
|
51 | function TabNavList(props, ref) {
|
52 | var _classNames;
|
53 |
|
54 | var _React$useContext = React.useContext(TabContext),
|
55 | prefixCls = _React$useContext.prefixCls,
|
56 | tabs = _React$useContext.tabs;
|
57 |
|
58 | var className = props.className,
|
59 | style = props.style,
|
60 | id = props.id,
|
61 | animated = props.animated,
|
62 | activeKey = props.activeKey,
|
63 | rtl = props.rtl,
|
64 | extra = props.extra,
|
65 | editable = props.editable,
|
66 | locale = props.locale,
|
67 | tabPosition = props.tabPosition,
|
68 | tabBarGutter = props.tabBarGutter,
|
69 | children = props.children,
|
70 | onTabClick = props.onTabClick,
|
71 | onTabScroll = props.onTabScroll;
|
72 | var tabsWrapperRef = useRef();
|
73 | var tabListRef = useRef();
|
74 | var operationsRef = useRef();
|
75 | var innerAddButtonRef = useRef();
|
76 |
|
77 | var _useRefs = useRefs(),
|
78 | _useRefs2 = _slicedToArray(_useRefs, 2),
|
79 | getBtnRef = _useRefs2[0],
|
80 | removeBtnRef = _useRefs2[1];
|
81 |
|
82 | var tabPositionTopOrBottom = tabPosition === 'top' || tabPosition === 'bottom';
|
83 |
|
84 | var _useSyncState = useSyncState(0, function (next, prev) {
|
85 | if (tabPositionTopOrBottom && onTabScroll) {
|
86 | onTabScroll({
|
87 | direction: next > prev ? 'left' : 'right'
|
88 | });
|
89 | }
|
90 | }),
|
91 | _useSyncState2 = _slicedToArray(_useSyncState, 2),
|
92 | transformLeft = _useSyncState2[0],
|
93 | setTransformLeft = _useSyncState2[1];
|
94 |
|
95 | var _useSyncState3 = useSyncState(0, function (next, prev) {
|
96 | if (!tabPositionTopOrBottom && onTabScroll) {
|
97 | onTabScroll({
|
98 | direction: next > prev ? 'top' : 'bottom'
|
99 | });
|
100 | }
|
101 | }),
|
102 | _useSyncState4 = _slicedToArray(_useSyncState3, 2),
|
103 | transformTop = _useSyncState4[0],
|
104 | setTransformTop = _useSyncState4[1];
|
105 |
|
106 | var _useState = useState(0),
|
107 | _useState2 = _slicedToArray(_useState, 2),
|
108 | wrapperScrollWidth = _useState2[0],
|
109 | setWrapperScrollWidth = _useState2[1];
|
110 |
|
111 | var _useState3 = useState(0),
|
112 | _useState4 = _slicedToArray(_useState3, 2),
|
113 | wrapperScrollHeight = _useState4[0],
|
114 | setWrapperScrollHeight = _useState4[1];
|
115 |
|
116 | var _useState5 = useState(0),
|
117 | _useState6 = _slicedToArray(_useState5, 2),
|
118 | wrapperContentWidth = _useState6[0],
|
119 | setWrapperContentWidth = _useState6[1];
|
120 |
|
121 | var _useState7 = useState(0),
|
122 | _useState8 = _slicedToArray(_useState7, 2),
|
123 | wrapperContentHeight = _useState8[0],
|
124 | setWrapperContentHeight = _useState8[1];
|
125 |
|
126 | var _useState9 = useState(null),
|
127 | _useState10 = _slicedToArray(_useState9, 2),
|
128 | wrapperWidth = _useState10[0],
|
129 | setWrapperWidth = _useState10[1];
|
130 |
|
131 | var _useState11 = useState(null),
|
132 | _useState12 = _slicedToArray(_useState11, 2),
|
133 | wrapperHeight = _useState12[0],
|
134 | setWrapperHeight = _useState12[1];
|
135 |
|
136 | var _useState13 = useState(0),
|
137 | _useState14 = _slicedToArray(_useState13, 2),
|
138 | addWidth = _useState14[0],
|
139 | setAddWidth = _useState14[1];
|
140 |
|
141 | var _useState15 = useState(0),
|
142 | _useState16 = _slicedToArray(_useState15, 2),
|
143 | addHeight = _useState16[0],
|
144 | setAddHeight = _useState16[1];
|
145 |
|
146 | var _useRafState = useRafState(new Map()),
|
147 | _useRafState2 = _slicedToArray(_useRafState, 2),
|
148 | tabSizes = _useRafState2[0],
|
149 | setTabSizes = _useRafState2[1];
|
150 |
|
151 | var tabOffsets = useOffsets(tabs, tabSizes, wrapperScrollWidth);
|
152 |
|
153 | var operationsHiddenClassName = "".concat(prefixCls, "-nav-operations-hidden");
|
154 | var transformMin = 0;
|
155 | var transformMax = 0;
|
156 |
|
157 | if (!tabPositionTopOrBottom) {
|
158 | transformMin = Math.min(0, wrapperHeight - wrapperScrollHeight);
|
159 | transformMax = 0;
|
160 | } else if (rtl) {
|
161 | transformMin = 0;
|
162 | transformMax = Math.max(0, wrapperScrollWidth - wrapperWidth);
|
163 | } else {
|
164 | transformMin = Math.min(0, wrapperWidth - wrapperScrollWidth);
|
165 | transformMax = 0;
|
166 | }
|
167 |
|
168 | function alignInRange(value) {
|
169 | if (value < transformMin) {
|
170 | return transformMin;
|
171 | }
|
172 |
|
173 | if (value > transformMax) {
|
174 | return transformMax;
|
175 | }
|
176 |
|
177 | return value;
|
178 | }
|
179 |
|
180 |
|
181 | var touchMovingRef = useRef();
|
182 |
|
183 | var _useState17 = useState(),
|
184 | _useState18 = _slicedToArray(_useState17, 2),
|
185 | lockAnimation = _useState18[0],
|
186 | setLockAnimation = _useState18[1];
|
187 |
|
188 | function doLockAnimation() {
|
189 | setLockAnimation(Date.now());
|
190 | }
|
191 |
|
192 | function clearTouchMoving() {
|
193 | window.clearTimeout(touchMovingRef.current);
|
194 | }
|
195 |
|
196 | useTouchMove(tabsWrapperRef, function (offsetX, offsetY) {
|
197 | function doMove(setState, offset) {
|
198 | setState(function (value) {
|
199 | var newValue = alignInRange(value + offset);
|
200 | return newValue;
|
201 | });
|
202 | }
|
203 |
|
204 | if (tabPositionTopOrBottom) {
|
205 |
|
206 | if (wrapperWidth >= wrapperScrollWidth) {
|
207 | return false;
|
208 | }
|
209 |
|
210 | doMove(setTransformLeft, offsetX);
|
211 | } else {
|
212 | if (wrapperHeight >= wrapperScrollHeight) {
|
213 | return false;
|
214 | }
|
215 |
|
216 | doMove(setTransformTop, offsetY);
|
217 | }
|
218 |
|
219 | clearTouchMoving();
|
220 | doLockAnimation();
|
221 | return true;
|
222 | });
|
223 | useEffect(function () {
|
224 | clearTouchMoving();
|
225 |
|
226 | if (lockAnimation) {
|
227 | touchMovingRef.current = window.setTimeout(function () {
|
228 | setLockAnimation(0);
|
229 | }, 100);
|
230 | }
|
231 |
|
232 | return clearTouchMoving;
|
233 | }, [lockAnimation]);
|
234 |
|
235 | function scrollToTab() {
|
236 | var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : activeKey;
|
237 | var tabOffset = tabOffsets.get(key) || {
|
238 | width: 0,
|
239 | height: 0,
|
240 | left: 0,
|
241 | right: 0,
|
242 | top: 0
|
243 | };
|
244 |
|
245 | if (tabPositionTopOrBottom) {
|
246 |
|
247 | var newTransform = transformLeft;
|
248 |
|
249 | if (rtl) {
|
250 | if (tabOffset.right < transformLeft) {
|
251 | newTransform = tabOffset.right;
|
252 | } else if (tabOffset.right + tabOffset.width > transformLeft + wrapperWidth) {
|
253 | newTransform = tabOffset.right + tabOffset.width - wrapperWidth;
|
254 | }
|
255 | }
|
256 | else if (tabOffset.left < -transformLeft) {
|
257 | newTransform = -tabOffset.left;
|
258 | } else if (tabOffset.left + tabOffset.width > -transformLeft + wrapperWidth) {
|
259 | newTransform = -(tabOffset.left + tabOffset.width - wrapperWidth);
|
260 | }
|
261 |
|
262 | setTransformTop(0);
|
263 | setTransformLeft(alignInRange(newTransform));
|
264 | } else {
|
265 |
|
266 | var _newTransform = transformTop;
|
267 |
|
268 | if (tabOffset.top < -transformTop) {
|
269 | _newTransform = -tabOffset.top;
|
270 | } else if (tabOffset.top + tabOffset.height > -transformTop + wrapperHeight) {
|
271 | _newTransform = -(tabOffset.top + tabOffset.height - wrapperHeight);
|
272 | }
|
273 |
|
274 | setTransformLeft(0);
|
275 | setTransformTop(alignInRange(_newTransform));
|
276 | }
|
277 | }
|
278 |
|
279 |
|
280 |
|
281 | var _useVisibleRange = useVisibleRange(tabOffsets, {
|
282 | width: wrapperWidth,
|
283 | height: wrapperHeight,
|
284 | left: transformLeft,
|
285 | top: transformTop
|
286 | }, {
|
287 | width: wrapperContentWidth,
|
288 | height: wrapperContentHeight
|
289 | }, {
|
290 | width: addWidth,
|
291 | height: addHeight
|
292 | }, _objectSpread(_objectSpread({}, props), {}, {
|
293 | tabs: tabs
|
294 | })),
|
295 | _useVisibleRange2 = _slicedToArray(_useVisibleRange, 2),
|
296 | visibleStart = _useVisibleRange2[0],
|
297 | visibleEnd = _useVisibleRange2[1];
|
298 |
|
299 | var tabNodeStyle = {};
|
300 |
|
301 | if (tabPosition === 'top' || tabPosition === 'bottom') {
|
302 | tabNodeStyle[rtl ? 'marginRight' : 'marginLeft'] = tabBarGutter;
|
303 | } else {
|
304 | tabNodeStyle.marginTop = tabBarGutter;
|
305 | }
|
306 |
|
307 | var tabNodes = tabs.map(function (tab, i) {
|
308 | var key = tab.key;
|
309 | return React.createElement(TabNode, {
|
310 | id: id,
|
311 | prefixCls: prefixCls,
|
312 | key: key,
|
313 | tab: tab
|
314 |
|
315 | ,
|
316 | style: i === 0 ? undefined : tabNodeStyle,
|
317 | closable: tab.closable,
|
318 | editable: editable,
|
319 | active: key === activeKey,
|
320 | renderWrapper: children,
|
321 | removeAriaLabel: locale === null || locale === void 0 ? void 0 : locale.removeAriaLabel,
|
322 | ref: getBtnRef(key),
|
323 | onClick: function onClick(e) {
|
324 | onTabClick(key, e);
|
325 | },
|
326 | onRemove: function onRemove() {
|
327 | removeBtnRef(key);
|
328 | },
|
329 | onFocus: function onFocus() {
|
330 | scrollToTab(key);
|
331 | doLockAnimation();
|
332 |
|
333 | if (!tabsWrapperRef.current) {
|
334 | return;
|
335 | }
|
336 |
|
337 |
|
338 | if (!rtl) {
|
339 | tabsWrapperRef.current.scrollLeft = 0;
|
340 | }
|
341 |
|
342 | tabsWrapperRef.current.scrollTop = 0;
|
343 | }
|
344 | });
|
345 | });
|
346 | var onListHolderResize = useRaf(function () {
|
347 | var _tabsWrapperRef$curre, _tabsWrapperRef$curre2, _innerAddButtonRef$cu, _innerAddButtonRef$cu2, _operationsRef$curren, _operationsRef$curren2, _tabListRef$current, _tabListRef$current2, _operationsRef$curren3;
|
348 |
|
349 |
|
350 | var offsetWidth = ((_tabsWrapperRef$curre = tabsWrapperRef.current) === null || _tabsWrapperRef$curre === void 0 ? void 0 : _tabsWrapperRef$curre.offsetWidth) || 0;
|
351 | var offsetHeight = ((_tabsWrapperRef$curre2 = tabsWrapperRef.current) === null || _tabsWrapperRef$curre2 === void 0 ? void 0 : _tabsWrapperRef$curre2.offsetHeight) || 0;
|
352 | var newAddWidth = ((_innerAddButtonRef$cu = innerAddButtonRef.current) === null || _innerAddButtonRef$cu === void 0 ? void 0 : _innerAddButtonRef$cu.offsetWidth) || 0;
|
353 | var newAddHeight = ((_innerAddButtonRef$cu2 = innerAddButtonRef.current) === null || _innerAddButtonRef$cu2 === void 0 ? void 0 : _innerAddButtonRef$cu2.offsetHeight) || 0;
|
354 | var newOperationWidth = ((_operationsRef$curren = operationsRef.current) === null || _operationsRef$curren === void 0 ? void 0 : _operationsRef$curren.offsetWidth) || 0;
|
355 | var newOperationHeight = ((_operationsRef$curren2 = operationsRef.current) === null || _operationsRef$curren2 === void 0 ? void 0 : _operationsRef$curren2.offsetHeight) || 0;
|
356 | setWrapperWidth(offsetWidth);
|
357 | setWrapperHeight(offsetHeight);
|
358 | setAddWidth(newAddWidth);
|
359 | setAddHeight(newAddHeight);
|
360 | var newWrapperScrollWidth = (((_tabListRef$current = tabListRef.current) === null || _tabListRef$current === void 0 ? void 0 : _tabListRef$current.offsetWidth) || 0) - newAddWidth;
|
361 | var newWrapperScrollHeight = (((_tabListRef$current2 = tabListRef.current) === null || _tabListRef$current2 === void 0 ? void 0 : _tabListRef$current2.offsetHeight) || 0) - newAddHeight;
|
362 | setWrapperScrollWidth(newWrapperScrollWidth);
|
363 | setWrapperScrollHeight(newWrapperScrollHeight);
|
364 | var isOperationHidden = (_operationsRef$curren3 = operationsRef.current) === null || _operationsRef$curren3 === void 0 ? void 0 : _operationsRef$curren3.className.includes(operationsHiddenClassName);
|
365 | setWrapperContentWidth(newWrapperScrollWidth - (isOperationHidden ? 0 : newOperationWidth));
|
366 | setWrapperContentHeight(newWrapperScrollHeight - (isOperationHidden ? 0 : newOperationHeight));
|
367 |
|
368 | setTabSizes(function () {
|
369 | var newSizes = new Map();
|
370 | tabs.forEach(function (_ref2) {
|
371 | var key = _ref2.key;
|
372 | var btnNode = getBtnRef(key).current;
|
373 |
|
374 | if (btnNode) {
|
375 | newSizes.set(key, {
|
376 | width: btnNode.offsetWidth,
|
377 | height: btnNode.offsetHeight,
|
378 | left: btnNode.offsetLeft,
|
379 | top: btnNode.offsetTop
|
380 | });
|
381 | }
|
382 | });
|
383 | return newSizes;
|
384 | });
|
385 | });
|
386 |
|
387 | var startHiddenTabs = tabs.slice(0, visibleStart);
|
388 | var endHiddenTabs = tabs.slice(visibleEnd + 1);
|
389 | var hiddenTabs = [].concat(_toConsumableArray(startHiddenTabs), _toConsumableArray(endHiddenTabs));
|
390 |
|
391 | var _useState19 = useState(),
|
392 | _useState20 = _slicedToArray(_useState19, 2),
|
393 | inkStyle = _useState20[0],
|
394 | setInkStyle = _useState20[1];
|
395 |
|
396 | var activeTabOffset = tabOffsets.get(activeKey);
|
397 |
|
398 | var inkBarRafRef = useRef();
|
399 |
|
400 | function cleanInkBarRaf() {
|
401 | raf.cancel(inkBarRafRef.current);
|
402 | }
|
403 |
|
404 | useEffect(function () {
|
405 | var newInkStyle = {};
|
406 |
|
407 | if (activeTabOffset) {
|
408 | if (tabPositionTopOrBottom) {
|
409 | if (rtl) {
|
410 | newInkStyle.right = activeTabOffset.right;
|
411 | } else {
|
412 | newInkStyle.left = activeTabOffset.left;
|
413 | }
|
414 |
|
415 | newInkStyle.width = activeTabOffset.width;
|
416 | } else {
|
417 | newInkStyle.top = activeTabOffset.top;
|
418 | newInkStyle.height = activeTabOffset.height;
|
419 | }
|
420 | }
|
421 |
|
422 | cleanInkBarRaf();
|
423 | inkBarRafRef.current = raf(function () {
|
424 | setInkStyle(newInkStyle);
|
425 | });
|
426 | return cleanInkBarRaf;
|
427 | }, [activeTabOffset, tabPositionTopOrBottom, rtl]);
|
428 |
|
429 | useEffect(function () {
|
430 | scrollToTab();
|
431 | }, [activeKey, activeTabOffset, tabOffsets, tabPositionTopOrBottom]);
|
432 |
|
433 | useEffect(function () {
|
434 | onListHolderResize();
|
435 | }, [rtl, tabBarGutter, activeKey, tabs.map(function (tab) {
|
436 | return tab.key;
|
437 | }).join('_')]);
|
438 |
|
439 | var hasDropdown = !!hiddenTabs.length;
|
440 | var wrapPrefix = "".concat(prefixCls, "-nav-wrap");
|
441 | var pingLeft;
|
442 | var pingRight;
|
443 | var pingTop;
|
444 | var pingBottom;
|
445 |
|
446 | if (tabPositionTopOrBottom) {
|
447 | if (rtl) {
|
448 | pingRight = transformLeft > 0;
|
449 | pingLeft = transformLeft + wrapperWidth < wrapperScrollWidth;
|
450 | } else {
|
451 | pingLeft = transformLeft < 0;
|
452 | pingRight = -transformLeft + wrapperWidth < wrapperScrollWidth;
|
453 | }
|
454 | } else {
|
455 | pingTop = transformTop < 0;
|
456 | pingBottom = -transformTop + wrapperHeight < wrapperScrollHeight;
|
457 | }
|
458 |
|
459 | return React.createElement("div", {
|
460 | ref: ref,
|
461 | role: "tablist",
|
462 | className: classNames("".concat(prefixCls, "-nav"), className),
|
463 | style: style,
|
464 | onKeyDown: function onKeyDown() {
|
465 |
|
466 | doLockAnimation();
|
467 | }
|
468 | }, React.createElement(ExtraContent, {
|
469 | position: "left",
|
470 | extra: extra,
|
471 | prefixCls: prefixCls
|
472 | }), React.createElement(ResizeObserver, {
|
473 | onResize: onListHolderResize
|
474 | }, React.createElement("div", {
|
475 | className: classNames(wrapPrefix, (_classNames = {}, _defineProperty(_classNames, "".concat(wrapPrefix, "-ping-left"), pingLeft), _defineProperty(_classNames, "".concat(wrapPrefix, "-ping-right"), pingRight), _defineProperty(_classNames, "".concat(wrapPrefix, "-ping-top"), pingTop), _defineProperty(_classNames, "".concat(wrapPrefix, "-ping-bottom"), pingBottom), _classNames)),
|
476 | ref: tabsWrapperRef
|
477 | }, React.createElement(ResizeObserver, {
|
478 | onResize: onListHolderResize
|
479 | }, React.createElement("div", {
|
480 | ref: tabListRef,
|
481 | className: "".concat(prefixCls, "-nav-list"),
|
482 | style: {
|
483 | transform: "translate(".concat(transformLeft, "px, ").concat(transformTop, "px)"),
|
484 | transition: lockAnimation ? 'none' : undefined
|
485 | }
|
486 | }, tabNodes, React.createElement(AddButton, {
|
487 | ref: innerAddButtonRef,
|
488 | prefixCls: prefixCls,
|
489 | locale: locale,
|
490 | editable: editable,
|
491 | style: _objectSpread(_objectSpread({}, tabNodes.length === 0 ? undefined : tabNodeStyle), {}, {
|
492 | visibility: hasDropdown ? 'hidden' : null
|
493 | })
|
494 | }), React.createElement("div", {
|
495 | className: classNames("".concat(prefixCls, "-ink-bar"), _defineProperty({}, "".concat(prefixCls, "-ink-bar-animated"), animated.inkBar)),
|
496 | style: inkStyle
|
497 | }))))), React.createElement(OperationNode, _extends({}, props, {
|
498 | ref: operationsRef,
|
499 | prefixCls: prefixCls,
|
500 | tabs: hiddenTabs,
|
501 | className: !hasDropdown && operationsHiddenClassName
|
502 | })), React.createElement(ExtraContent, {
|
503 | position: "right",
|
504 | extra: extra,
|
505 | prefixCls: prefixCls
|
506 | }));
|
507 |
|
508 | }
|
509 |
|
510 | export default React.forwardRef(TabNavList); |
\ | No newline at end of file |