Skip to content

Commit 43ae3f0

Browse files
ArnonZethanshar
authored andcommitted
Feat/Picker - support custom modal (#507)
* Initial commit * Added support for cutom modal * typo fix * Added custom modal example * Cosmetics * Update index.js
1 parent 78838e5 commit 43ae3f0

File tree

2 files changed

+90
-26
lines changed

2 files changed

+90
-26
lines changed

demo/src/screens/componentScreens/PickerScreen.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import _ from 'lodash';
22
import React, {Component} from 'react';
33
import {ScrollView, Image} from 'react-native';
4-
import {View, Colors, Text, Stepper, Typography, Picker, Avatar, Assets, TagsInput} from 'react-native-ui-lib'; //eslint-disable-line
4+
import {View, Colors, Dialog, Text, Stepper, Typography, Picker, Avatar, Assets, TagsInput} from 'react-native-ui-lib'; //eslint-disable-line
55
import contacts from '../../data/conversations';
66
import tagIcon from '../../assets/icons/tags.png';
77
import dropdown from '../../assets/icons/chevronDown.png';
@@ -29,6 +29,7 @@ export default class PickerScreen extends Component {
2929
// language: {value: 'java', label: 'Java'},
3030
language: undefined,
3131
languages: [],
32+
customModalValues: [],
3233
filter: filters[0],
3334
contact: contacts[0],
3435
tags: [{label: 'Amit'}, {label: 'Ethan'}],
@@ -37,11 +38,34 @@ export default class PickerScreen extends Component {
3738
};
3839
}
3940

41+
renderDialog = modalProps => {
42+
const {visible, toggleModal, children} = modalProps;
43+
44+
return (
45+
<Dialog
46+
visible={visible}
47+
onDismiss={() => toggleModal(false)}
48+
width="100%"
49+
height="45%"
50+
bottom
51+
useSafeArea
52+
style={{paddingTop: 20, backgroundColor: Colors.white}}
53+
>
54+
<View flex>
55+
<Text marginL-15 text60>
56+
Custom modal
57+
</Text>
58+
<ScrollView>{children}</ScrollView>
59+
</View>
60+
</Dialog>
61+
);
62+
};
63+
4064
render() {
4165
return (
4266
<ScrollView keyboardShouldPersistTaps="always">
4367
<View flex padding-20>
44-
<Text text40 marginB-20>
68+
<Text text40>
4569
Picker
4670
</Text>
4771
<Picker
@@ -97,7 +121,8 @@ export default class PickerScreen extends Component {
97121
style: {width: 200},
98122
color: Colors.violet30,
99123
labelStyle: {fontSize: 32, fontFamily: 'sans-serif-condensed-light'},
100-
itemHeight: 55}}
124+
itemHeight: 55
125+
}}
101126
selectLabelStyle={{color: Colors.violet30}}
102127
cancelLabelStyle={{color: Colors.violet30}}
103128
>
@@ -106,6 +131,22 @@ export default class PickerScreen extends Component {
106131
))}
107132
</Picker>
108133

134+
<View marginT-20>
135+
<Picker
136+
title="Custom modal"
137+
placeholder="Pick multiple Languages"
138+
value={this.state.customModalValues}
139+
onChange={items => this.setState({customModalValues: items})}
140+
mode={Picker.modes.MULTI}
141+
rightIconSource={dropdown}
142+
renderCustomModal={this.renderDialog}
143+
>
144+
{_.map(options, option => (
145+
<Picker.Item key={option.value} value={option} label={option.label} disabled={option.disabled} />
146+
))}
147+
</Picker>
148+
</View>
149+
109150
<Text marginT-20 marginB-10 text70 dark60>
110151
Custom Picker:
111152
</Text>

src/components/picker/index.js

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ import NativePicker from './NativePicker';
1414
import PickerModal from './PickerModal';
1515
import PickerItem from './PickerItem';
1616

17-
1817
const PICKER_MODES = {
1918
SINGLE: 'SINGLE',
20-
MULTI: 'MULTI',
19+
MULTI: 'MULTI'
2120
};
2221
const ItemType = PropTypes.shape({
23-
value: PropTypes.any,
22+
value: PropTypes.any,
2423
label: PropTypes.string
2524
});
2625

