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
+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
import type { CollapseProps } from './interface';
declare const _default: React.ForwardRefExoticComponent<CollapseProps & React.RefAttributes<HTMLDivElement>> & {
/**
* @deprecated use `items` instead, will be removed in `v4.0.0`
*/
Panel: React.ForwardRefExoticComponent<import("./interface").CollapsePanelProps & React.RefAttributes<HTMLDivElement>>;
};
export default _default;
+82
View File
@@ -0,0 +1,82 @@
import _extends from "@babel/runtime/helpers/esm/extends";
import { clsx } from 'clsx';
import { useControlledState, useEvent } from '@rc-component/util';
import warning from "@rc-component/util/es/warning";
import React from 'react';
import useItems from "./hooks/useItems";
import CollapsePanel from "./Panel";
import pickAttrs from "@rc-component/util/es/pickAttrs";
function getActiveKeysArray(activeKey) {
let currentActiveKey = activeKey;
if (!Array.isArray(currentActiveKey)) {
const activeKeyType = typeof currentActiveKey;
currentActiveKey = activeKeyType === 'number' || activeKeyType === 'string' ? [currentActiveKey] : [];
}
return currentActiveKey.map(key => String(key));
}
const Collapse = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls = 'rc-collapse',
destroyOnHidden = false,
style,
accordion,
className,
children,
collapsible,
openMotion,
expandIcon,
activeKey: rawActiveKey,
defaultActiveKey,
onChange,
items,
classNames: customizeClassNames,
styles
} = props;
const collapseClassName = clsx(prefixCls, className);
const [internalActiveKey, setActiveKey] = useControlledState(defaultActiveKey, rawActiveKey);
const activeKey = getActiveKeysArray(internalActiveKey);
const triggerActiveKey = useEvent(next => {
const nextKeys = getActiveKeysArray(next);
setActiveKey(nextKeys);
onChange?.(nextKeys);
});
const onItemClick = key => {
if (accordion) {
triggerActiveKey(activeKey[0] === key ? [] : [key]);
} else {
triggerActiveKey(activeKey.includes(key) ? activeKey.filter(item => item !== key) : [...activeKey, key]);
}
};
// ======================== Children ========================
warning(!children, '[rc-collapse] `children` will be removed in next major version. Please use `items` instead.');
const mergedChildren = useItems(items, children, {
prefixCls,
accordion,
openMotion,
expandIcon,
collapsible,
destroyOnHidden,
onItemClick,
activeKey,
classNames: customizeClassNames,
styles
});
// ======================== Render ========================
return /*#__PURE__*/React.createElement("div", _extends({
ref: ref,
className: collapseClassName,
style: style,
role: accordion ? 'tablist' : undefined
}, pickAttrs(props, {
aria: true,
data: true
})), mergedChildren);
});
export default Object.assign(Collapse, {
/**
* @deprecated use `items` instead, will be removed in `v4.0.0`
*/
Panel: CollapsePanel
});
+4
View File
@@ -0,0 +1,4 @@
import React from 'react';
import type { CollapsePanelProps } from './interface';
declare const CollapsePanel: React.ForwardRefExoticComponent<CollapsePanelProps & React.RefAttributes<HTMLDivElement>>;
export default CollapsePanel;
+101
View File
@@ -0,0 +1,101 @@
import _extends from "@babel/runtime/helpers/esm/extends";
import { clsx } from 'clsx';
import CSSMotion from '@rc-component/motion';
import KeyCode from "@rc-component/util/es/KeyCode";
import React from 'react';
import PanelContent from "./PanelContent";
const CollapsePanel = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
showArrow = true,
headerClass,
isActive,
onItemClick,
forceRender,
className,
classNames: customizeClassNames = {},
styles = {},
prefixCls,
collapsible,
accordion,
panelKey,
extra,
header,
expandIcon,
openMotion,
destroyOnHidden,
children,
...resetProps
} = props;
const disabled = collapsible === 'disabled';
const ifExtraExist = extra !== null && extra !== undefined && typeof extra !== 'boolean';
const collapsibleProps = {
onClick: () => {
onItemClick?.(panelKey);
},
onKeyDown: e => {
if (e.key === 'Enter' || e.keyCode === KeyCode.ENTER || e.which === KeyCode.ENTER) {
onItemClick?.(panelKey);
}
},
role: accordion ? 'tab' : 'button',
['aria-expanded']: isActive,
['aria-disabled']: disabled,
tabIndex: disabled ? -1 : 0
};
// ======================== Icon ========================
const iconNodeInner = typeof expandIcon === 'function' ? expandIcon(props) : /*#__PURE__*/React.createElement("i", {
className: "arrow"
});
const iconNode = iconNodeInner && /*#__PURE__*/React.createElement("div", _extends({
className: clsx(`${prefixCls}-expand-icon`, customizeClassNames?.icon),
style: styles?.icon
}, ['header', 'icon'].includes(collapsible) ? collapsibleProps : {}), iconNodeInner);
const collapsePanelClassNames = clsx(`${prefixCls}-item`, {
[`${prefixCls}-item-active`]: isActive,
[`${prefixCls}-item-disabled`]: disabled
}, className);
const headerClassName = clsx(headerClass, `${prefixCls}-header`, {
[`${prefixCls}-collapsible-${collapsible}`]: !!collapsible
}, customizeClassNames?.header);
// ======================== HeaderProps ========================
const headerProps = {
className: headerClassName,
style: styles?.header,
...(['header', 'icon'].includes(collapsible) ? {} : collapsibleProps)
};
// ======================== Render ========================
return /*#__PURE__*/React.createElement("div", _extends({}, resetProps, {
ref: ref,
className: collapsePanelClassNames
}), /*#__PURE__*/React.createElement("div", headerProps, showArrow && iconNode, /*#__PURE__*/React.createElement("span", _extends({
className: clsx(`${prefixCls}-title`, customizeClassNames?.title),
style: styles?.title
}, collapsible === 'header' ? collapsibleProps : {}), header), ifExtraExist && /*#__PURE__*/React.createElement("div", {
className: `${prefixCls}-extra`
}, extra)), /*#__PURE__*/React.createElement(CSSMotion, _extends({
visible: isActive,
leavedClassName: `${prefixCls}-panel-hidden`
}, openMotion, {
forceRender: forceRender,
removeOnLeave: destroyOnHidden
}), ({
className: motionClassName,
style: motionStyle
}, motionRef) => {
return /*#__PURE__*/React.createElement(PanelContent, {
ref: motionRef,
prefixCls: prefixCls,
className: motionClassName,
classNames: customizeClassNames,
style: motionStyle,
styles: styles,
isActive: isActive,
forceRender: forceRender,
role: accordion ? 'tabpanel' : undefined
}, children);
}));
});
export default CollapsePanel;
@@ -0,0 +1,6 @@
import React from 'react';
import type { CollapsePanelProps } from './interface';
declare const PanelContent: React.ForwardRefExoticComponent<Readonly<CollapsePanelProps> & {
children?: React.ReactNode;
} & React.RefAttributes<HTMLDivElement>>;
export default PanelContent;
+40
View File
@@ -0,0 +1,40 @@
import { clsx } from 'clsx';
import React from 'react';
const PanelContent = /*#__PURE__*/React.forwardRef((props, ref) => {
const {
prefixCls,
forceRender,
className,
style,
children,
isActive,
role,
classNames: customizeClassNames,
styles
} = props;
const [rendered, setRendered] = React.useState(isActive || forceRender);
React.useEffect(() => {
if (forceRender || isActive) {
setRendered(true);
}
}, [forceRender, isActive]);
if (!rendered) {
return null;
}
return /*#__PURE__*/React.createElement("div", {
ref: ref,
className: clsx(`${prefixCls}-panel`, {
[`${prefixCls}-panel-active`]: isActive,
[`${prefixCls}-panel-inactive`]: !isActive
}, className),
style: style,
role: role
}, /*#__PURE__*/React.createElement("div", {
className: clsx(`${prefixCls}-body`, customizeClassNames?.body),
style: styles?.body
}, children));
});
if (process.env.NODE_ENV !== 'production') {
PanelContent.displayName = 'PanelContent';
}
export default PanelContent;
@@ -0,0 +1,7 @@
import React from 'react';
import type { CollapsePanelProps, CollapseProps, ItemType } from '../interface';
type Props = Pick<CollapsePanelProps, 'prefixCls' | 'onItemClick' | 'openMotion' | 'expandIcon' | 'classNames' | 'styles'> & Pick<CollapseProps, 'accordion' | 'collapsible' | 'destroyOnHidden'> & {
activeKey: React.Key[];
};
declare function useItems(items?: ItemType[], rawChildren?: React.ReactNode, props?: Props): React.ReactElement<CollapsePanelProps>[];
export default useItems;
@@ -0,0 +1,164 @@
import _extends from "@babel/runtime/helpers/esm/extends";
import toArray from "@rc-component/util/es/Children/toArray";
import React from 'react';
import CollapsePanel from "../Panel";
import clsx from 'clsx';
function mergeSemantic(src, tgt, mergeFn) {
if (!src || !tgt) {
return src || tgt;
}
const keys = Array.from(new Set([...Object.keys(src), ...Object.keys(tgt)]));
const result = {};
keys.forEach(key => {
result[key] = mergeFn(src[key], tgt[key]);
});
return result;
}
function mergeSemanticClassNames(src, tgt) {
return mergeSemantic(src, tgt, (a, b) => clsx(a, b));
}
function mergeSemanticStyles(src, tgt) {
return mergeSemantic(src, tgt, (a, b) => ({
...a,
...b
}));
}
const convertItemsToNodes = (items, props) => {
const {
prefixCls,
accordion,
collapsible,
destroyOnHidden,
onItemClick,
activeKey,
openMotion,
expandIcon,
classNames: collapseClassNames,
styles: collapseStyles
} = props;
return items.map((item, index) => {
const {
children,
label,
key: rawKey,
collapsible: rawCollapsible,
onItemClick: rawOnItemClick,
destroyOnHidden: rawDestroyOnHidden,
classNames,
styles,
...restProps
} = item;
// You may be puzzled why you want to convert them all into strings, me too.
// Maybe: https://github.com/react-component/collapse/blob/aac303a8b6ff30e35060b4f8fecde6f4556fcbe2/src/Collapse.tsx#L15
const key = String(rawKey ?? index);
const mergeCollapsible = rawCollapsible ?? collapsible;
const mergedDestroyOnHidden = rawDestroyOnHidden ?? destroyOnHidden;
const handleItemClick = value => {
if (mergeCollapsible === 'disabled') {
return;
}
onItemClick(value);
rawOnItemClick?.(value);
};
let isActive = false;
if (accordion) {
isActive = activeKey[0] === key;
} else {
isActive = activeKey.indexOf(key) > -1;
}
return /*#__PURE__*/React.createElement(CollapsePanel, _extends({}, restProps, {
classNames: mergeSemanticClassNames(collapseClassNames, classNames),
styles: mergeSemanticStyles(collapseStyles, styles),
prefixCls: prefixCls,
key: key,
panelKey: key,
isActive: isActive,
accordion: accordion,
openMotion: openMotion,
expandIcon: expandIcon,
header: label,
collapsible: mergeCollapsible,
onItemClick: handleItemClick,
destroyOnHidden: mergedDestroyOnHidden
}), children);
});
};
/**
* @deprecated The next major version will be removed
*/
const getNewChild = (child, index, props) => {
if (!child) {
return null;
}
const {
prefixCls,
accordion,
collapsible,
destroyOnHidden,
onItemClick,
activeKey,
openMotion,
expandIcon,
classNames: collapseClassNames,
styles
} = props;
const key = child.key || String(index);
const {
header,
headerClass,
destroyOnHidden: childDestroyOnHidden,
collapsible: childCollapsible,
onItemClick: childOnItemClick
} = child.props;
let isActive = false;
if (accordion) {
isActive = activeKey[0] === key;
} else {
isActive = activeKey.indexOf(key) > -1;
}
const mergeCollapsible = childCollapsible ?? collapsible;
const handleItemClick = value => {
if (mergeCollapsible === 'disabled') {
return;
}
onItemClick(value);
childOnItemClick?.(value);
};
const childProps = {
key,
panelKey: key,
header,
headerClass,
classNames: collapseClassNames,
styles,
isActive,
prefixCls,
destroyOnHidden: childDestroyOnHidden ?? destroyOnHidden,
openMotion,
accordion,
children: child.props.children,
onItemClick: handleItemClick,
expandIcon,
collapsible: mergeCollapsible
};
// https://github.com/ant-design/ant-design/issues/20479
if (typeof child.type === 'string') {
return child;
}
Object.keys(childProps).forEach(propName => {
if (typeof childProps[propName] === 'undefined') {
delete childProps[propName];
}
});
return /*#__PURE__*/React.cloneElement(child, childProps);
};
function useItems(items, rawChildren, props) {
if (Array.isArray(items)) {
return convertItemsToNodes(items, props);
}
return toArray(rawChildren).map((child, index) => getNewChild(child, index, props));
}
export default useItems;
+8
View File
@@ -0,0 +1,8 @@
/// <reference types="react" />
import Collapse from './Collapse';
export type { CollapsePanelProps, CollapseProps } from './interface';
export default Collapse;
/**
* @deprecated use `items` instead, will be removed in `v4.0.0`
*/
export declare const Panel: import("react").ForwardRefExoticComponent<import("./interface").CollapsePanelProps & import("react").RefAttributes<HTMLDivElement>>;
+9
View File
@@ -0,0 +1,9 @@
import Collapse from "./Collapse";
export default Collapse;
/**
* @deprecated use `items` instead, will be removed in `v4.0.0`
*/
export const {
Panel
} = Collapse;
+53
View File
@@ -0,0 +1,53 @@
import type { CSSMotionProps } from '@rc-component/motion';
import type * as React from 'react';
export type CollapsibleType = 'header' | 'icon' | 'disabled';
export interface ItemType extends Omit<CollapsePanelProps, 'header' | 'prefixCls' | 'panelKey' | 'isActive' | 'accordion' | 'openMotion' | 'expandIcon'> {
key?: CollapsePanelProps['panelKey'];
label?: CollapsePanelProps['header'];
ref?: React.RefObject<HTMLDivElement>;
}
export interface CollapseProps {
prefixCls?: string;
activeKey?: React.Key | React.Key[];
defaultActiveKey?: React.Key | React.Key[];
openMotion?: CSSMotionProps;
onChange?: (key: React.Key[]) => void;
accordion?: boolean;
className?: string;
style?: object;
destroyOnHidden?: boolean;
expandIcon?: (props: object) => React.ReactNode;
collapsible?: CollapsibleType;
children?: React.ReactNode;
/**
* Collapse items content
* @since 3.6.0
*/
items?: ItemType[];
classNames?: Partial<Record<SemanticName, string>>;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
}
export type SemanticName = 'header' | 'title' | 'body' | 'icon';
export interface CollapsePanelProps extends React.DOMAttributes<HTMLDivElement> {
id?: string;
header?: React.ReactNode;
prefixCls?: string;
headerClass?: string;
showArrow?: boolean;
className?: string;
classNames?: Partial<Record<SemanticName, string>>;
style?: object;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
isActive?: boolean;
openMotion?: CSSMotionProps;
destroyOnHidden?: boolean;
accordion?: boolean;
forceRender?: boolean;
extra?: React.ReactNode;
onItemClick?: (panelKey: React.Key) => void;
expandIcon?: (props: object) => React.ReactNode;
panelKey?: React.Key;
role?: string;
collapsible?: CollapsibleType;
children?: React.ReactNode;
}
+1
View File
@@ -0,0 +1 @@
export {};