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
+8
View File
@@ -0,0 +1,8 @@
/// <reference types="react" />
import type { Tab } from './interface';
export interface TabContextProps {
tabs: Tab[];
prefixCls: string;
}
declare const _default: import("react").Context<TabContextProps>;
export default _default;
+8
View File
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = require("react");
var _default = exports.default = /*#__PURE__*/(0, _react.createContext)(null);
@@ -0,0 +1,10 @@
import * as React from 'react';
import type { EditableConfig, TabsLocale } from '../interface';
export interface AddButtonProps {
prefixCls: string;
editable?: EditableConfig;
locale?: TabsLocale;
style?: React.CSSProperties;
}
declare const AddButton: React.ForwardRefExoticComponent<AddButtonProps & React.RefAttributes<HTMLButtonElement>>;
export default AddButton;
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
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; }
const AddButton = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
editable,
locale,
style
} = props;
if (!editable || editable.showAdd === false) {
return null;
}
return /*#__PURE__*/React.createElement("button", {
ref: ref,
type: "button",
className: `${prefixCls}-nav-add`,
style: style,
"aria-label": locale?.addAriaLabel || 'Add tab',
onClick: event => {
editable.onEdit('add', {
event
});
}
}, editable.addIcon || '+');
});
var _default = exports.default = AddButton;
@@ -0,0 +1,9 @@
import * as React from 'react';
import type { TabBarExtraContent, TabBarExtraPosition } from '../interface';
interface ExtraContentProps {
position: TabBarExtraPosition;
prefixCls: string;
extra?: TabBarExtraContent;
}
declare const ExtraContent: React.ForwardRefExoticComponent<ExtraContentProps & React.RefAttributes<HTMLDivElement>>;
export default ExtraContent;
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
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; }
const ExtraContent = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
position,
prefixCls,
extra
} = props;
if (!extra) {
return null;
}
let content;
// Parse extra
let assertExtra = {};
if (typeof extra === 'object' && ! /*#__PURE__*/React.isValidElement(extra)) {
assertExtra = extra;
} else {
assertExtra.right = extra;
}
if (position === 'right') {
content = assertExtra.right;
}
if (position === 'left') {
content = assertExtra.left;
}
return content ? /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-extra-content`,
ref: ref
}, content) : null;
});
if (process.env.NODE_ENV !== 'production') {
ExtraContent.displayName = 'ExtraContent';
}
var _default = exports.default = ExtraContent;
@@ -0,0 +1,24 @@
import * as React from 'react';
import type { EditableConfig, Tab, TabsLocale, MoreProps } from '../interface';
export interface OperationNodeProps {
prefixCls: string;
className?: string;
style?: React.CSSProperties;
id: string;
tabs: Tab[];
rtl: boolean;
tabBarGutter?: number;
activeKey: string;
mobile: boolean;
more?: MoreProps;
editable?: EditableConfig;
locale?: TabsLocale;
removeAriaLabel?: string;
onTabClick: (key: string, e: React.MouseEvent | React.KeyboardEvent) => void;
tabMoving?: boolean;
getPopupContainer?: (node: HTMLElement) => HTMLElement;
popupClassName?: string;
popupStyle?: React.CSSProperties;
}
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<OperationNodeProps & React.RefAttributes<HTMLDivElement>>>;
export default _default;
@@ -0,0 +1,200 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
var _dropdown = _interopRequireDefault(require("@rc-component/dropdown"));
var _menu = _interopRequireWildcard(require("@rc-component/menu"));
var _KeyCode = _interopRequireDefault(require("@rc-component/util/lib/KeyCode"));
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _util = require("../util");
var _AddButton = _interopRequireDefault(require("./AddButton"));
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 }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const OperationNode = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
id,
tabs,
locale,
mobile,
more: moreProps = {},
style,
className,
editable,
tabBarGutter,
rtl,
removeAriaLabel,
onTabClick,
getPopupContainer,
popupClassName,
popupStyle
} = props;
// ======================== Dropdown ========================
const [open, setOpen] = (0, _react.useState)(false);
const [selectedKey, setSelectedKey] = (0, _react.useState)(null);
const {
icon: moreIcon = 'More'
} = moreProps;
const popupId = `${id}-more-popup`;
const dropdownPrefix = `${prefixCls}-dropdown`;
const selectedItemId = selectedKey !== null ? `${popupId}-${selectedKey}` : null;
const dropdownAriaLabel = locale?.dropdownAriaLabel;
function onRemoveTab(event, key) {
event.preventDefault();
event.stopPropagation();
editable.onEdit('remove', {
key,
event
});
}
const menu = /*#__PURE__*/React.createElement(_menu.default, {
onClick: ({
key,
domEvent
}) => {
onTabClick(key, domEvent);
setOpen(false);
},
prefixCls: `${dropdownPrefix}-menu`,
id: popupId,
tabIndex: -1,
role: "listbox",
"aria-activedescendant": selectedItemId,
selectedKeys: [selectedKey],
"aria-label": dropdownAriaLabel !== undefined ? dropdownAriaLabel : 'expanded dropdown'
}, tabs.map(tab => {
const {
closable,
disabled,
closeIcon,
key,
label
} = tab;
const removable = (0, _util.getRemovable)(closable, closeIcon, editable, disabled);
return /*#__PURE__*/React.createElement(_menu.MenuItem, {
key: key,
id: `${popupId}-${key}`,
role: "option",
"aria-controls": id && `${id}-panel-${key}`,
disabled: disabled
}, /*#__PURE__*/React.createElement("span", null, label), removable && /*#__PURE__*/React.createElement("button", {
type: "button",
"aria-label": removeAriaLabel || 'remove',
tabIndex: 0,
className: `${dropdownPrefix}-menu-item-remove`,
onClick: e => {
e.stopPropagation();
onRemoveTab(e, key);
}
}, closeIcon || editable.removeIcon || '×'));
}));
function selectOffset(offset) {
const enabledTabs = tabs.filter(tab => !tab.disabled);
let selectedIndex = enabledTabs.findIndex(tab => tab.key === selectedKey) || 0;
const len = enabledTabs.length;
for (let i = 0; i < len; i += 1) {
selectedIndex = (selectedIndex + offset + len) % len;
const tab = enabledTabs[selectedIndex];
if (!tab.disabled) {
setSelectedKey(tab.key);
return;
}
}
}
function onKeyDown(e) {
const {
which
} = e;
if (!open) {
if ([_KeyCode.default.DOWN, _KeyCode.default.SPACE, _KeyCode.default.ENTER].includes(which)) {
setOpen(true);
e.preventDefault();
}
return;
}
switch (which) {
case _KeyCode.default.UP:
selectOffset(-1);
e.preventDefault();
break;
case _KeyCode.default.DOWN:
selectOffset(1);
e.preventDefault();
break;
case _KeyCode.default.ESC:
setOpen(false);
break;
case _KeyCode.default.SPACE:
case _KeyCode.default.ENTER:
if (selectedKey !== null) {
onTabClick(selectedKey, e);
}
break;
}
}
// ========================= Effect =========================
(0, _react.useEffect)(() => {
// We use query element here to avoid React strict warning
const ele = document.getElementById(selectedItemId);
if (ele?.scrollIntoView) {
ele.scrollIntoView(false);
}
}, [selectedItemId, selectedKey]);
(0, _react.useEffect)(() => {
if (!open) {
setSelectedKey(null);
}
}, [open]);
// ========================= Render =========================
const moreStyle = {
marginInlineStart: tabBarGutter
};
if (!tabs.length) {
moreStyle.visibility = 'hidden';
moreStyle.order = 1;
}
const overlayClassName = (0, _clsx.clsx)(popupClassName, {
[`${dropdownPrefix}-rtl`]: rtl
});
const moreNode = mobile ? null : /*#__PURE__*/React.createElement(_dropdown.default, _extends({
prefixCls: dropdownPrefix,
overlay: menu,
visible: tabs.length ? open : false,
onVisibleChange: setOpen,
overlayClassName: overlayClassName,
overlayStyle: popupStyle,
mouseEnterDelay: 0.1,
mouseLeaveDelay: 0.1,
getPopupContainer: getPopupContainer
}, moreProps), /*#__PURE__*/React.createElement("button", {
type: "button",
className: `${prefixCls}-nav-more`,
style: moreStyle,
"aria-haspopup": "listbox",
"aria-controls": popupId,
id: `${id}-more`,
"aria-expanded": open,
onKeyDown: onKeyDown
}, moreIcon));
return /*#__PURE__*/React.createElement("div", {
className: (0, _clsx.clsx)(`${prefixCls}-nav-operations`, className),
style: style,
ref: ref
}, moreNode, /*#__PURE__*/React.createElement(_AddButton.default, {
prefixCls: prefixCls,
locale: locale,
editable: editable
}));
});
var _default = exports.default = /*#__PURE__*/React.memo(OperationNode, (_, next) =>
// https://github.com/ant-design/ant-design/issues/32544
// We'd better remove syntactic sugar in `rc-menu` since this has perf issue
next.tabMoving);
@@ -0,0 +1,27 @@
import * as React from 'react';
import type { EditableConfig, Tab } from '../interface';
export interface TabNodeProps {
id: string;
prefixCls: string;
tab: Tab;
active: boolean;
focus: boolean;
closable?: boolean;
editable?: EditableConfig;
onClick?: (e: React.MouseEvent | React.KeyboardEvent) => void;
onResize?: (width: number, height: number, left: number, top: number) => void;
renderWrapper?: (node: React.ReactElement) => React.ReactElement;
removeAriaLabel?: string;
tabCount: number;
currentPosition: number;
removeIcon?: React.ReactNode;
onKeyDown: React.KeyboardEventHandler;
onMouseDown: React.MouseEventHandler;
onMouseUp: React.MouseEventHandler;
onFocus: React.FocusEventHandler;
onBlur: React.FocusEventHandler;
style?: React.CSSProperties;
className?: string;
}
declare const TabNode: React.FC<TabNodeProps>;
export default TabNode;
@@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
var React = _interopRequireWildcard(require("react"));
var _util = require("../util");
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 TabNode = props => {
const {
prefixCls,
id,
active,
focus,
tab: {
key,
label,
disabled,
closeIcon,
icon
},
closable,
renderWrapper,
removeAriaLabel,
editable,
onClick,
onFocus,
onBlur,
onKeyDown,
onMouseDown,
onMouseUp,
style,
className,
tabCount,
currentPosition
} = props;
const tabPrefix = `${prefixCls}-tab`;
const removable = (0, _util.getRemovable)(closable, closeIcon, editable, disabled);
function onInternalClick(e) {
if (disabled) {
return;
}
onClick(e);
}
function onRemoveTab(event) {
event.preventDefault();
event.stopPropagation();
editable.onEdit('remove', {
key,
event
});
}
const labelNode = React.useMemo(() => icon && typeof label === 'string' ? /*#__PURE__*/React.createElement("span", null, label) : label, [label, icon]);
const btnRef = React.useRef(null);
React.useEffect(() => {
if (focus && btnRef.current) {
btnRef.current.focus();
}
}, [focus]);
const node = /*#__PURE__*/React.createElement("div", {
key: key,
"data-node-key": (0, _util.genDataNodeKey)(key),
className: (0, _clsx.clsx)(tabPrefix, className, {
[`${tabPrefix}-with-remove`]: removable,
[`${tabPrefix}-active`]: active,
[`${tabPrefix}-disabled`]: disabled,
[`${tabPrefix}-focus`]: focus
}),
style: style,
onClick: onInternalClick
}, /*#__PURE__*/React.createElement("div", {
ref: btnRef,
role: "tab",
"aria-selected": active,
id: id && `${id}-tab-${key}`,
className: `${tabPrefix}-btn`,
"aria-controls": id && `${id}-panel-${key}`,
"aria-disabled": disabled,
tabIndex: disabled ? null : active ? 0 : -1,
onClick: e => {
e.stopPropagation();
onInternalClick(e);
},
onKeyDown: onKeyDown,
onMouseDown: onMouseDown,
onMouseUp: onMouseUp,
onFocus: onFocus,
onBlur: onBlur
}, focus && /*#__PURE__*/React.createElement("div", {
"aria-live": "polite",
style: {
width: 0,
height: 0,
position: 'absolute',
overflow: 'hidden',
opacity: 0
}
}, `Tab ${currentPosition} of ${tabCount}`), icon && /*#__PURE__*/React.createElement("span", {
className: `${tabPrefix}-icon`
}, icon), label && labelNode), removable && /*#__PURE__*/React.createElement("button", {
type: "button",
"aria-label": removeAriaLabel || 'remove',
tabIndex: active ? 0 : -1,
className: `${tabPrefix}-remove`,
onClick: e => {
e.stopPropagation();
onRemoveTab(e);
}
}, closeIcon || editable.removeIcon || '×'));
return renderWrapper ? renderWrapper(node) : node;
};
var _default = exports.default = TabNode;
@@ -0,0 +1,5 @@
import * as React from 'react';
import type { TabNavListProps } from '.';
export type TabNavListWrapperProps = Required<Omit<TabNavListProps, 'children' | 'className'>> & TabNavListProps;
declare const TabNavListWrapper: React.FC<TabNavListWrapperProps>;
export default TabNavListWrapper;
@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var React = _interopRequireWildcard(require("react"));
var _ = _interopRequireDefault(require("."));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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; }
// zombieJ: To compatible with `renderTabBar` usage.
// We have to create a TabNavList components.
const TabNavListWrapper = ({
renderTabBar,
...restProps
}) => {
if (renderTabBar) {
return renderTabBar(restProps, _.default);
}
return /*#__PURE__*/React.createElement(_.default, restProps);
};
if (process.env.NODE_ENV !== 'production') {
TabNavListWrapper.displayName = 'TabNavListWrapper';
}
var _default = exports.default = TabNavListWrapper;
@@ -0,0 +1,33 @@
import * as React from 'react';
import type { GetIndicatorSize } from '../hooks/useIndicator';
import type { AnimatedConfig, EditableConfig, MoreProps, OnTabScroll, RenderTabBar, TabBarExtraContent, TabPosition, TabsLocale } from '../interface';
import type { SemanticName } from '../Tabs';
export interface TabNavListProps {
id: string;
tabPosition: TabPosition;
activeKey: string;
rtl: boolean;
animated?: AnimatedConfig;
extra?: TabBarExtraContent;
editable?: EditableConfig;
more?: MoreProps;
mobile: boolean;
tabBarGutter?: number;
renderTabBar?: RenderTabBar;
className?: string;
style?: React.CSSProperties;
locale?: TabsLocale;
onTabClick: (activeKey: string, e: React.MouseEvent | React.KeyboardEvent) => void;
onTabScroll?: OnTabScroll;
children?: (node: React.ReactElement) => React.ReactElement;
getPopupContainer?: (node: HTMLElement) => HTMLElement;
popupClassName?: string;
indicator?: {
size?: GetIndicatorSize;
align?: 'start' | 'center' | 'end';
};
classNames?: Partial<Record<SemanticName, string>>;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
}
declare const TabNavList: React.ForwardRefExoticComponent<TabNavListProps & React.RefAttributes<HTMLDivElement>>;
export default TabNavList;
+598
View File
@@ -0,0 +1,598 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
var _resizeObserver = _interopRequireDefault(require("@rc-component/resize-observer"));
var _useEvent = _interopRequireDefault(require("@rc-component/util/lib/hooks/useEvent"));
var _ref = require("@rc-component/util/lib/ref");
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _TabContext = _interopRequireDefault(require("../TabContext"));
var _useIndicator = _interopRequireDefault(require("../hooks/useIndicator"));
var _useOffsets = _interopRequireDefault(require("../hooks/useOffsets"));
var _useSyncState = _interopRequireDefault(require("../hooks/useSyncState"));
var _useTouchMove = _interopRequireDefault(require("../hooks/useTouchMove"));
var _useUpdate = _interopRequireWildcard(require("../hooks/useUpdate"));
var _useVisibleRange = _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 (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 }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const getTabSize = (tab, containerRect) => {
// tabListRef
const {
offsetWidth,
offsetHeight,
offsetTop,
offsetLeft
} = tab;
const {
width,
height,
left,
top
} = tab.getBoundingClientRect();
// Use getBoundingClientRect to avoid decimal inaccuracy
if (Math.abs(width - offsetWidth) < 1) {
return [width, height, left - containerRect.left, top - containerRect.top];
}
return [offsetWidth, offsetHeight, offsetLeft, offsetTop];
};
const getSize = refObj => {
const {
offsetWidth = 0,
offsetHeight = 0
} = refObj.current || {};
// Use getBoundingClientRect to avoid decimal inaccuracy
if (refObj.current) {
const {
width,
height
} = refObj.current.getBoundingClientRect();
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`
*/
const getUnitValue = (size, tabPositionTopOrBottom) => {
return size[tabPositionTopOrBottom ? 0 : 1];
};
const TabNavList = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
className,
style,
id,
animated,
activeKey,
rtl,
extra,
editable,
locale,
tabPosition,
tabBarGutter,
children,
onTabClick,
onTabScroll,
indicator,
classNames: tabsClassNames,
styles
} = props;
const {
prefixCls,
tabs
} = React.useContext(_TabContext.default);
const containerRef = (0, _react.useRef)(null);
const extraLeftRef = (0, _react.useRef)(null);
const extraRightRef = (0, _react.useRef)(null);
const tabsWrapperRef = (0, _react.useRef)(null);
const tabListRef = (0, _react.useRef)(null);
const operationsRef = (0, _react.useRef)(null);
const innerAddButtonRef = (0, _react.useRef)(null);
const tabPositionTopOrBottom = tabPosition === 'top' || tabPosition === 'bottom';
const [transformLeft, setTransformLeft] = (0, _useSyncState.default)(0, (next, prev) => {
if (tabPositionTopOrBottom && onTabScroll) {
onTabScroll({
direction: next > prev ? 'left' : 'right'
});
}
});
const [transformTop, setTransformTop] = (0, _useSyncState.default)(0, (next, prev) => {
if (!tabPositionTopOrBottom && onTabScroll) {
onTabScroll({
direction: next > prev ? 'top' : 'bottom'
});
}
});
const [containerExcludeExtraSize, setContainerExcludeExtraSize] = (0, _react.useState)([0, 0]);
const [tabContentSize, setTabContentSize] = (0, _react.useState)([0, 0]);
const [addSize, setAddSize] = (0, _react.useState)([0, 0]);
const [operationSize, setOperationSize] = (0, _react.useState)([0, 0]);
const [tabSizes, setTabSizes] = (0, _useUpdate.useUpdateState)(new Map());
const tabOffsets = (0, _useOffsets.default)(tabs, tabSizes, tabContentSize[0]);
// ========================== Unit =========================
const containerExcludeExtraSizeValue = getUnitValue(containerExcludeExtraSize, tabPositionTopOrBottom);
const tabContentSizeValue = getUnitValue(tabContentSize, tabPositionTopOrBottom);
const addSizeValue = getUnitValue(addSize, tabPositionTopOrBottom);
const operationSizeValue = getUnitValue(operationSize, tabPositionTopOrBottom);
const needScroll = Math.floor(containerExcludeExtraSizeValue) < Math.floor(tabContentSizeValue + addSizeValue);
const visibleTabContentValue = needScroll ? containerExcludeExtraSizeValue - operationSizeValue : containerExcludeExtraSizeValue - addSizeValue;
// ========================== Util =========================
const operationsHiddenClassName = `${prefixCls}-nav-operations-hidden`;
let transformMin = 0;
let 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 ========================
const touchMovingRef = (0, _react.useRef)(null);
const [lockAnimation, setLockAnimation] = (0, _react.useState)();
function doLockAnimation() {
setLockAnimation(Date.now());
}
function clearTouchMoving() {
if (touchMovingRef.current) {
clearTimeout(touchMovingRef.current);
}
}
(0, _useTouchMove.default)(tabsWrapperRef, (offsetX, offsetY) => {
function doMove(setState, offset) {
setState(value => {
const 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)(() => {
clearTouchMoving();
if (lockAnimation) {
touchMovingRef.current = setTimeout(() => {
setLockAnimation(0);
}, 100);
}
return clearTouchMoving;
}, [lockAnimation]);
// ===================== Visible Range =====================
// Render tab node & collect tab offset
const [visibleStart, visibleEnd] = (0, _useVisibleRange.default)(tabOffsets,
// Container
visibleTabContentValue,
// Transform
tabPositionTopOrBottom ? transformLeft : transformTop,
// Tabs
tabContentSizeValue,
// Add
addSizeValue,
// Operation
operationSizeValue, {
...props,
tabs
});
// ========================= Scroll ========================
const scrollToTab = (0, _useEvent.default)((key = activeKey) => {
const tabOffset = tabOffsets.get(key) || {
width: 0,
height: 0,
left: 0,
right: 0,
top: 0
};
if (tabPositionTopOrBottom) {
// ============ Align with top & bottom ============
let 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 ============
let 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));
}
});
// ========================= Focus =========================
const [focusKey, setFocusKey] = (0, _react.useState)();
const [isMouse, setIsMouse] = (0, _react.useState)(false);
const enabledTabs = tabs.filter(tab => !tab.disabled).map(tab => tab.key);
const onOffset = offset => {
const currentIndex = enabledTabs.indexOf(focusKey || activeKey);
const len = enabledTabs.length;
const nextIndex = (currentIndex + offset + len) % len;
const newKey = enabledTabs[nextIndex];
setFocusKey(newKey);
};
const handleRemoveTab = (removalTabKey, e) => {
const removeIndex = enabledTabs.indexOf(removalTabKey);
const removeTab = tabs.find(tab => tab.key === removalTabKey);
const removable = (0, _util.getRemovable)(removeTab?.closable, removeTab?.closeIcon, editable, removeTab?.disabled);
if (removable) {
e.preventDefault();
e.stopPropagation();
editable.onEdit('remove', {
key: removalTabKey,
event: e
});
// when remove last tab, focus previous tab
if (removeIndex === enabledTabs.length - 1) {
onOffset(-1);
} else {
onOffset(1);
}
}
};
const handleMouseDown = (key, e) => {
setIsMouse(true);
// Middle mouse button
if (e.button === 1) {
handleRemoveTab(key, e);
}
};
const handleKeyDown = e => {
const {
code
} = e;
const isRTL = rtl && tabPositionTopOrBottom;
const firstEnabledTab = enabledTabs[0];
const lastEnabledTab = enabledTabs[enabledTabs.length - 1];
switch (code) {
// LEFT
case 'ArrowLeft':
{
if (tabPositionTopOrBottom) {
onOffset(isRTL ? 1 : -1);
}
break;
}
// RIGHT
case 'ArrowRight':
{
if (tabPositionTopOrBottom) {
onOffset(isRTL ? -1 : 1);
}
break;
}
// UP
case 'ArrowUp':
{
e.preventDefault();
if (!tabPositionTopOrBottom) {
onOffset(-1);
}
break;
}
// DOWN
case 'ArrowDown':
{
e.preventDefault();
if (!tabPositionTopOrBottom) {
onOffset(1);
}
break;
}
// HOME
case 'Home':
{
e.preventDefault();
setFocusKey(firstEnabledTab);
break;
}
// END
case 'End':
{
e.preventDefault();
setFocusKey(lastEnabledTab);
break;
}
// Enter & Space
case 'Enter':
case 'Space':
{
e.preventDefault();
onTabClick(focusKey ?? activeKey, e);
break;
}
// Backspace
case 'Backspace':
case 'Delete':
{
handleRemoveTab(focusKey, e);
break;
}
}
};
// ========================== Tab ==========================
const tabNodeStyle = {};
if (tabPositionTopOrBottom) {
tabNodeStyle.marginInlineStart = tabBarGutter;
} else {
tabNodeStyle.marginTop = tabBarGutter;
}
const tabNodes = tabs.map((tab, i) => {
const {
key
} = tab;
return /*#__PURE__*/React.createElement(_TabNode.default, {
id: id,
prefixCls: prefixCls,
key: key,
tab: tab,
className: tabsClassNames?.item
/* first node should not have margin left */,
style: i === 0 ? styles?.item : {
...tabNodeStyle,
...styles?.item
},
closable: tab.closable,
editable: editable,
active: key === activeKey,
focus: key === focusKey,
renderWrapper: children,
removeAriaLabel: locale?.removeAriaLabel,
tabCount: enabledTabs.length,
currentPosition: i + 1,
onClick: e => {
onTabClick(key, e);
},
onKeyDown: handleKeyDown,
onFocus: () => {
if (!isMouse) {
setFocusKey(key);
}
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;
},
onBlur: () => {
setFocusKey(undefined);
},
onMouseDown: e => handleMouseDown(key, e),
onMouseUp: () => {
setIsMouse(false);
}
});
});
// Update buttons records
const updateTabSizes = () => setTabSizes(() => {
const newSizes = new Map();
const listRect = tabListRef.current?.getBoundingClientRect();
tabs.forEach(({
key
}) => {
const btnNode = tabListRef.current?.querySelector(`[data-node-key="${(0, _util.genDataNodeKey)(key)}"]`);
if (btnNode) {
const [width, height, left, top] = getTabSize(btnNode, listRect);
newSizes.set(key, {
width,
height,
left,
top
});
}
});
return newSizes;
});
(0, _react.useEffect)(() => {
updateTabSizes();
}, [tabs.map(tab => tab.key).join('_')]);
const onListHolderResize = (0, _useUpdate.default)(() => {
// Update wrapper records
const containerSize = getSize(containerRef);
const extraLeftSize = getSize(extraLeftRef);
const extraRightSize = getSize(extraRightRef);
setContainerExcludeExtraSize([containerSize[0] - extraLeftSize[0] - extraRightSize[0], containerSize[1] - extraLeftSize[1] - extraRightSize[1]]);
const newAddSize = getSize(innerAddButtonRef);
setAddSize(newAddSize);
const newOperationSize = getSize(operationsRef);
setOperationSize(newOperationSize);
// Which includes add button size
const tabContentFullSize = getSize(tabListRef);
setTabContentSize([tabContentFullSize[0] - newAddSize[0], tabContentFullSize[1] - newAddSize[1]]);
// Update buttons records
updateTabSizes();
});
// ======================== Dropdown =======================
const startHiddenTabs = tabs.slice(0, visibleStart);
const endHiddenTabs = tabs.slice(visibleEnd + 1);
const hiddenTabs = [...startHiddenTabs, ...endHiddenTabs];
// =================== Link & Operations ===================
const activeTabOffset = tabOffsets.get(activeKey);
const {
style: indicatorStyle
} = (0, _useIndicator.default)({
activeTabOffset,
horizontal: tabPositionTopOrBottom,
indicator,
rtl
});
// ========================= Effect ========================
(0, _react.useEffect)(() => {
scrollToTab();
}, [activeKey, transformMin, transformMax, (0, _util.stringify)(activeTabOffset), (0, _util.stringify)(tabOffsets), tabPositionTopOrBottom]);
// Should recalculate when rtl changed
(0, _react.useEffect)(() => {
onListHolderResize();
// eslint-disable-next-line
}, [rtl]);
// ========================= Render ========================
const hasDropdown = !!hiddenTabs.length;
const wrapPrefix = `${prefixCls}-nav-wrap`;
let pingLeft;
let pingRight;
let pingTop;
let 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(_resizeObserver.default, {
onResize: onListHolderResize
}, /*#__PURE__*/React.createElement("div", {
ref: (0, _ref.useComposeRef)(ref, containerRef),
role: "tablist",
"aria-orientation": tabPositionTopOrBottom ? 'horizontal' : 'vertical',
className: (0, _clsx.clsx)(`${prefixCls}-nav`, className, tabsClassNames?.header),
style: {
...styles?.header,
...style
},
onKeyDown: () => {
// No need animation when use keyboard
doLockAnimation();
}
}, /*#__PURE__*/React.createElement(_ExtraContent.default, {
ref: extraLeftRef,
position: "left",
extra: extra,
prefixCls: prefixCls
}), /*#__PURE__*/React.createElement(_resizeObserver.default, {
onResize: onListHolderResize
}, /*#__PURE__*/React.createElement("div", {
className: (0, _clsx.clsx)(wrapPrefix, {
[`${wrapPrefix}-ping-left`]: pingLeft,
[`${wrapPrefix}-ping-right`]: pingRight,
[`${wrapPrefix}-ping-top`]: pingTop,
[`${wrapPrefix}-ping-bottom`]: pingBottom
}),
ref: tabsWrapperRef
}, /*#__PURE__*/React.createElement(_resizeObserver.default, {
onResize: onListHolderResize
}, /*#__PURE__*/React.createElement("div", {
ref: tabListRef,
className: `${prefixCls}-nav-list`,
style: {
transform: `translate(${transformLeft}px, ${transformTop}px)`,
transition: lockAnimation ? 'none' : undefined
}
}, tabNodes, /*#__PURE__*/React.createElement(_AddButton.default, {
ref: innerAddButtonRef,
prefixCls: prefixCls,
locale: locale,
editable: editable,
style: {
...(tabNodes.length === 0 ? undefined : tabNodeStyle),
visibility: hasDropdown ? 'hidden' : null
}
}), /*#__PURE__*/React.createElement("div", {
className: (0, _clsx.clsx)(`${prefixCls}-ink-bar`, tabsClassNames?.indicator, {
[`${prefixCls}-ink-bar-animated`]: animated.inkBar
}),
style: {
...indicatorStyle,
...styles?.indicator
}
}))))), /*#__PURE__*/React.createElement(_OperationNode.default, _extends({}, props, {
removeAriaLabel: locale?.removeAriaLabel,
ref: operationsRef,
prefixCls: prefixCls,
tabs: hiddenTabs,
className: !hasDropdown && operationsHiddenClassName,
popupStyle: styles?.popup,
tabMoving: !!lockAnimation
})), /*#__PURE__*/React.createElement(_ExtraContent.default, {
ref: extraRightRef,
position: "right",
extra: extra,
prefixCls: prefixCls
})));
/* eslint-enable */
});
var _default = exports.default = TabNavList;
@@ -0,0 +1,20 @@
import * as React from 'react';
export interface TabPaneProps {
tab?: React.ReactNode;
className?: string;
style?: React.CSSProperties;
disabled?: boolean;
children?: React.ReactNode;
forceRender?: boolean;
closable?: boolean;
closeIcon?: React.ReactNode;
icon?: React.ReactNode;
prefixCls?: string;
tabKey?: string;
id?: string;
animated?: boolean;
active?: boolean;
destroyOnHidden?: boolean;
}
declare const TabPane: React.ForwardRefExoticComponent<TabPaneProps & React.RefAttributes<HTMLDivElement>>;
export default TabPane;
@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
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; }
const TabPane = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
className,
style,
id,
active,
tabKey,
children
} = props;
const hasContent = React.Children.count(children) > 0;
return /*#__PURE__*/React.createElement("div", {
id: id && `${id}-panel-${tabKey}`,
role: "tabpanel",
tabIndex: active && hasContent ? 0 : -1,
"aria-labelledby": id && `${id}-tab-${tabKey}`,
"aria-hidden": !active,
style: style,
className: (0, _clsx.clsx)(prefixCls, active && `${prefixCls}-active`, className),
ref: ref
}, children);
});
if (process.env.NODE_ENV !== 'production') {
TabPane.displayName = 'TabPane';
}
var _default = exports.default = TabPane;
@@ -0,0 +1,13 @@
import * as React from 'react';
import type { AnimatedConfig, TabPosition } from '../interface';
export interface TabPanelListProps {
activeKey: string;
id: string;
animated?: AnimatedConfig;
tabPosition?: TabPosition;
destroyOnHidden?: boolean;
contentStyle?: React.CSSProperties;
contentClassName?: string;
}
declare const TabPanelList: React.FC<TabPanelListProps>;
export default TabPanelList;
@@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
var _motion = _interopRequireDefault(require("@rc-component/motion"));
var React = _interopRequireWildcard(require("react"));
var _TabContext = _interopRequireDefault(require("../TabContext"));
var _TabPane = _interopRequireDefault(require("./TabPane"));
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 }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const TabPanelList = props => {
const {
id,
activeKey,
animated,
tabPosition,
destroyOnHidden,
contentStyle,
contentClassName
} = props;
const {
prefixCls,
tabs
} = React.useContext(_TabContext.default);
const tabPaneAnimated = animated.tabPane;
const tabPanePrefixCls = `${prefixCls}-tabpane`;
return /*#__PURE__*/React.createElement("div", {
className: (0, _clsx.clsx)(`${prefixCls}-content-holder`)
}, /*#__PURE__*/React.createElement("div", {
className: (0, _clsx.clsx)(`${prefixCls}-content`, `${prefixCls}-content-${tabPosition}`, {
[`${prefixCls}-content-animated`]: tabPaneAnimated
})
}, tabs.map(item => {
const {
key,
forceRender,
style: paneStyle,
className: paneClassName,
destroyOnHidden: itemDestroyOnHidden,
...restTabProps
} = item;
const active = key === activeKey;
return /*#__PURE__*/React.createElement(_motion.default, _extends({
key: key,
visible: active,
forceRender: forceRender,
removeOnLeave: !!(destroyOnHidden ?? itemDestroyOnHidden),
leavedClassName: `${tabPanePrefixCls}-hidden`
}, animated.tabPaneMotion), ({
style: motionStyle,
className: motionClassName
}, ref) => /*#__PURE__*/React.createElement(_TabPane.default, _extends({}, restTabProps, {
prefixCls: tabPanePrefixCls,
id: id,
tabKey: key,
animated: tabPaneAnimated,
active: active,
style: {
...contentStyle,
...paneStyle,
...motionStyle
},
className: (0, _clsx.clsx)(contentClassName, paneClassName, motionClassName),
ref: ref
})));
})));
};
var _default = exports.default = TabPanelList;
+38
View File
@@ -0,0 +1,38 @@
import * as React from 'react';
import type { GetIndicatorSize } from './hooks/useIndicator';
import type { AnimatedConfig, EditableConfig, MoreProps, OnTabScroll, RenderTabBar, Tab, TabBarExtraContent, TabPosition, TabsLocale } from './interface';
export type SemanticName = 'popup' | 'item' | 'indicator' | 'content' | 'header';
export interface TabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'children'> {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
classNames?: Partial<Record<SemanticName, string>>;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
id?: string;
items?: Tab[];
activeKey?: string;
defaultActiveKey?: string;
direction?: 'ltr' | 'rtl';
animated?: boolean | AnimatedConfig;
renderTabBar?: RenderTabBar;
tabBarExtraContent?: TabBarExtraContent;
tabBarGutter?: number;
tabBarStyle?: React.CSSProperties;
tabPosition?: TabPosition;
destroyOnHidden?: boolean;
onChange?: (activeKey: string) => void;
onTabClick?: (activeKey: string, e: React.KeyboardEvent | React.MouseEvent) => void;
onTabScroll?: OnTabScroll;
editable?: EditableConfig;
getPopupContainer?: (node: HTMLElement) => HTMLElement;
locale?: TabsLocale;
more?: MoreProps;
/** @private Internal usage. Not promise will rename in future */
popupClassName?: string;
indicator?: {
size?: GetIndicatorSize;
align?: 'start' | 'center' | 'end';
};
}
declare const Tabs: React.ForwardRefExoticComponent<TabsProps & React.RefAttributes<HTMLDivElement>>;
export default Tabs;
+161
View File
@@ -0,0 +1,161 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _clsx = require("clsx");
var _useControlledState = _interopRequireDefault(require("@rc-component/util/lib/hooks/useControlledState"));
var _isMobile = _interopRequireDefault(require("@rc-component/util/lib/isMobile"));
var _react = _interopRequireWildcard(require("react"));
var React = _react;
var _TabContext = _interopRequireDefault(require("./TabContext"));
var _Wrapper = _interopRequireDefault(require("./TabNavList/Wrapper"));
var _TabPanelList = _interopRequireDefault(require("./TabPanelList"));
var _useAnimateConfig = _interopRequireDefault(require("./hooks/useAnimateConfig"));
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 }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } // Accessibility https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role
/**
* Should added antd:
* - type
*
* Removed:
* - onNextClick
* - onPrevClick
* - keyboard
*/
// Used for accessibility
let uuid = 0;
const Tabs = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
id,
prefixCls = 'rc-tabs',
className,
items,
direction,
activeKey,
defaultActiveKey,
editable,
animated,
tabPosition = 'top',
tabBarGutter,
tabBarStyle,
tabBarExtraContent,
locale,
more,
destroyOnHidden,
renderTabBar,
onChange,
onTabClick,
onTabScroll,
getPopupContainer,
popupClassName,
indicator,
classNames: tabsClassNames,
styles,
...restProps
} = props;
const tabs = React.useMemo(() => (items || []).filter(item => item && typeof item === 'object' && 'key' in item), [items]);
const rtl = direction === 'rtl';
const mergedAnimated = (0, _useAnimateConfig.default)(animated);
// ======================== Mobile ========================
const [mobile, setMobile] = (0, _react.useState)(false);
(0, _react.useEffect)(() => {
// Only update on the client side
setMobile((0, _isMobile.default)());
}, []);
// ====================== Active Key ======================
const [mergedActiveKey, setMergedActiveKey] = (0, _useControlledState.default)(defaultActiveKey ?? tabs[0]?.key, activeKey);
const [activeIndex, setActiveIndex] = (0, _react.useState)(() => tabs.findIndex(tab => tab.key === mergedActiveKey));
// Reset active key if not exist anymore
(0, _react.useEffect)(() => {
let newActiveIndex = tabs.findIndex(tab => tab.key === mergedActiveKey);
if (newActiveIndex === -1) {
newActiveIndex = Math.max(0, Math.min(activeIndex, tabs.length - 1));
setMergedActiveKey(tabs[newActiveIndex]?.key);
}
setActiveIndex(newActiveIndex);
}, [tabs.map(tab => tab.key).join('_'), mergedActiveKey, activeIndex]);
// ===================== Accessibility ====================
const [mergedId, setMergedId] = (0, _useControlledState.default)(null, id);
// Async generate id to avoid ssr mapping failed
(0, _react.useEffect)(() => {
if (!id) {
setMergedId(`rc-tabs-${process.env.NODE_ENV === 'test' ? 'test' : uuid}`);
uuid += 1;
}
}, []);
// ======================== Events ========================
function onInternalTabClick(key, e) {
onTabClick?.(key, e);
const isActiveChanged = key !== mergedActiveKey;
setMergedActiveKey(key);
if (isActiveChanged) {
onChange?.(key);
}
}
// ======================== Render ========================
const sharedProps = {
id: mergedId,
activeKey: mergedActiveKey,
animated: mergedAnimated,
tabPosition,
rtl,
mobile
};
const tabNavBarProps = {
...sharedProps,
editable,
locale,
more,
tabBarGutter,
onTabClick: onInternalTabClick,
onTabScroll,
extra: tabBarExtraContent,
style: tabBarStyle,
getPopupContainer,
popupClassName: (0, _clsx.clsx)(popupClassName, tabsClassNames?.popup),
indicator,
styles,
classNames: tabsClassNames
};
const memoizedValue = React.useMemo(() => {
return {
tabs,
prefixCls
};
}, [tabs, prefixCls]);
return /*#__PURE__*/React.createElement(_TabContext.default.Provider, {
value: memoizedValue
}, /*#__PURE__*/React.createElement("div", _extends({
ref: ref,
id: id,
className: (0, _clsx.clsx)(prefixCls, `${prefixCls}-${tabPosition}`, {
[`${prefixCls}-mobile`]: mobile,
[`${prefixCls}-editable`]: editable,
[`${prefixCls}-rtl`]: rtl
}, className)
}, restProps), /*#__PURE__*/React.createElement(_Wrapper.default, _extends({}, tabNavBarProps, {
renderTabBar: renderTabBar
})), /*#__PURE__*/React.createElement(_TabPanelList.default, _extends({
destroyOnHidden: destroyOnHidden
}, sharedProps, {
contentStyle: styles?.content,
contentClassName: tabsClassNames?.content,
animated: mergedAnimated
}))));
});
if (process.env.NODE_ENV !== 'production') {
Tabs.displayName = 'Tabs';
}
var _default = exports.default = Tabs;
@@ -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]);
}
+4
View File
@@ -0,0 +1,4 @@
import type { TabsProps } from './Tabs';
import Tabs from './Tabs';
export type { TabsProps };
export default Tabs;
+9
View File
@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _Tabs = _interopRequireDefault(require("./Tabs"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = exports.default = _Tabs.default;
+75
View File
@@ -0,0 +1,75 @@
import type { CSSMotionProps } from '@rc-component/motion';
import type { DropdownProps } from '@rc-component/dropdown';
import type React from 'react';
import type { TabNavListProps } from './TabNavList';
import type { TabPaneProps } from './TabPanelList/TabPane';
export type TriggerProps = {
trigger?: 'hover' | 'click';
};
export type moreIcon = React.ReactNode;
export type MoreProps = {
icon?: moreIcon;
} & Omit<DropdownProps, 'children'>;
export type SizeInfo = [width: number, height: number];
export type TabSizeMap = Map<React.Key, {
width: number;
height: number;
left: number;
top: number;
}>;
export interface TabOffset {
width: number;
height: number;
left: number;
right: number;
top: number;
}
export type TabOffsetMap = Map<React.Key, TabOffset>;
export type TabPosition = 'left' | 'right' | 'top' | 'bottom';
export interface Tab extends Omit<TabPaneProps, 'tab'> {
key: string;
label: React.ReactNode;
}
type RenderTabBarProps = {
id: string;
activeKey: string;
animated: AnimatedConfig;
tabPosition: TabPosition;
rtl: boolean;
mobile: boolean;
editable: EditableConfig;
locale: TabsLocale;
more: MoreProps;
tabBarGutter: number;
onTabClick: (key: string, e: React.MouseEvent | React.KeyboardEvent) => void;
onTabScroll: OnTabScroll;
extra: TabBarExtraContent;
style: React.CSSProperties;
};
export type RenderTabBar = (props: RenderTabBarProps, DefaultTabBar: React.ComponentType<TabNavListProps>) => React.ReactElement;
export interface TabsLocale {
dropdownAriaLabel?: string;
removeAriaLabel?: string;
addAriaLabel?: string;
}
export interface EditableConfig {
onEdit: (type: 'add' | 'remove', info: {
key?: string;
event: React.MouseEvent | React.KeyboardEvent;
}) => void;
showAdd?: boolean;
removeIcon?: React.ReactNode;
addIcon?: React.ReactNode;
}
export interface AnimatedConfig {
inkBar?: boolean;
tabPane?: boolean;
tabPaneMotion?: CSSMotionProps;
}
export type OnTabScroll = (info: {
direction: 'left' | 'right' | 'top' | 'bottom';
}) => void;
export type TabBarExtraPosition = 'left' | 'right';
export type TabBarExtraMap = Partial<Record<TabBarExtraPosition, React.ReactNode>>;
export type TabBarExtraContent = React.ReactNode | TabBarExtraMap;
export {};
+5
View File
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
+10
View File
@@ -0,0 +1,10 @@
import type React from 'react';
import type { ReactNode } from 'react';
import type { EditableConfig } from './interface';
/**
* We trade Map as deps which may change with same value but different ref object.
* We should make it as hash for deps
* */
export declare function stringify<K extends PropertyKey, V>(obj: Record<K, V> | Map<K, V>): string;
export declare function genDataNodeKey(key: React.Key): string;
export declare function getRemovable(closable?: boolean, closeIcon?: ReactNode, editable?: EditableConfig, disabled?: boolean): boolean;
+42
View File
@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.genDataNodeKey = genDataNodeKey;
exports.getRemovable = getRemovable;
exports.stringify = stringify;
/**
* We trade Map as deps which may change with same value but different ref object.
* We should make it as hash for deps
* */
function stringify(obj) {
let tgt;
if (obj instanceof Map) {
tgt = {};
obj.forEach((v, k) => {
tgt[k] = v;
});
} else {
tgt = obj;
}
return JSON.stringify(tgt);
}
const RC_TABS_DOUBLE_QUOTE = 'TABS_DQ';
function genDataNodeKey(key) {
return String(key).replace(/"/g, RC_TABS_DOUBLE_QUOTE);
}
function getRemovable(closable, closeIcon, editable, disabled) {
if (
// Only editable tabs can be removed
!editable ||
// Tabs cannot be removed when disabled
disabled ||
// closable is false
closable === false ||
// If closable is undefined, the remove button should be hidden when closeIcon is null or false
closable === undefined && (closeIcon === false || closeIcon === null)) {
return false;
}
return true;
}