This commit is contained in:
2026-05-25 17:08:18 +08:00
parent df501f6151
commit f1259b71b5
9178 changed files with 1626125 additions and 0 deletions
@@ -0,0 +1,3 @@
import type { TabsProps } from '..';
import type { AnimatedConfig } from '../interface';
export default function useAnimateConfig(animated?: TabsProps['animated']): AnimatedConfig;
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useAnimateConfig;
var _warning = _interopRequireDefault(require("@rc-component/util/lib/warning"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function useAnimateConfig(animated = {
inkBar: true,
tabPane: false
}) {
let mergedAnimated;
if (animated === false) {
mergedAnimated = {
inkBar: false,
tabPane: false
};
} else if (animated === true) {
mergedAnimated = {
inkBar: true,
tabPane: false
};
} else {
mergedAnimated = {
inkBar: true,
...(typeof animated === 'object' ? animated : {})
};
}
// Enable tabPane animation if provide motion
if (mergedAnimated.tabPaneMotion && mergedAnimated.tabPane === undefined) {
mergedAnimated.tabPane = true;
}
if (!mergedAnimated.tabPaneMotion && mergedAnimated.tabPane) {
if (process.env.NODE_ENV !== 'production') {
(0, _warning.default)(false, '`animated.tabPane` is true but `animated.tabPaneMotion` is not provided. Motion will not work.');
}
mergedAnimated.tabPane = false;
}
return mergedAnimated;
}
@@ -0,0 +1,16 @@
import React from 'react';
import type { TabOffset } from '../interface';
export type GetIndicatorSize = number | ((origin: number) => number);
interface UseIndicatorOptions {
activeTabOffset: TabOffset;
horizontal: boolean;
rtl: boolean;
indicator?: {
size?: GetIndicatorSize;
align?: 'start' | 'center' | 'end';
};
}
declare const useIndicator: (options: UseIndicatorOptions) => {
style: React.CSSProperties;
};
export default useIndicator;
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _raf = _interopRequireDefault(require("@rc-component/util/lib/raf"));
var _react = _interopRequireWildcard(require("react"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (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; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const useIndicator = options => {
const {
activeTabOffset,
horizontal,
rtl,
indicator = {}
} = options;
const {
size,
align = 'center'
} = indicator;
const [inkStyle, setInkStyle] = (0, _react.useState)();
const inkBarRafRef = (0, _react.useRef)();
const getLength = _react.default.useCallback(origin => {
if (typeof size === 'function') {
return size(origin);
}
if (typeof size === 'number') {
return size;
}
return origin;
}, [size]);
// Delay set ink style to avoid remove tab blink
function cleanInkBarRaf() {
_raf.default.cancel(inkBarRafRef.current);
}
(0, _react.useEffect)(() => {
const newInkStyle = {};
if (activeTabOffset) {
if (horizontal) {
newInkStyle.width = getLength(activeTabOffset.width);
const key = rtl ? 'right' : 'left';
if (align === 'start') {
newInkStyle[key] = activeTabOffset[key];
}
if (align === 'center') {
newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width / 2;
newInkStyle.transform = rtl ? 'translateX(50%)' : 'translateX(-50%)';
}
if (align === 'end') {
newInkStyle[key] = activeTabOffset[key] + activeTabOffset.width;
newInkStyle.transform = 'translateX(-100%)';
}
} else {
newInkStyle.height = getLength(activeTabOffset.height);
if (align === 'start') {
newInkStyle.top = activeTabOffset.top;
}
if (align === 'center') {
newInkStyle.top = activeTabOffset.top + activeTabOffset.height / 2;
newInkStyle.transform = 'translateY(-50%)';
}
if (align === 'end') {
newInkStyle.top = activeTabOffset.top + activeTabOffset.height;
newInkStyle.transform = 'translateY(-100%)';
}
}
}
cleanInkBarRaf();
inkBarRafRef.current = (0, _raf.default)(() => {
// Avoid jitter caused by tiny numerical differences
// fix https://github.com/ant-design/ant-design/issues/53378
const isEqual = inkStyle && newInkStyle && Object.keys(newInkStyle).every(key => {
const newValue = newInkStyle[key];
const oldValue = inkStyle[key];
return typeof newValue === 'number' && typeof oldValue === 'number' ? Math.round(newValue) === Math.round(oldValue) : newValue === oldValue;
});
if (!isEqual) {
setInkStyle(newInkStyle);
}
});
return cleanInkBarRaf;
}, [JSON.stringify(activeTabOffset), horizontal, rtl, align, getLength]);
return {
style: inkStyle
};
};
var _default = exports.default = useIndicator;
@@ -0,0 +1,2 @@
import type { Tab, TabOffsetMap, TabSizeMap } from '../interface';
export default function useOffsets(tabs: Tab[], tabSizes: TabSizeMap, holderScrollWidth: number): TabOffsetMap;
@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useOffsets;
var _react = require("react");
const DEFAULT_SIZE = {
width: 0,
height: 0,
left: 0,
top: 0
};
function useOffsets(tabs, tabSizes, holderScrollWidth) {
return (0, _react.useMemo)(() => {
const map = new Map();
const lastOffset = tabSizes.get(tabs[0]?.key) || DEFAULT_SIZE;
const rightOffset = lastOffset.left + lastOffset.width;
for (let i = 0; i < tabs.length; i += 1) {
const {
key
} = tabs[i];
let data = tabSizes.get(key);
// Reuse last one when not exist yet
if (!data) {
data = tabSizes.get(tabs[i - 1]?.key) || DEFAULT_SIZE;
}
const entity = map.get(key) || {
...data
};
// Right
entity.right = rightOffset - entity.left - entity.width;
// Update entity
map.set(key, entity);
}
return map;
}, [tabs.map(tab => tab.key).join('_'), tabSizes, holderScrollWidth]);
}
@@ -0,0 +1,3 @@
type Updater<T> = (prev: T) => T;
export default function useSyncState<T>(defaultState: T, onChange: (newValue: T, prevValue: T) => void): [T, (updater: T | Updater<T>) => void];
export {};
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useSyncState;
var React = _interopRequireWildcard(require("react"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (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; }
function useSyncState(defaultState, onChange) {
const stateRef = React.useRef(defaultState);
const [, forceUpdate] = React.useState({});
function setState(updater) {
const newValue = typeof updater === 'function' ? updater(stateRef.current) : updater;
if (newValue !== stateRef.current) {
onChange(newValue, stateRef.current);
}
stateRef.current = newValue;
forceUpdate({});
}
return [stateRef.current, setState];
}
@@ -0,0 +1,2 @@
import * as React from 'react';
export default function useTouchMove(ref: React.RefObject<HTMLDivElement>, onOffset: (offsetX: number, offsetY: number) => boolean): void;
@@ -0,0 +1,154 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useTouchMove;
var _react = _interopRequireWildcard(require("react"));
var React = _react;
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (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; }
const MIN_SWIPE_DISTANCE = 0.1;
const STOP_SWIPE_DISTANCE = 0.01;
const REFRESH_INTERVAL = 20;
const SPEED_OFF_MULTIPLE = 0.995 ** REFRESH_INTERVAL;
// ================================= Hook =================================
function useTouchMove(ref, onOffset) {
const [touchPosition, setTouchPosition] = (0, _react.useState)();
const [lastTimestamp, setLastTimestamp] = (0, _react.useState)(0);
const [lastTimeDiff, setLastTimeDiff] = (0, _react.useState)(0);
const [lastOffset, setLastOffset] = (0, _react.useState)();
const motionRef = (0, _react.useRef)();
// ========================= Events =========================
// >>> Touch events
function onTouchStart(e) {
const {
screenX,
screenY
} = e.touches[0];
setTouchPosition({
x: screenX,
y: screenY
});
window.clearInterval(motionRef.current);
}
function onTouchMove(e) {
if (!touchPosition) return;
// e.preventDefault();
const {
screenX,
screenY
} = e.touches[0];
setTouchPosition({
x: screenX,
y: screenY
});
const offsetX = screenX - touchPosition.x;
const offsetY = screenY - touchPosition.y;
onOffset(offsetX, offsetY);
const now = Date.now();
setLastTimestamp(now);
setLastTimeDiff(now - lastTimestamp);
setLastOffset({
x: offsetX,
y: offsetY
});
}
function onTouchEnd() {
if (!touchPosition) return;
setTouchPosition(null);
setLastOffset(null);
// Swipe if needed
if (lastOffset) {
const distanceX = lastOffset.x / lastTimeDiff;
const distanceY = lastOffset.y / lastTimeDiff;
const absX = Math.abs(distanceX);
const absY = Math.abs(distanceY);
// Skip swipe if low distance
if (Math.max(absX, absY) < MIN_SWIPE_DISTANCE) return;
let currentX = distanceX;
let currentY = distanceY;
motionRef.current = window.setInterval(() => {
if (Math.abs(currentX) < STOP_SWIPE_DISTANCE && Math.abs(currentY) < STOP_SWIPE_DISTANCE) {
window.clearInterval(motionRef.current);
return;
}
currentX *= SPEED_OFF_MULTIPLE;
currentY *= SPEED_OFF_MULTIPLE;
onOffset(currentX * REFRESH_INTERVAL, currentY * REFRESH_INTERVAL);
}, REFRESH_INTERVAL);
}
}
// >>> Wheel event
const lastWheelDirectionRef = (0, _react.useRef)();
function onWheel(e) {
const {
deltaX,
deltaY
} = e;
// Convert both to x & y since wheel only happened on PC
let mixed = 0;
const absX = Math.abs(deltaX);
const absY = Math.abs(deltaY);
if (absX === absY) {
mixed = lastWheelDirectionRef.current === 'x' ? deltaX : deltaY;
} else if (absX > absY) {
mixed = deltaX;
lastWheelDirectionRef.current = 'x';
} else {
mixed = deltaY;
lastWheelDirectionRef.current = 'y';
}
if (onOffset(-mixed, -mixed)) {
e.preventDefault();
}
}
// ========================= Effect =========================
const touchEventsRef = (0, _react.useRef)(null);
touchEventsRef.current = {
onTouchStart,
onTouchMove,
onTouchEnd,
onWheel
};
React.useEffect(() => {
function onProxyTouchStart(e) {
touchEventsRef.current.onTouchStart(e);
}
function onProxyTouchMove(e) {
touchEventsRef.current.onTouchMove(e);
}
function onProxyTouchEnd(e) {
touchEventsRef.current.onTouchEnd(e);
}
function onProxyWheel(e) {
touchEventsRef.current.onWheel(e);
}
document.addEventListener('touchmove', onProxyTouchMove, {
passive: false
});
document.addEventListener('touchend', onProxyTouchEnd, {
passive: true
});
// No need to clean up since element removed
ref.current.addEventListener('touchstart', onProxyTouchStart, {
passive: true
});
ref.current.addEventListener('wheel', onProxyWheel, {
passive: false
});
return () => {
document.removeEventListener('touchmove', onProxyTouchMove);
document.removeEventListener('touchend', onProxyTouchEnd);
};
}, []);
}
@@ -0,0 +1,8 @@
/**
* Help to merge callback with `useLayoutEffect`.
* One time will only trigger once.
*/
export default function useUpdate(callback: VoidFunction): () => void;
type Callback<T> = (ori: T) => T;
export declare function useUpdateState<T>(defaultState: T | (() => T)): [T, (updater: Callback<T>) => void];
export {};
+52
View File
@@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useUpdate;
exports.useUpdateState = useUpdateState;
var _useLayoutEffect = require("@rc-component/util/lib/hooks/useLayoutEffect");
var _react = require("react");
/**
* Help to merge callback with `useLayoutEffect`.
* One time will only trigger once.
*/
function useUpdate(callback) {
const [count, setCount] = (0, _react.useState)(0);
const effectRef = (0, _react.useRef)(0);
const callbackRef = (0, _react.useRef)();
callbackRef.current = callback;
// Trigger on `useLayoutEffect`
(0, _useLayoutEffect.useLayoutUpdateEffect)(() => {
callbackRef.current?.();
}, [count]);
// Trigger to update count
return () => {
if (effectRef.current !== count) {
return;
}
effectRef.current += 1;
setCount(effectRef.current);
};
}
function useUpdateState(defaultState) {
const batchRef = (0, _react.useRef)([]);
const [, forceUpdate] = (0, _react.useState)({});
const state = (0, _react.useRef)(typeof defaultState === 'function' ? defaultState() : defaultState);
const flushUpdate = useUpdate(() => {
let current = state.current;
batchRef.current.forEach(callback => {
current = callback(current);
});
batchRef.current = [];
state.current = current;
forceUpdate({});
});
function updater(callback) {
batchRef.current.push(callback);
flushUpdate();
}
return [state.current, updater];
}
@@ -0,0 +1,6 @@
import type { Tab, TabOffsetMap } from '../interface';
import type { TabNavListProps } from '../TabNavList';
export type ContainerSizeInfo = [width: number, height: number, left: number, top: number];
export default function useVisibleRange(tabOffsets: TabOffsetMap, visibleTabContentValue: number, transform: number, tabContentSizeValue: number, addNodeSizeValue: number, operationNodeSizeValue: number, { tabs, tabPosition, rtl }: {
tabs: Tab[];
} & TabNavListProps): [visibleStart: number, visibleEnd: number];
@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useVisibleRange;
var _react = require("react");
const DEFAULT_SIZE = {
width: 0,
height: 0,
left: 0,
top: 0,
right: 0
};
function useVisibleRange(tabOffsets, visibleTabContentValue, transform, tabContentSizeValue, addNodeSizeValue, operationNodeSizeValue, {
tabs,
tabPosition,
rtl
}) {
let charUnit;
let position;
let transformSize;
if (['top', 'bottom'].includes(tabPosition)) {
charUnit = 'width';
position = rtl ? 'right' : 'left';
transformSize = Math.abs(transform);
} else {
charUnit = 'height';
position = 'top';
transformSize = -transform;
}
return (0, _react.useMemo)(() => {
if (!tabs.length) {
return [0, 0];
}
const len = tabs.length;
let endIndex = len;
for (let i = 0; i < len; i += 1) {
const offset = tabOffsets.get(tabs[i].key) || DEFAULT_SIZE;
if (Math.floor(offset[position] + offset[charUnit]) > Math.floor(transformSize + visibleTabContentValue)) {
endIndex = i - 1;
break;
}
}
let startIndex = 0;
for (let i = len - 1; i >= 0; i -= 1) {
const offset = tabOffsets.get(tabs[i].key) || DEFAULT_SIZE;
if (offset[position] < transformSize) {
startIndex = i + 1;
break;
}
}
return startIndex > endIndex ? [0, -1] : [startIndex, endIndex];
}, [tabOffsets, visibleTabContentValue, tabContentSizeValue, addNodeSizeValue, operationNodeSizeValue, transformSize, tabPosition, tabs.map(tab => tab.key).join('_'), rtl]);
}