import * as React from 'react'; import RcCollapse from 'rc-collapse'; import type { CSSMotionProps } from 'rc-motion'; import classNames from 'classnames'; import RightOutlined from '@ant-design/icons/RightOutlined'; import toArray from 'rc-util/lib/Children/toArray'; import omit from 'rc-util/lib/omit'; import type { CollapsibleType } from './CollapsePanel'; import CollapsePanel from './CollapsePanel'; import { ConfigContext } from '../config-provider'; import collapseMotion from '../_util/motion'; import { cloneElement } from '../_util/reactNode'; import useStyle from './style'; export type ExpandIconPosition = 'left' | 'right' | undefined; export interface CollapseProps { activeKey?: Array | string | number; defaultActiveKey?: Array | string | number; /** 手风琴效果 */ accordion?: boolean; destroyInactivePanel?: boolean; onChange?: (key: string | string[]) => void; style?: React.CSSProperties; className?: string; bordered?: boolean; prefixCls?: string; expandIcon?: (panelProps: PanelProps) => React.ReactNode; expandIconPosition?: ExpandIconPosition; ghost?: boolean; collapsible?: CollapsibleType; children?: React.ReactNode; } interface PanelProps { isActive?: boolean; header?: React.ReactNode; className?: string; style?: React.CSSProperties; showArrow?: boolean; forceRender?: boolean; /** @deprecated Use `collapsible="disabled"` instead */ disabled?: boolean; extra?: React.ReactNode; collapsible?: CollapsibleType; } interface CollapseInterface extends React.FC { Panel: typeof CollapsePanel; } const Collapse: CollapseInterface = props => { const { getPrefixCls, direction } = React.useContext(ConfigContext); const { prefixCls: customizePrefixCls, className = '', bordered = true, ghost } = props; const prefixCls = getPrefixCls('collapse', customizePrefixCls); const [wrapSSR, hashId] = useStyle(prefixCls); const getIconPosition = () => { const { expandIconPosition } = props; if (expandIconPosition !== undefined) { return expandIconPosition; } return direction === 'rtl' ? 'right' : 'left'; }; const renderExpandIcon = (panelProps: PanelProps = {}) => { const { expandIcon } = props; const icon = ( expandIcon ? ( expandIcon(panelProps) ) : ( ) ) as React.ReactNode; return ( // Create additional div here to make arrow align to center of first line
{cloneElement(icon, () => ({ className: classNames((icon as any).props.className, `${prefixCls}-arrow`), }))}
); }; const iconPosition = getIconPosition(); const collapseClassName = classNames( { [`${prefixCls}-borderless`]: !bordered, [`${prefixCls}-icon-position-${iconPosition}`]: true, [`${prefixCls}-rtl`]: direction === 'rtl', [`${prefixCls}-ghost`]: !!ghost, }, className, hashId, ); const openMotion: CSSMotionProps = { ...collapseMotion, motionAppear: false, leavedClassName: `${prefixCls}-content-hidden`, }; const getItems = () => { const { children } = props; return toArray(children).map((child: React.ReactElement, index: number) => { if (child.props?.disabled) { const key = child.key || String(index); const { disabled, collapsible } = child.props; const childProps: CollapseProps & { key: React.Key } = { ...omit(child.props, ['disabled']), key, collapsible: collapsible ?? (disabled ? 'disabled' : undefined), }; return cloneElement(child, childProps); } return child; }); }; return wrapSSR( {getItems()} , ); }; Collapse.Panel = CollapsePanel; export default Collapse;