forked from blossom-educational/react-native-collapsible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCollapsible.js
129 lines (116 loc) · 3.37 KB
/
Collapsible.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* @providesModule Collapsible
* @flow
*/
'use strict';
var React = require('react-native');
var {
Animated,
Easing,
View,
} = React;
var ANIMATED_EASING_PREFIXES = ['easeInOut', 'easeOut', 'easeIn'];
// For some reason 0 heights won't hide overflow in RN 0.12+
var ALMOST_ZERO = 0.00000001;
var Collapsible = React.createClass({
propTypes: {
align: React.PropTypes.oneOf(['top', 'center', 'bottom']),
collapsed: React.PropTypes.bool,
duration: React.PropTypes.number,
easing: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.func
]),
},
getDefaultProps() : Object {
return {
align: 'top',
collapsed: true,
duration: 300,
easing: 'easeOutCubic',
};
},
componentWillReceiveProps(props : Object) {
if(props.collapsed !== this.props.collapsed) {
this._toggleCollapsed(props.collapsed);
}
},
getInitialState() : Object {
return {
height: new Animated.Value(ALMOST_ZERO),
contentHeight: 0,
animating: false,
};
},
_toggleCollapsed(collapsed : bool) {
var height = collapsed ? ALMOST_ZERO : this.state.contentHeight;
var { easing, duration } = this.props;
if(typeof easing === 'string') {
var prefix, found = false;
for (var i = 0; i < ANIMATED_EASING_PREFIXES.length; i++) {
prefix = ANIMATED_EASING_PREFIXES[i];
if(easing.substr(0, prefix.length) === prefix) {
easing = easing.substr(prefix.length, 1).toLowerCase() + easing.substr(prefix.length + 1);
prefix = prefix.substr(4, 1).toLowerCase() + prefix.substr(5);
easing = Easing[prefix](Easing[easing || 'ease']);
found = true;
break;
}
};
if(!found) {
easing = Easing[easing];
}
if(!easing) {
throw new Error('Invalid easing type "' + this.props.easing +'"');
}
}
if(this._animation) {
this._animation.stop();
}
this.setState({ animating: true });
this._animation = Animated.timing(this.state.height, {
toValue: height,
duration,
easing,
}).start(event => this.setState({ animating: true }));
},
_handleLayoutChange(event : Object) {
var contentHeight = event.nativeEvent.layout.height;
var height = this.props.collapsed ? ALMOST_ZERO : contentHeight
this.setState({
height: new Animated.Value(height),
contentHeight,
});
},
render() {
var { height, contentHeight } = this.state;
var style = {
overflow: 'hidden',
height: height
};
var contentStyle = {};
if(this.props.align === 'center') {
contentStyle.transform = [{
translateY: height.interpolate({
inputRange: [0, contentHeight],
outputRange: [contentHeight/-2, 0],
})
}];
} else if(this.props.align === 'bottom') {
contentStyle.transform = [{
translateY: height.interpolate({
inputRange: [0, contentHeight],
outputRange: [-contentHeight, 0],
})
}];
}
return (
<Animated.View style={style} pointerEvents={this.props.collapsed ? 'none' : 'auto'}>
<Animated.View style={contentStyle} onLayout={this.state.animating ? undefined : this._handleLayoutChange}>
{this.props.children}
</Animated.View>
</Animated.View>
);
}
});
module.exports = Collapsible;