Skip to content

Commit ff26366

Browse files
committed
feat: 完善动画支持
1 parent ce3ba4c commit ff26366

File tree

3 files changed

+91
-27
lines changed

3 files changed

+91
-27
lines changed

assets/index.less

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@
3535

3636
& > &-item {
3737
border-top: @borderStyle;
38+
list-style-position: outside;
39+
interpolate-size: allow-keywords;
40+
overflow: hidden;
41+
42+
&::details-content {
43+
block-size: 0;
44+
transition: block-size 0.6s, content-visibility 0.6s;
45+
transition-behavior: allow-discrete;
46+
}
47+
48+
&[open]::details-content {
49+
block-size: auto;
50+
}
51+
3852
&:first-child {
3953
border-top: none;
4054
}

src/Collapse.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
4646
});
4747

4848
const onItemClick = (key: React.Key) =>
49-
// ? 为了解决https://github.com/facebook/react/issues/15486
49+
// ? 用于解决react状态与details[open]状态不一致的问题
50+
// ? 具体参考issue https://github.com/facebook/react/issues/15486
5051
React.startTransition(() => {
5152
setActiveKey(() => {
5253
if (accordion) {

src/Panel.tsx

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import classNames from 'classnames';
22
import CSSMotion from 'rc-motion';
33
import KeyCode from '@rc-component/util/lib/KeyCode';
4-
import React from 'react';
4+
import React, { useMemo } from 'react';
55
import type { CollapsePanelProps } from './interface';
66
import PanelContent from './PanelContent';
77

@@ -32,6 +32,15 @@ const CollapsePanel = React.forwardRef<HTMLDetailsElement, CollapsePanelProps>((
3232

3333
const ifExtraExist = extra !== null && extra !== undefined && typeof extra !== 'boolean';
3434

35+
// ? 用于判断浏览器是否支持::details-content 否则使用CSSMotion
36+
const supportsDetailsContentSelector = useMemo(
37+
() =>
38+
typeof document !== 'undefined' && typeof document.createElement === 'function'
39+
? CSS.supports('selector(details::details-content)')
40+
: false,
41+
[],
42+
);
43+
3544
const collapsibleProps = {
3645
onClick: (e: React.MouseEvent) => {
3746
onItemClick?.(panelKey);
@@ -68,6 +77,8 @@ const CollapsePanel = React.forwardRef<HTMLDetailsElement, CollapsePanelProps>((
6877
[`${prefixCls}-item-disabled`]: disabled,
6978
},
7079
className,
80+
// ? 修改为details实现后动画是作用在details元素上 需要将motionName设置在details上
81+
supportsDetailsContentSelector && openMotion?.motionName,
7182
);
7283

7384
const headerClassName = classNames(
@@ -87,6 +98,68 @@ const CollapsePanel = React.forwardRef<HTMLDetailsElement, CollapsePanelProps>((
8798
};
8899

89100
// ======================== Render ========================
101+
102+
const leavedClassName = `${prefixCls}-panel-hidden`;
103+
const createPanelContent = (
104+
props: Partial<{
105+
className: string;
106+
style: React.CSSProperties;
107+
motionRef: (node: HTMLDivElement) => void;
108+
}>,
109+
) => {
110+
const { className, style, motionRef } = props;
111+
112+
return (
113+
<PanelContent
114+
ref={motionRef}
115+
prefixCls={prefixCls}
116+
className={className}
117+
classNames={customizeClassNames}
118+
style={style}
119+
styles={styles}
120+
isActive={isActive}
121+
forceRender={forceRender}
122+
role={accordion ? 'tabpanel' : void 0}
123+
>
124+
{children}
125+
</PanelContent>
126+
);
127+
};
128+
let detailsChildren = (
129+
<CSSMotion
130+
visible={isActive}
131+
leavedClassName={leavedClassName}
132+
{...openMotion}
133+
forceRender={forceRender}
134+
removeOnLeave={destroyInactivePanel}
135+
>
136+
{({ className, style }, motionRef) =>
137+
createPanelContent({
138+
className,
139+
style,
140+
motionRef,
141+
})
142+
}
143+
</CSSMotion>
144+
);
145+
146+
// ? 模拟CSSMotion子元素生命周期管理
147+
if (supportsDetailsContentSelector) {
148+
if (isActive) {
149+
detailsChildren = createPanelContent({});
150+
} else if (!destroyInactivePanel && leavedClassName) {
151+
detailsChildren = createPanelContent({
152+
className: leavedClassName,
153+
});
154+
} else if (forceRender || (!destroyInactivePanel && !leavedClassName)) {
155+
detailsChildren = createPanelContent({
156+
style: { display: 'none' },
157+
});
158+
} else {
159+
detailsChildren = null;
160+
}
161+
}
162+
90163
return (
91164
<details {...resetProps} ref={ref} className={collapsePanelClassNames} open={isActive}>
92165
<summary {...headerProps}>
@@ -100,31 +173,7 @@ const CollapsePanel = React.forwardRef<HTMLDetailsElement, CollapsePanelProps>((
100173
</span>
101174
{ifExtraExist && <div className={`${prefixCls}-extra`}>{extra}</div>}
102175
</summary>
103-
<CSSMotion
104-
visible={isActive}
105-
leavedClassName={`${prefixCls}-panel-hidden`}
106-
{...openMotion}
107-
forceRender={forceRender}
108-
removeOnLeave={destroyInactivePanel}
109-
>
110-
{({ className: motionClassName, style: motionStyle }, motionRef) => {
111-
return (
112-
<PanelContent
113-
ref={motionRef}
114-
prefixCls={prefixCls}
115-
className={motionClassName}
116-
classNames={customizeClassNames}
117-
style={motionStyle}
118-
styles={styles}
119-
isActive={isActive}
120-
forceRender={forceRender}
121-
role={accordion ? 'tabpanel' : void 0}
122-
>
123-
{children}
124-
</PanelContent>
125-
);
126-
}}
127-
</CSSMotion>
176+
{detailsChildren}
128177
</details>
129178
);
130179
});

0 commit comments

Comments
 (0)