|
|
|
|
@ -1,5 +1,11 @@
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
import { useEffect, useRef, useState } from 'react';
|
|
|
|
|
import {
|
|
|
|
|
forwardRef,
|
|
|
|
|
useEffect,
|
|
|
|
|
useImperativeHandle,
|
|
|
|
|
useRef,
|
|
|
|
|
useState
|
|
|
|
|
} from 'react';
|
|
|
|
|
import './index.less';
|
|
|
|
|
|
|
|
|
|
interface TransitionWrapProps {
|
|
|
|
|
@ -7,50 +13,67 @@ interface TransitionWrapProps {
|
|
|
|
|
header?: React.ReactNode;
|
|
|
|
|
variant?: 'bordered' | 'filled';
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
ref?: any;
|
|
|
|
|
}
|
|
|
|
|
const TransitionWrapper: React.FC<TransitionWrapProps> = (props) => {
|
|
|
|
|
const { minHeight = 50, header, variant = 'bordered', children } = props;
|
|
|
|
|
const [isOpen, setIsOpen] = useState(true);
|
|
|
|
|
const [height, setHeight] = useState(0);
|
|
|
|
|
const contentRef = useRef(null);
|
|
|
|
|
const TransitionWrapper: React.FC<TransitionWrapProps> = forwardRef(
|
|
|
|
|
(props, ref) => {
|
|
|
|
|
const { minHeight = 50, header, variant = 'bordered', children } = props;
|
|
|
|
|
const [isOpen, setIsOpen] = useState(true);
|
|
|
|
|
const [height, setHeight] = useState(0);
|
|
|
|
|
const contentRef = useRef(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (isOpen) {
|
|
|
|
|
setHeight(contentRef?.current?.scrollHeight);
|
|
|
|
|
} else {
|
|
|
|
|
setHeight(0);
|
|
|
|
|
}
|
|
|
|
|
}, [isOpen]);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (isOpen) {
|
|
|
|
|
setHeight(contentRef?.current?.scrollHeight || 0);
|
|
|
|
|
} else {
|
|
|
|
|
setHeight(0);
|
|
|
|
|
}
|
|
|
|
|
}, [isOpen]);
|
|
|
|
|
|
|
|
|
|
const toggleOpen = () => {
|
|
|
|
|
setIsOpen(!isOpen);
|
|
|
|
|
};
|
|
|
|
|
const toggleOpen = () => {
|
|
|
|
|
setIsOpen(!isOpen);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={classNames('transition-wrapper', {
|
|
|
|
|
bordered: variant === 'bordered',
|
|
|
|
|
filled: variant === 'filled'
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
onClick={toggleOpen}
|
|
|
|
|
className="header"
|
|
|
|
|
style={{
|
|
|
|
|
height: minHeight
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{header}
|
|
|
|
|
</div>
|
|
|
|
|
const setHeightByContent = () => {
|
|
|
|
|
setHeight(contentRef?.current?.scrollHeight || 0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useImperativeHandle(ref, () => {
|
|
|
|
|
return {
|
|
|
|
|
setHeightByContent
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className="content-wrapper"
|
|
|
|
|
style={{ height: height }}
|
|
|
|
|
ref={contentRef}
|
|
|
|
|
className={classNames('transition-wrapper', {
|
|
|
|
|
bordered: variant === 'bordered',
|
|
|
|
|
filled: variant === 'filled'
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<div className="content">{children}</div>
|
|
|
|
|
<div
|
|
|
|
|
onClick={toggleOpen}
|
|
|
|
|
className="header"
|
|
|
|
|
style={{
|
|
|
|
|
// when content is closed, header should have minHeight
|
|
|
|
|
height: minHeight
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{header}
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
className="content-wrapper"
|
|
|
|
|
style={{
|
|
|
|
|
minHeight: isOpen ? height : 0,
|
|
|
|
|
height: isOpen ? 'auto' : 0
|
|
|
|
|
}}
|
|
|
|
|
ref={contentRef}
|
|
|
|
|
>
|
|
|
|
|
<div className="content">{children}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export default TransitionWrapper;
|
|
|
|
|
|