1
1
import _ from 'lodash' ;
2
2
import React from 'react' ;
3
3
import { StyleSheet } from 'react-native' ;
4
- // TODO: we should use asBaseComponent here instead of using UIComponent directly
5
4
import { Colors , Spacings } from 'style' ;
5
+ // TODO: we should use asBaseComponent here instead of using UIComponent directly
6
6
import UIComponent from '../../commons/UIComponent' ;
7
7
import View from '../view' ;
8
8
import Text from '../text' ;
9
9
import { Constants } from 'helpers' ;
10
10
import GridListItem , { GridListItemProps } from '../gridListItem' ;
11
11
import { formatLastItemLabel } from '../../helpers/FormattingPresenter' ;
12
12
13
+ const DEFAULT_NUM_COLUMNS = 3 ;
14
+ const DEFAULT_ITEM_SPACINGS = Spacings . s4 ;
13
15
export interface GridViewProps {
14
16
/**
15
17
* The list of items based on GridListItem props
@@ -20,7 +22,11 @@ export interface GridViewProps {
20
22
*/
21
23
viewWidth ?: number ;
22
24
/**
23
- * Number of items to show in a row
25
+ * Allow a responsive item width to the maximum item width
26
+ */
27
+ maxItemWidth ?: number ;
28
+ /**
29
+ * Number of items to show in a row (ignored when passing maxItemWidth)
24
30
*/
25
31
numColumns ?: number ;
26
32
/**
@@ -38,44 +44,38 @@ export interface GridViewProps {
38
44
/**
39
45
* whether to keep the items initial size when orientation changes,
40
46
* in which case the apt number of columns will be calculated automatically.
47
+ * Ignored when passing 'maxItemWidth'
41
48
*/
42
49
keepItemSize ?: boolean ;
43
50
}
44
51
45
- interface State {
52
+ interface GridViewState {
46
53
viewWidth : number ;
47
54
numColumns : number ;
55
+ itemSize : number ;
48
56
}
49
57
50
-
51
- type ExistProps = GridViewProps & State
52
58
/**
53
59
* @description : A auto-generated grid view that calculate item size according to given props
54
60
* @example : https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/GridViewScreen.tsx
55
61
*/
56
- class GridView extends UIComponent < GridViewProps , State > {
62
+ class GridView extends UIComponent < GridViewProps , GridViewState > {
57
63
static displayName = 'GridView' ;
58
64
59
65
static defaultProps = {
60
- numColumns : 3 ,
61
- itemSpacing : Spacings . s4
66
+ numColumns : DEFAULT_NUM_COLUMNS ,
67
+ itemSpacing : DEFAULT_ITEM_SPACINGS
62
68
} ;
63
69
64
- private itemSize ?: number ;
65
70
private dimensionsChangeListener : any ;
66
71
67
- constructor ( props : ExistProps ) {
68
- super ( props ) ;
69
-
70
- this . state = {
71
- viewWidth : Math . floor ( props . viewWidth || this . getDefaultViewWidth ( ) ) ,
72
- numColumns : props . numColumns
73
- } ;
74
-
75
- this . itemSize = undefined ;
76
- }
72
+ state = {
73
+ viewWidth : this . getGridContainerWidth ( ) ,
74
+ numColumns : this . calcNumberOfColumns ( ) ,
75
+ itemSize : this . calcItemSize ( )
76
+ } ;
77
77
78
- static getDerivedStateFromProps ( nextProps : ExistProps , prevState : State ) {
78
+ static getDerivedStateFromProps ( nextProps : GridViewProps , prevState : GridViewState ) {
79
79
let viewWidth ;
80
80
let numColumns ;
81
81
if ( nextProps . viewWidth && Math . floor ( nextProps . viewWidth ) !== prevState . viewWidth ) {
@@ -101,38 +101,44 @@ class GridView extends UIComponent<GridViewProps, State> {
101
101
}
102
102
103
103
onOrientationChanged = ( ) => {
104
+ const { keepItemSize} = this . props ;
105
+ const { itemSize} = this . state ;
106
+
104
107
if ( ! this . props . viewWidth ) {
105
- this . setState ( { viewWidth : Math . floor ( this . getDefaultViewWidth ( ) ) , numColumns : this . getCalculatedNumOfColumns ( ) } ) ;
108
+ const newItemSize = keepItemSize ? itemSize : this . calcItemSize ( ) ;
109
+ this . setState ( {
110
+ viewWidth : Math . floor ( this . getDefaultViewWidth ( ) ) ,
111
+ numColumns : this . calcNumberOfColumns ( ) ,
112
+ itemSize : newItemSize
113
+ } ) ;
106
114
}
107
115
} ;
108
116
109
- shouldUpdateItemSize ( ) {
110
- return ! this . itemSize || ! this . props . keepItemSize ;
117
+ getDefaultViewWidth ( ) {
118
+ return Constants . screenWidth - Spacings . s5 * 2 ;
111
119
}
112
120
113
- getDefaultViewWidth ( ) {
114
- // @ts -ignore
115
- return Constants . screenWidth - ( Spacings . page * 2 ) ;
121
+ getGridContainerWidth ( ) {
122
+ return Math . floor ( this . props . viewWidth || this . getDefaultViewWidth ( ) ) ;
116
123
}
117
124
118
- getCalculatedNumOfColumns ( ) {
119
- const { itemSpacing, numColumns} = this . props as ExistProps ;
125
+ calcNumberOfColumns ( ) {
126
+ const { numColumns, itemSpacing = DEFAULT_ITEM_SPACINGS , maxItemWidth} = this . props ;
127
+ const containerWidth = this . getGridContainerWidth ( ) ;
120
128
121
- if ( ! this . shouldUpdateItemSize ( ) && Constants . orientation === 'landscape' && this . itemSize && itemSpacing ) {
122
- const numberOfColumns = this . getDefaultViewWidth ( ) / ( this . itemSize + itemSpacing ) ;
123
- return Math . floor ( numberOfColumns ) ;
129
+ if ( maxItemWidth ) {
130
+ return Math . ceil ( ( containerWidth + itemSpacing ) / ( maxItemWidth + itemSpacing ) ) ;
131
+ } else {
132
+ return numColumns || DEFAULT_NUM_COLUMNS ;
124
133
}
125
- return numColumns ;
126
134
}
127
135
128
- getItemSize ( ) {
129
- const { itemSpacing} = this . props ;
130
- const { viewWidth, numColumns} = this . state ;
136
+ calcItemSize ( ) {
137
+ const { itemSpacing = DEFAULT_ITEM_SPACINGS } = this . props ;
138
+ const containerWidth = this . getGridContainerWidth ( ) ;
139
+ const numColumns = this . calcNumberOfColumns ( ) ;
131
140
132
- if ( this . shouldUpdateItemSize ( ) && viewWidth && itemSpacing && numColumns ) {
133
- return ( viewWidth - itemSpacing * ( numColumns - 1 ) ) / numColumns ;
134
- }
135
- return this . itemSize ;
141
+ return ( containerWidth - itemSpacing * ( numColumns - 1 ) ) / numColumns ;
136
142
}
137
143
138
144
getThemeColor ( placeColor : string ) {
@@ -154,10 +160,7 @@ class GridView extends UIComponent<GridViewProps, State> {
154
160
return ;
155
161
}
156
162
157
- const imageBorderRadius = _ . chain ( items )
158
- . first ( )
159
- . get ( 'imageProps.borderRadius' )
160
- . value ( ) ;
163
+ const imageBorderRadius = _ . chain ( items ) . first ( ) . get ( 'imageProps.borderRadius' ) . value ( ) ;
161
164
return (
162
165
< View
163
166
style = { [
@@ -173,36 +176,40 @@ class GridView extends UIComponent<GridViewProps, State> {
173
176
}
174
177
175
178
renderItem = ( item : GridListItemProps , index : number ) => {
179
+ const { itemSize} = this . state ;
176
180
const { items, itemSpacing} = this . props ;
177
- const { numColumns} = this . state ;
181
+
182
+ const { numColumns = DEFAULT_NUM_COLUMNS } = this . state ;
178
183
const itemsCount = _ . size ( items ) ;
179
184
const rowCount = itemsCount / numColumns ;
180
185
const isLastItemInRow = ( index + 1 ) % numColumns === 0 ;
181
186
const isLastRow = index + 1 > ( rowCount - 1 ) * numColumns ;
182
187
const isLastItem = index === itemsCount - 1 ;
183
- const size = typeof item . itemSize === 'object'
184
- ? { width : this . itemSize , height : _ . get ( item . itemSize , 'height' , this . itemSize ) }
185
- : this . itemSize ;
188
+ const size =
189
+ typeof item . itemSize === 'object' ? { width : itemSize , height : item . itemSize ?. height || itemSize } : itemSize ;
186
190
return (
187
191
< GridListItem
188
192
key = { index }
189
193
{ ...item }
190
194
itemSize = { size }
191
- containerStyle = { [ ! isLastItemInRow && { marginRight : itemSpacing } ,
192
- ! isLastRow && { marginBottom : itemSpacing } , item . containerStyle ] }
195
+ containerStyle = { [
196
+ ! isLastItemInRow && { marginRight : itemSpacing } ,
197
+ ! isLastRow && { marginBottom : itemSpacing } ,
198
+ item . containerStyle
199
+ ] }
193
200
>
194
201
{ isLastItem && this . renderLastItemOverlay ( ) }
195
202
</ GridListItem >
196
203
) ;
197
204
} ;
198
205
199
206
render ( ) {
207
+ const { itemSize} = this . state ;
200
208
const { items, viewWidth} = this . props ;
201
- this . itemSize = this . getItemSize ( ) ;
202
209
203
210
return (
204
211
< View style = { [ styles . container , { width : viewWidth ? Math . floor ( viewWidth ) : undefined } ] } >
205
- { this . itemSize && _ . map ( items , this . renderItem ) }
212
+ { itemSize && _ . map ( items , this . renderItem ) }
206
213
</ View >
207
214
) ;
208
215
}
0 commit comments