1
1
import _ from 'lodash' ;
2
- import PropTypes from 'prop-types' ;
3
- import React from 'react' ;
4
- import { StyleSheet , Animated , Easing , LayoutAnimation } from 'react-native' ;
2
+ import React , { PureComponent } from 'react' ;
3
+ import { StyleSheet , Animated , Easing , LayoutAnimation , StyleProp , ViewStyle , LayoutChangeEvent } from 'react-native' ;
5
4
import { Constants } from '../../helpers' ;
6
5
import { Colors } from '../../style' ;
7
- import { PureBaseComponent } from '../../commons' ;
8
- import View from '../view' ;
6
+ import View , { ViewProps } from '../view' ;
9
7
import TouchableOpacity from '../touchableOpacity' ;
10
- import Button from '../button' ;
8
+ import Button , { ButtonSize , ButtonProps } from '../button' ;
11
9
import Card from '../card' ;
10
+ import { asBaseComponent } from '../../commons/new' ;
12
11
13
12
const PEEP = 8 ;
14
13
const DURATION = 300 ;
15
14
const MARGIN_BOTTOM = 24 ;
16
15
const buttonStartValue = 0.8 ;
17
16
const icon = require ( './assets/arrow-down.png' ) ;
18
17
19
- /**
20
- * @description : Stack aggregator component
21
- * @modifiers : margin, padding
22
- * @example : https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/StackAggregatorScreen.js
23
- * @gif : https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/StackAggregator/StackAggregator.gif?raw=true
24
- */
25
- export default class StackAggregator extends PureBaseComponent {
26
- static displayName = 'StackAggregator' ;
27
-
28
- static propTypes = {
29
- /**
18
+ export type StackAggregatorProps = ViewProps & {
19
+ /**
30
20
* The initial state of the stack
31
21
*/
32
- collapsed : PropTypes . bool ,
22
+ collapsed : boolean ;
23
+ /**
24
+ * Component Children
25
+ */
26
+ children : JSX . Element | JSX . Element [ ]
33
27
/**
34
28
* The container style
35
29
*/
36
- containerStyle : PropTypes . oneOfType ( [ PropTypes . object , PropTypes . number , PropTypes . array ] ) ,
30
+ containerStyle ?: StyleProp < ViewStyle > ;
37
31
/**
38
32
* The content container style
39
33
*/
40
- contentContainerStyle : PropTypes . oneOfType ( [ PropTypes . object , PropTypes . number , PropTypes . array ] ) ,
34
+ contentContainerStyle ?: StyleProp < ViewStyle > ;
41
35
/**
42
36
* The items border radius
43
37
*/
44
- itemBorderRadius : PropTypes . number ,
38
+ itemBorderRadius ?: number ;
45
39
/**
46
40
* Props passed to the 'show less' button
47
41
*/
48
- buttonProps : PropTypes . object ,
42
+ buttonProps ?: ButtonProps ;
49
43
/**
50
44
* A callback for item press
51
45
*/
52
- onItemPress : PropTypes . func ,
46
+ onItemPress ?: ( index : number ) => void ;
53
47
/**
54
48
* A callback for collapse state will change (value is future collapsed state)
55
49
*/
56
- onCollapseWillChange : PropTypes . func ,
50
+ onCollapseWillChange ?: ( changed : boolean ) => void ;
57
51
/**
58
- * A callback for collapse state change (value is collapsed state)
59
- */
60
- onCollapseChanged : PropTypes . func ,
52
+ * A callback for collapse state change (value is collapsed state)
53
+ */
54
+ onCollapseChanged ?: ( changed : boolean ) => void ;
61
55
/**
62
56
* A setting that disables pressability on cards
63
57
*/
64
- disablePresses : PropTypes . boolean
65
- }
58
+ disablePresses ?: boolean ;
59
+ } ;
60
+
61
+
62
+ type State = {
63
+ collapsed : boolean ;
64
+ firstItemHeight ?: number ;
65
+ } ;
66
+
67
+ /**
68
+ * @description : Stack aggregator component
69
+ * @modifiers : margin, padding
70
+ * @example : https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/StackAggregatorScreen.js
71
+ */
72
+ class StackAggregator extends PureComponent < StackAggregatorProps , State > {
73
+ static displayName = 'StackAggregator' ;
74
+
75
+ animatedScale : Animated . Value ;
76
+ animatedOpacity : any ;
77
+ animatedContentOpacity : any ;
78
+ itemsCount = React . Children . count ( this . props . children ) ;
79
+ easeOut = Easing . bezier ( 0 , 0 , 0.58 , 1 ) ;
80
+ animatedScaleArray : Animated . Value [ ] ;
66
81
67
82
static defaultProps = {
68
83
disablePresses : false ,
69
84
collapsed : true ,
70
85
itemBorderRadius : 0
71
86
} ;
72
87
73
- constructor ( props ) {
88
+ constructor ( props : StackAggregatorProps ) {
74
89
super ( props ) ;
75
-
76
90
this . state = {
77
91
collapsed : props . collapsed ,
78
92
firstItemHeight : undefined
79
93
} ;
80
-
81
- this . itemsCount = React . Children . count ( props . children ) ;
82
- this . easeOut = Easing . bezier ( 0 , 0 , 0.58 , 1 ) ;
83
94
this . animatedScale = new Animated . Value ( this . state . collapsed ? buttonStartValue : 1 ) ;
84
95
this . animatedOpacity = new Animated . Value ( this . state . collapsed ? buttonStartValue : 1 ) ;
85
- this . animatedScaleArray = this . getAnimatedScales ( ) ;
86
96
this . animatedContentOpacity = new Animated . Value ( this . state . collapsed ? 0 : 1 ) ;
97
+ this . animatedScaleArray = this . getAnimatedScales ( ) ;
87
98
}
88
99
89
- componentDidUpdate ( _prevProps , prevState ) {
90
- if ( prevState . collapsed !== this . state . collapsed ) {
100
+ componentDidUpdate ( _prevProps : StackAggregatorProps , prevState : State ) {
101
+ if ( prevState . collapsed !== this . state ? .collapsed ) {
91
102
LayoutAnimation . configureNext ( LayoutAnimation . Presets . easeInEaseOut ) ;
92
103
}
93
104
}
94
105
95
- generateStyles ( ) {
96
- this . styles = createStyles ( this . getThemeProps ( ) ) ;
97
- }
98
-
99
- getAnimatedScales ( ) {
106
+ getAnimatedScales = ( ) : Animated . Value [ ] => {
100
107
return React . Children . map ( this . props . children , ( _item , index ) => {
101
108
return new Animated . Value ( this . getItemScale ( index ) ) ;
102
109
} ) ;
103
110
}
104
111
105
- getItemScale ( index ) {
112
+ getItemScale = ( index : number ) => {
106
113
if ( this . state . collapsed ) {
107
114
if ( index === this . itemsCount - 2 ) {
108
115
return 0.95 ;
@@ -116,12 +123,12 @@ export default class StackAggregator extends PureBaseComponent {
116
123
117
124
animate = async ( ) => {
118
125
return Promise . all ( [ this . animateValues ( ) , this . animateCards ( ) ] ) ;
119
- }
126
+ } ;
120
127
121
128
animateValues ( ) {
122
129
const { collapsed} = this . state ;
123
130
const newValue = collapsed ? buttonStartValue : 1 ;
124
- return new Promise ( ( resolve ) => {
131
+ return new Promise ( resolve => {
125
132
Animated . parallel ( [
126
133
Animated . timing ( this . animatedOpacity , {
127
134
duration : DURATION ,
@@ -144,13 +151,13 @@ export default class StackAggregator extends PureBaseComponent {
144
151
} ) ;
145
152
}
146
153
147
- animateCards ( ) {
154
+ animateCards ( ) {
148
155
const promises = [ ] ;
149
156
for ( let index = 0 ; index < this . itemsCount ; index ++ ) {
150
157
const newScale = this . getItemScale ( index ) ;
151
158
152
159
promises . push (
153
- new Promise ( ( resolve ) => {
160
+ new Promise ( resolve => {
154
161
Animated . timing ( this . animatedScaleArray [ index ] , {
155
162
toValue : Number ( newScale ) ,
156
163
easing : this . easeOut ,
@@ -173,7 +180,7 @@ export default class StackAggregator extends PureBaseComponent {
173
180
this . animate ( ) ;
174
181
}
175
182
} ) ;
176
- }
183
+ } ;
177
184
178
185
open = ( ) => {
179
186
this . setState ( { collapsed : false } , async ( ) => {
@@ -185,9 +192,9 @@ export default class StackAggregator extends PureBaseComponent {
185
192
this . animate ( ) ;
186
193
}
187
194
} ) ;
188
- }
195
+ } ;
189
196
190
- getTop ( index ) {
197
+ getTop ( index : number ) {
191
198
let start = 0 ;
192
199
193
200
if ( index === this . itemsCount - 2 ) {
@@ -200,7 +207,7 @@ export default class StackAggregator extends PureBaseComponent {
200
207
return start ;
201
208
}
202
209
203
- getStyle ( index ) {
210
+ getStyle ( index : number ) : StyleProp < ViewStyle > {
204
211
const { collapsed} = this . state ;
205
212
const top = this . getTop ( index ) ;
206
213
@@ -216,19 +223,19 @@ export default class StackAggregator extends PureBaseComponent {
216
223
} ;
217
224
}
218
225
219
- onLayout = event => {
226
+ onLayout = ( event : LayoutChangeEvent ) => {
220
227
const height = event . nativeEvent . layout . height ;
221
228
222
229
if ( height ) {
223
230
this . setState ( { firstItemHeight : height } ) ;
224
231
}
225
232
} ;
226
233
227
- onItemPress = index => {
234
+ onItemPress = ( index : number ) => {
228
235
_ . invoke ( this . props , 'onItemPress' , index ) ;
229
236
} ;
230
237
231
- renderItem = ( item , index ) => {
238
+ renderItem = ( item : JSX . Element | JSX . Element [ ] , index : number ) => {
232
239
const { contentContainerStyle, itemBorderRadius} = this . props ;
233
240
const { firstItemHeight, collapsed} = this . state ;
234
241
@@ -237,7 +244,7 @@ export default class StackAggregator extends PureBaseComponent {
237
244
key = { index }
238
245
onLayout = { index === 0 ? this . onLayout : undefined }
239
246
style = { [
240
- Constants . isIOS && this . styles . containerShadow ,
247
+ Constants . isIOS && styles . containerShadow ,
241
248
this . getStyle ( index ) ,
242
249
{
243
250
borderRadius : Constants . isIOS ? itemBorderRadius : undefined ,
@@ -251,8 +258,8 @@ export default class StackAggregator extends PureBaseComponent {
251
258
collapsable = { false }
252
259
>
253
260
< Card
254
- style = { [ contentContainerStyle , this . styles . card ] }
255
- onPress = { this . props . disablePresses ? false : ( ) => this . onItemPress ( index ) }
261
+ style = { [ contentContainerStyle , styles . card ] }
262
+ onPress = { ( ) => this . props . disablePresses && this . onItemPress ( index ) }
256
263
borderRadius = { itemBorderRadius }
257
264
elevation = { 5 }
258
265
>
@@ -283,7 +290,7 @@ export default class StackAggregator extends PureBaseComponent {
283
290
label = { 'Show less' }
284
291
iconSource = { icon }
285
292
link
286
- size = { ' small' }
293
+ size = { ButtonSize . small }
287
294
{ ...buttonProps }
288
295
marginH-24
289
296
marginB-20
@@ -300,7 +307,7 @@ export default class StackAggregator extends PureBaseComponent {
300
307
onPress = { this . open }
301
308
activeOpacity = { 1 }
302
309
style = { [
303
- this . styles . touchable ,
310
+ styles . touchable ,
304
311
{
305
312
height : firstItemHeight ? firstItemHeight + PEEP * 2 : undefined ,
306
313
zIndex : this . itemsCount
@@ -314,22 +321,22 @@ export default class StackAggregator extends PureBaseComponent {
314
321
}
315
322
}
316
323
317
- function createStyles ( ) {
318
- return StyleSheet . create ( {
319
- touchable : {
320
- position : 'absolute' ,
321
- width : '100%'
322
- } ,
323
- containerShadow : {
324
- backgroundColor : Colors . white ,
325
- shadowColor : Colors . dark40 ,
326
- shadowOpacity : 0.25 ,
327
- shadowRadius : 12 ,
328
- shadowOffset : { height : 5 , width : 0 }
329
- } ,
330
- card : {
331
- overflow : 'hidden' ,
332
- flexShrink : 1
333
- }
334
- } ) ;
335
- }
324
+ const styles = StyleSheet . create ( {
325
+ touchable : {
326
+ position : 'absolute' ,
327
+ width : '100%'
328
+ } ,
329
+ containerShadow : {
330
+ backgroundColor : Colors . white ,
331
+ shadowColor : Colors . dark40 ,
332
+ shadowOpacity : 0.25 ,
333
+ shadowRadius : 12 ,
334
+ shadowOffset : { height : 5 , width : 0 }
335
+ } ,
336
+ card : {
337
+ overflow : 'hidden' ,
338
+ flexShrink : 1
339
+ }
340
+ } ) ;
341
+
342
+ export default asBaseComponent < StackAggregatorProps > ( StackAggregator ) ;
0 commit comments