-
Notifications
You must be signed in to change notification settings - Fork 0
/
App.tsx
88 lines (80 loc) · 3.04 KB
/
App.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import React, { CSSProperties, useLayoutEffect, useMemo, useRef, useState } from "react";
import styles from "./App.module.scss";
import cx from "clsx";
function App() {
const contentRef = useRef<HTMLDivElement>(null);
const { isExpanded, toggleExpand, animationProps, animationStyles } =
useExpandAnimation(contentRef);
return (
<div>
<button type="button" onClick={toggleExpand}>
{isExpanded ? 'Collapse' : 'Expand'} animation
</button>
<div
ref={contentRef}
className={cx(styles.content)}
style={{
...animationStyles,
}}
{...animationProps}
>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt modi
quis pariatur sapiente at totam ipsam, saepe cupiditate ut eveniet rem
obcaecati nesciunt quaerat itaque mollitia? Eligendi, veniam soluta
voluptas voluptate aut ad nam explicabo eius minima necessitatibus
assumenda reiciendis perspiciatis nihil provident ab adipisci quae
doloremque eveniet? Autem aliquid placeat, quia eligendi eum corporis
totam laborum ducimus doloribus accusantium id nulla facere qui. Autem
suscipit est modi, rem saepe quas fugiat dignissimos quod voluptatum non
velit dolorem, expedita, voluptatibus omnis ab obcaecati. Maiores
ducimus laboriosam vel qui, voluptates tempore neque. Repellat minima
nostrum nihil ratione voluptates magni tempora asperiores rem! Id
excepturi eos illo esse necessitatibus sed enim, reprehenderit maxime
ipsa facilis vitae eveniet ratione, doloremque aperiam modi pariatur
magni. Excepturi nulla id, facilis nemo fugit doloremque amet eligendi
beatae sunt voluptatem cupiditate.
</div>
<div style={{ backgroundColor: 'darkkhaki'}}>Some other content</div>
</div>
);
}
export default App;
function useExpandAnimation(contentRef: React.RefObject<HTMLElement>) {
const [isExpanded, setIsExpanded] = useState(false);
const [contentHeight, setContentHeight] = useState(0);
useLayoutEffect(() => {
if (isExpanded && contentHeight === 0 && contentRef.current) {
setContentHeight(contentRef.current.getBoundingClientRect().height);
setIsExpanded(false);
requestAnimationFrame(() => {
setIsExpanded(true);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isExpanded]);
return useMemo(
() => ({
isExpanded,
toggleExpand: () => {
if (isExpanded) {
setContentHeight(contentRef.current!.getBoundingClientRect().height);
}
requestAnimationFrame(() => setIsExpanded((x) => !x));
},
animationProps: {
onTransitionEnd: () => setContentHeight(0),
},
animationStyles: {
height:
isExpanded && contentHeight > 0
? contentHeight
: isExpanded
? "auto"
: 0,
overflow: "hidden",
transition: 'height 300ms',
} as CSSProperties,
}),
[contentHeight, contentRef, isExpanded]
);
}