mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 09:26:06 +08:00
feat: bump rc-collapse
version (#27790)
* refactor: RM rc-animate * put rc-animate back * clean up * chore: Update snasphot * feat: suport collapsible and deprecated disabled of Panel * docs: remove disabled of Panel * chore: bump rc-collapse to 3.1.0 * chore: update deprecated info * clean up * chore: update demo and remove rc-animate * chore: update snapshot Co-authored-by: Kermit <kermitlx@outlook.com>
This commit is contained in:
parent
7bea2380c5
commit
3923288275
@ -1,11 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import RcCollapse from 'rc-collapse';
|
||||
import { CSSMotionProps } from 'rc-motion';
|
||||
import classNames from 'classnames';
|
||||
import RightOutlined from '@ant-design/icons/RightOutlined';
|
||||
|
||||
import CollapsePanel from './CollapsePanel';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import omit from 'omit.js';
|
||||
import CollapsePanel, { CollapsibleType } from './CollapsePanel';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import animation from './openAnimation';
|
||||
import collapseMotion from '../_util/motion';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
|
||||
export type ExpandIconPosition = 'left' | 'right' | undefined;
|
||||
@ -24,6 +27,7 @@ export interface CollapseProps {
|
||||
expandIcon?: (panelProps: PanelProps) => React.ReactNode;
|
||||
expandIconPosition?: ExpandIconPosition;
|
||||
ghost?: boolean;
|
||||
collapsible?: CollapsibleType;
|
||||
}
|
||||
|
||||
interface PanelProps {
|
||||
@ -33,8 +37,10 @@ interface PanelProps {
|
||||
style?: React.CSSProperties;
|
||||
showArrow?: boolean;
|
||||
forceRender?: boolean;
|
||||
/** @deprecated Use `collapsible="disabled"` instead */
|
||||
disabled?: boolean;
|
||||
extra?: React.ReactNode;
|
||||
collapsible?: CollapsibleType;
|
||||
}
|
||||
|
||||
interface CollapseInterface extends React.FC<CollapseProps> {
|
||||
@ -77,16 +83,39 @@ const Collapse: CollapseInterface = props => {
|
||||
},
|
||||
className,
|
||||
);
|
||||
const openAnimation = { ...animation, appear() {} };
|
||||
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 = {
|
||||
...omit(child.props, 'disabled'),
|
||||
key,
|
||||
collapsible: collapsible ?? (disabled ? 'disabled' : undefined),
|
||||
};
|
||||
return cloneElement(child, childProps);
|
||||
}
|
||||
return child;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<RcCollapse
|
||||
openAnimation={openAnimation}
|
||||
openMotion={openMotion}
|
||||
{...props}
|
||||
expandIcon={(panelProps: PanelProps) => renderExpandIcon(panelProps)}
|
||||
prefixCls={prefixCls}
|
||||
className={collapseClassName}
|
||||
/>
|
||||
>
|
||||
{getItems()}
|
||||
</RcCollapse>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,10 +2,14 @@ import * as React from 'react';
|
||||
import RcCollapse from 'rc-collapse';
|
||||
import classNames from 'classnames';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
|
||||
export type CollapsibleType = 'header' | 'disabled';
|
||||
|
||||
export interface CollapsePanelProps {
|
||||
key: string | number;
|
||||
header: React.ReactNode;
|
||||
/** @deprecated Use `collapsible="disabled"` instead */
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
@ -14,9 +18,16 @@ export interface CollapsePanelProps {
|
||||
forceRender?: boolean;
|
||||
id?: string;
|
||||
extra?: React.ReactNode;
|
||||
collapsible: CollapsibleType;
|
||||
}
|
||||
|
||||
const CollapsePanel: React.FC<CollapsePanelProps> = props => {
|
||||
devWarning(
|
||||
!('disabled' in props),
|
||||
'Collapse.Panel',
|
||||
'`disabled` is deprecated. Please use `collapsible="disabled"` instead.',
|
||||
);
|
||||
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, className = '', showArrow = true } = props;
|
||||
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
|
||||
|
@ -1,7 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Collapse rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<div
|
||||
class="ant-collapse ant-collapse-icon-position-right ant-collapse-rtl"
|
||||
/>
|
||||
`;
|
@ -184,13 +184,13 @@ exports[`renders ./components/collapse/demo/basic.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-collapse-item ant-collapse-item-disabled"
|
||||
class="ant-collapse-item"
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
class="ant-collapse-header"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
@ -331,6 +331,112 @@ exports[`renders ./components/collapse/demo/borderless.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/collapse/demo/collapsible.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<div
|
||||
class="ant-collapse ant-collapse-icon-position-left"
|
||||
>
|
||||
<div
|
||||
class="ant-collapse-item ant-collapse-item-active"
|
||||
>
|
||||
<div
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header ant-collapse-header-collapsible-only"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-collapse-arrow"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
style="-ms-transform:rotate(90deg);transform:rotate(90deg)"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-collapse-header-text"
|
||||
>
|
||||
This panel can only be collapsed by clicking text
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-collapse-content ant-collapse-content-active"
|
||||
>
|
||||
<div
|
||||
class="ant-collapse-content-box"
|
||||
>
|
||||
<p>
|
||||
|
||||
A dog is a type of domesticated animal.
|
||||
Known for its loyalty and faithfulness,
|
||||
it can be found as a welcome guest in many households across the world.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<div
|
||||
class="ant-collapse ant-collapse-icon-position-left"
|
||||
>
|
||||
<div
|
||||
class="ant-collapse-item ant-collapse-item-disabled"
|
||||
>
|
||||
<div
|
||||
aria-expanded="false"
|
||||
class="ant-collapse-header"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-collapse-arrow"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
This panel can't be collapsed
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/collapse/demo/custom.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-collapse ant-collapse-borderless ant-collapse-icon-position-left site-collapse-custom-collapse"
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Collapse could override default openAnimation 1`] = `
|
||||
exports[`Collapse could override default openMotion 1`] = `
|
||||
<div
|
||||
class="ant-collapse ant-collapse-icon-position-left"
|
||||
>
|
||||
|
@ -1,26 +0,0 @@
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import Collapse from '..';
|
||||
import openAnimation from '../openAnimation';
|
||||
|
||||
describe('Collapse', () => {
|
||||
mountTest(Collapse);
|
||||
rtlTest(Collapse);
|
||||
});
|
||||
|
||||
describe('openAnimation', () => {
|
||||
it('should support openAnimation', () => {
|
||||
const done = jest.fn();
|
||||
const domNode = document.createElement('div');
|
||||
expect(typeof openAnimation.enter).toBe('function');
|
||||
expect(typeof openAnimation.leave).toBe('function');
|
||||
expect(typeof openAnimation.appear).toBe('function');
|
||||
const appear = openAnimation.appear(domNode, done);
|
||||
const enter = openAnimation.enter(domNode, done);
|
||||
const leave = openAnimation.leave(domNode, done);
|
||||
expect(typeof appear.stop).toBe('function');
|
||||
expect(typeof enter.stop).toBe('function');
|
||||
expect(typeof leave.stop).toBe('function');
|
||||
expect(done).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -1,11 +1,22 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import { resetWarned } from '../../_util/devWarning';
|
||||
|
||||
describe('Collapse', () => {
|
||||
// eslint-disable-next-line global-require
|
||||
const Collapse = require('..').default;
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
afterEach(() => {
|
||||
errorSpy.mockReset();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should support remove expandIcon', () => {
|
||||
const wrapper = mount(
|
||||
<Collapse expandIcon={() => null}>
|
||||
@ -57,9 +68,9 @@ describe('Collapse', () => {
|
||||
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(true);
|
||||
});
|
||||
|
||||
it('could override default openAnimation', () => {
|
||||
it('could override default openMotion', () => {
|
||||
const wrapper = mount(
|
||||
<Collapse openAnimation={{}}>
|
||||
<Collapse openMotion={{}}>
|
||||
<Collapse.Panel header="This is panel header 1" key="1">
|
||||
content
|
||||
</Collapse.Panel>
|
||||
@ -68,4 +79,26 @@ describe('Collapse', () => {
|
||||
wrapper.find('.ant-collapse-header').at(0).simulate('click');
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should trigger warning and keep compatibility when using disabled in Panel', () => {
|
||||
resetWarned();
|
||||
const wrapper = mount(
|
||||
<Collapse>
|
||||
<Collapse.Panel disabled header="This is panel header 1" key="1">
|
||||
content
|
||||
</Collapse.Panel>
|
||||
</Collapse>,
|
||||
);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Collapse.Panel] `disabled` is deprecated. Please use `collapsible="disabled"` instead.',
|
||||
);
|
||||
|
||||
expect(wrapper.find('.ant-collapse-header-text').exists()).toBeFalsy();
|
||||
|
||||
expect(wrapper.find('.ant-collapse-item-disabled').length).toBe(1);
|
||||
|
||||
wrapper.find('.ant-collapse-header').simulate('click');
|
||||
expect(wrapper.find('.ant-collapse-item-active').length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
@ -36,7 +36,7 @@ ReactDOM.render(
|
||||
<Panel header="This is panel header 2" key="2">
|
||||
<p>{text}</p>
|
||||
</Panel>
|
||||
<Panel header="This is panel header 3" key="3" disabled>
|
||||
<Panel header="This is panel header 3" key="3">
|
||||
<p>{text}</p>
|
||||
</Panel>
|
||||
</Collapse>,
|
||||
|
51
components/collapse/demo/collapsible.md
Normal file
51
components/collapse/demo/collapsible.md
Normal file
@ -0,0 +1,51 @@
|
||||
---
|
||||
order: 7
|
||||
title:
|
||||
zh-CN: 可折叠触发区域
|
||||
en-US: Collapsible
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
通过 `collapsible` 属性,可以设置面板的可折叠触发区域。
|
||||
|
||||
## en-US
|
||||
|
||||
Specify the trigger area of collapsible by `collapsible`.
|
||||
|
||||
```jsx
|
||||
import { Collapse, Space } from 'antd';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
const text = `
|
||||
A dog is a type of domesticated animal.
|
||||
Known for its loyalty and faithfulness,
|
||||
it can be found as a welcome guest in many households across the world.
|
||||
`;
|
||||
|
||||
ReactDOM.render(
|
||||
<Space direction="vertical">
|
||||
<Collapse collapsible="header" defaultActiveKey={['1']}>
|
||||
<Panel header="This panel can only be collapsed by clicking text" key="1">
|
||||
<p>{text}</p>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
<Collapse collapsible="disabled">
|
||||
<Panel header="This panel can't be collapsed" key="1">
|
||||
<p>{text}</p>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</Space>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
<style>
|
||||
[data-theme="compact"] p, p {
|
||||
margin: 0;
|
||||
}
|
||||
#components-collapse-demo-collapsible .ant-space {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -22,6 +22,7 @@ A content area which can be collapsed and expanded.
|
||||
| accordion | If true, Collapse renders as Accordion | boolean | false | |
|
||||
| activeKey | Key of the active panel | string\[] \| string <br/> number\[] \| number | No default value. In `accordion` mode, it's the key of the first panel | |
|
||||
| bordered | Toggles rendering of the border around the collapse block | boolean | true | |
|
||||
| collapsible | Specify whether the panels of children be collapsible or the trigger area of collapsible | `header` \| `disabled` | - | 4.9.0 |
|
||||
| defaultActiveKey | Key of the initial active panel | string\[] \| string <br/> number\[] \| number | - | |
|
||||
| destroyInactivePanel | Destroy Inactive Panel | boolean | false | |
|
||||
| expandIcon | Allow to customize collapse icon | (panelProps) => ReactNode | - | |
|
||||
@ -33,7 +34,7 @@ A content area which can be collapsed and expanded.
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| disabled | If true, panel cannot be opened or closed | boolean | false | |
|
||||
| collapsible | Specify whether the panel be collapsible or the trigger area of collapsible | `header` \| `disabled` | - | 4.9.0 |
|
||||
| extra | The extra element in the corner | ReactNode | - | |
|
||||
| forceRender | Forced render of content on panel, instead of lazy rending after clicking on header | boolean | false | |
|
||||
| header | Title of the panel | ReactNode | - | |
|
||||
|
@ -23,6 +23,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/IxH16B9RD/Collapse.svg
|
||||
| accordion | 手风琴模式 | boolean | false | |
|
||||
| activeKey | 当前激活 tab 面板的 key | string\[] \| string <br/> number\[] \| number | 默认无,accordion 模式下默认第一个元素 | |
|
||||
| bordered | 带边框风格的折叠面板 | boolean | true | |
|
||||
| collapsible | 所有子面板是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 4.9.0 |
|
||||
| defaultActiveKey | 初始化选中面板的 key | string\[] \| string<br/> number\[] \| number | - | |
|
||||
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | false | |
|
||||
| expandIcon | 自定义切换图标 | (panelProps) => ReactNode | - | |
|
||||
@ -34,7 +35,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/IxH16B9RD/Collapse.svg
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false | |
|
||||
| collapsible | 是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 4.9.0 |
|
||||
| extra | 自定义渲染每个面板右上角的内容 | ReactNode | - | |
|
||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
||||
| header | 面板头内容 | ReactNode | - | |
|
||||
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Deprecated. We should replace the animation with pure react motion instead of modify style directly.
|
||||
* If you are creating new component with animation, please use `./motion`.
|
||||
*/
|
||||
import cssAnimation from '@ant-design/css-animation';
|
||||
import raf from 'rc-util/lib/raf';
|
||||
|
||||
function animate(node: HTMLElement, show: boolean, done: () => void) {
|
||||
let height: number;
|
||||
let requestAnimationFrameId: number;
|
||||
return cssAnimation(node, 'ant-motion-collapse-legacy', {
|
||||
start() {
|
||||
if (!show) {
|
||||
node.style.height = `${node.offsetHeight}px`;
|
||||
node.style.opacity = '1';
|
||||
} else {
|
||||
height = node.offsetHeight;
|
||||
node.style.height = '0px';
|
||||
node.style.opacity = '0';
|
||||
}
|
||||
},
|
||||
active() {
|
||||
requestAnimationFrameId = raf(() => {
|
||||
node.style.height = `${show ? height : 0}px`;
|
||||
node.style.opacity = show ? '1' : '0';
|
||||
});
|
||||
},
|
||||
end() {
|
||||
if (requestAnimationFrameId) {
|
||||
raf.cancel(requestAnimationFrameId);
|
||||
}
|
||||
node.style.height = '';
|
||||
node.style.opacity = '';
|
||||
done();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const animation = {
|
||||
enter(node: HTMLElement, done: () => void) {
|
||||
return animate(node, true, done);
|
||||
},
|
||||
leave(node: HTMLElement, done: () => void) {
|
||||
return animate(node, false, done);
|
||||
},
|
||||
appear(node: HTMLElement, done: () => void) {
|
||||
return animate(node, true, done);
|
||||
},
|
||||
};
|
||||
|
||||
export default animation;
|
@ -54,6 +54,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.@{collapse-prefix-cls}-header-collapsible-only {
|
||||
cursor: default;
|
||||
.@{collapse-prefix-cls}-header-text {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{collapse-prefix-cls}-no-arrow {
|
||||
> .@{collapse-prefix-cls}-header {
|
||||
padding-left: 12px;
|
||||
@ -76,10 +83,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-anim-active {
|
||||
transition: height 0.2s @ease-out;
|
||||
}
|
||||
|
||||
&-content {
|
||||
overflow: hidden;
|
||||
color: @text-color;
|
||||
@ -90,7 +93,7 @@
|
||||
padding: @collapse-content-padding;
|
||||
}
|
||||
|
||||
&-inactive {
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -117,10 +117,9 @@
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.25.3",
|
||||
"omit.js": "^2.0.2",
|
||||
"rc-animate": "~3.1.0",
|
||||
"rc-cascader": "~1.4.0",
|
||||
"rc-checkbox": "~2.3.0",
|
||||
"rc-collapse": "~2.0.0",
|
||||
"rc-collapse": "~3.1.0",
|
||||
"rc-dialog": "~8.4.0",
|
||||
"rc-drawer": "~4.1.0",
|
||||
"rc-dropdown": "~3.2.0",
|
||||
|
Loading…
Reference in New Issue
Block a user