/
Collapse.js
94 lines (78 loc) · 2.66 KB
/
Collapse.js
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
89
90
91
92
93
94
/* Fork of https://github.com/nkbt/react-collapse
*******************************************************************************/
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { Motion, spring } from 'react-motion';
class Collapse extends PureComponent {
static propTypes = {
isOpened: PropTypes.bool.isRequired,
springConfig: PropTypes.object.isRequired,
children: PropTypes.node.isRequired
};
state = {
from: 0,
to: 0
};
componentDidMount () {
const { isOpened } = this.props;
// isOpened will be true on mount if window.innerWidth > 991px
if (isOpened) {
const collapseContentHeight = this.CollapseContent.clientHeight;
this.setState({
from: collapseContentHeight,
to: collapseContentHeight
});
}
}
componentDidUpdate () {
const { isOpened } = this.props;
const collapseHeight = this.Collapse.clientHeight;
const collapseContentHeight = isOpened ? this.CollapseContent.clientHeight : 0;
if (collapseHeight !== collapseContentHeight) {
// Only set state in componentDidUpdate in a PureComponent or use shouldComponentUpdate
this.setState({
from: collapseHeight,
to: collapseContentHeight
});
}
}
// Motion passes an interpolatedStyle object to its child component
// The properties are the same as the style object passed to Motion
motionChildren = (interpolatedStyle) => {
const { height } = interpolatedStyle;
const { children, isOpened, springConfig, ...rest } = this.props;
const collapseProps = {
id: 'Collapse',
ref: (Collapse) => { this.Collapse = Collapse; },
style: { overflow: 'hidden', height: Math.max(0, height) }
};
const collapseContentProps = {
id: 'CollapseContent',
ref: (CollapseContent) => { this.CollapseContent = CollapseContent; }
};
return (
<div {...collapseProps} {...rest}>
<div {...collapseContentProps}>
{children}
</div>
</div>
);
};
render () {
const { from, to } = this.state;
const { springConfig } = this.props;
// defaultStyle is the initial value for Motion to interpolate on mount
// style is the value to interpolate on subsequent re-renders
const motionProps = {
defaultStyle: { height: from },
style: { height: spring(to, { precision: 1, ...springConfig }) }
};
return (
// Motion's child component must be a function
<Motion {...motionProps}>
{this.motionChildren}
</Motion>
);
}
}
export default Collapse;