@@ -36,7 +35,13 @@ class Picker extends BaseComponent {
3635
/**
3736
* Picker current value in the shape of {value: ..., label: ...}, for custom shape use 'getItemValue' prop
3837
*/
39-
value: PropTypes.oneOfType([ItemType, PropTypes.arrayOf(ItemType), PropTypes.object, PropTypes.string, PropTypes.number]),
38+
value: PropTypes.oneOfType([
39+
ItemType,
40+
PropTypes.arrayOf(ItemType),
41+
PropTypes.object,
42+
PropTypes.string,
43+
PropTypes.number
44+
]),
4045
/**
4146
* Callback for when picker value change
4247
*/
@@ -59,6 +64,10 @@ class Picker extends BaseComponent {
5964
* Render custom picker item
6065
*/
6166
renderItem: PropTypes.func,
67+
/**
68+
* Render custom picker modal (e.g ({visible, children, toggleModal}) => {...})
69+
*/
70+
renderCustomModal: PropTypes.func,
6271
/**
6372
* Custom picker props (when using renderPicker, will apply on the button wrapper)
6473
*/
@@ -129,7 +138,6 @@ class Picker extends BaseComponent {
129138

130139
this.state = {
131140
value: props.value,
132-
showModal: false,
133141
selectedItemPosition: 0,
134142
};
135143

@@ -141,7 +149,7 @@ class Picker extends BaseComponent {
141149
}
142150

143151
if (props.useNativePicker && _.isPlainObject(props.value)) {
144-
console.warn('UILib Picker: dont use object as value for native picker, use either string or a number');
152+
console.warn('UILib Picker: don\'t use object as value for native picker, use either string or a number');
145153
}
146154
}
147155

@@ -153,7 +161,7 @@ class Picker extends BaseComponent {
153161

154162
getLabel() {
155163
const {value} = this.state;
156-
164+
157165
if (_.isArray(value)) {
158166
return _.chain(value)
159167
.map('label')
@@ -168,34 +176,34 @@ class Picker extends BaseComponent {
168176
handlePickerOnPress = () => {
169177
this.toggleExpandableModal(true);
170178
_.invoke(this.props, 'onPress');
171-
}
179+
};
172180

173-
toggleExpandableModal = (value) => {
181+
toggleExpandableModal = value => {
174182
this.setState({showExpandableModal: value});
175-
}
183+
};
176184

177-
toggleItemSelection = (item) => {
185+
toggleItemSelection = item => {
178186
const {value} = this.state;
179187
const newValue = _.xorBy(value, [item], 'value');
180188
this.setState({
181189
value: newValue,
182190
});
183-
}
191+
};
184192

185193
cancelSelect = () => {
186194
this.setState({
187195
value: this.props.value,
188196
});
189197
this.toggleExpandableModal(false);
190-
}
198+
};
191199

192-
onDoneSelecting = (item) => {
200+
onDoneSelecting = item => {
193201
this.setState({searchValue: '', value: item}); // clean search when done selecting
194202
this.toggleExpandableModal(false);
195203
_.invoke(this.props, 'onChange', item);
196-
}
204+
};
197205

198-
onSearchChange = (searchValue) => {
206+
onSearchChange = searchValue => {
199207
this.setState({
200208
searchValue,
201209
});
@@ -213,10 +221,10 @@ class Picker extends BaseComponent {
213221
appendPropsToChildren = () => {
214222
const {children, mode, getItemValue, showSearch, renderItem} = this.props;
215223
const {value, searchValue} = this.state;
216-
const childrenWithProps = React.Children.map(children, (child) => {
224+
const childrenWithProps = React.Children.map(children, child => {
217225
const childValue = PickerPresenter.getItemValue({getItemValue, ...child.props});
218226
const childLabel = PickerPresenter.getItemLabel({...child.props, getLabel: child.props.getItemLabel});
219-
227+
220228
if (!showSearch || _.isEmpty(searchValue) || _.includes(_.lowerCase(childLabel), _.lowerCase(searchValue))) {
221229
const selectedValue = PickerPresenter.getItemValue({value, getItemValue});
222230
return React.cloneElement(child, {
@@ -230,7 +238,7 @@ class Picker extends BaseComponent {
230238
});
231239

232240
return childrenWithProps;
233-
}
241+
};
234242

235243
renderExpandableModal = () => {
236244
const {
@@ -241,8 +249,21 @@ class Picker extends BaseComponent {
241249
searchStyle,
242250
searchPlaceholder,
243251
renderCustomSearch,
244-
listProps} = this.getThemeProps();
252+
renderCustomModal,
253+
listProps
254+
} = this.getThemeProps();
245255
const {showExpandableModal, selectedItemPosition} = this.state;
256+
const children = this.appendPropsToChildren(this.props.children);
257+
258+
if (renderCustomModal) {
259+
const modalProps = {
260+
visible: showExpandableModal,
261+
toggleModal: this.toggleExpandableModal,
262+
children,
263+
};
264+
265+
return renderCustomModal(modalProps);
266+
}
246267

247268
return (
248269
<PickerModal
@@ -261,15 +282,17 @@ class Picker extends BaseComponent {
261282
renderCustomSearch={renderCustomSearch}
262283
listProps={listProps}
263284
>
264-
{this.appendPropsToChildren(this.props.children)}
285+
{children}
265286
</PickerModal>
266287
);
267-
}
288+
};
268289

269290
render() {
270291
const {useNativePicker, renderPicker, customPickerProps, testID} = this.props;
271292

272-
if (useNativePicker) return <NativePicker {...this.props}/>;
293+
if (useNativePicker) {
294+
return <NativePicker {...this.props} />;
295+
}
273296

274297
if (_.isFunction(renderPicker)) {
275298
const {value} = this.state;

0 commit comments

Comments
 (0)