1
This commit is contained in:
+9
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
+6
@@ -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
@@ -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;
|
||||
+7
@@ -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;
|
||||
+164
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user