This repository has been archived by the owner on Mar 4, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Picker implementation for each platform. Will be used for example as nationality selector in passenger section of booking screen.
- Loading branch information
Showing
12 changed files
with
593 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// @flow | ||
|
||
import * as React from 'react'; | ||
import { Picker as RNPicker } from 'react-native'; | ||
|
||
import type { PickerOption } from './PickerTypes'; | ||
import type { StylePropType } from '../PlatformStyleSheet/StyleTypes'; | ||
|
||
export type Props = {| | ||
+optionsData: $ReadOnlyArray<PickerOption>, | ||
+onValueChange: (value: string) => void, | ||
+selectedValue: string, | ||
+style: StylePropType, | ||
|}; | ||
|
||
export default function NativePicker({ | ||
optionsData, | ||
selectedValue, | ||
style, | ||
onValueChange, | ||
}: Props) { | ||
const pickerOptions = optionsData.map(option => ( | ||
<RNPicker.Item | ||
key={option.value} | ||
label={option.label} | ||
value={option.value} | ||
/> | ||
)); | ||
|
||
return ( | ||
<RNPicker | ||
selectedValue={selectedValue} | ||
style={style} | ||
onValueChange={onValueChange} | ||
> | ||
{pickerOptions} | ||
</RNPicker> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// @flow | ||
|
||
import * as React from 'react'; | ||
import { View } from 'react-native'; | ||
import { defaultTokens } from '@kiwicom/orbit-design-tokens'; | ||
|
||
import { Text } from '../Text'; | ||
import { Icon } from '../Icon'; | ||
import { StyleSheet } from '../PlatformStyleSheet'; | ||
import type { Props } from './PickerTypes'; | ||
import { getSelectedLabel } from './PickerHelpers'; | ||
import NativePicker from './NativePicker'; | ||
|
||
const Picker = ({ | ||
optionsData, | ||
selectedValue, | ||
onValueChange, | ||
placeholder = '', | ||
iconName, | ||
}: Props) => { | ||
const selectedLabel = getSelectedLabel( | ||
optionsData, | ||
selectedValue, | ||
placeholder, | ||
); | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<Text style={styles.label}>{selectedLabel}</Text> | ||
<Icon name={iconName ?? 'chevron-right'} style={styles.icon} /> | ||
<NativePicker | ||
optionsData={optionsData} | ||
selectedValue={selectedValue} | ||
style={styles.picker} | ||
onValueChange={onValueChange} | ||
/> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
width: '100%', | ||
height: parseInt(defaultTokens.heightInputNormal, 10), | ||
borderRadius: parseInt(defaultTokens.borderRadiusLarge, 10), | ||
backgroundColor: defaultTokens.backgroundButtonSecondary, | ||
}, | ||
label: { | ||
flex: 1, | ||
color: defaultTokens.colorTextAttention, | ||
paddingLeft: parseInt(defaultTokens.spaceSmall, 10), | ||
}, | ||
icon: { | ||
marginRight: 10, | ||
}, | ||
picker: { | ||
position: 'absolute', | ||
left: 0, | ||
width: '100%', | ||
opacity: 0, // NOTE: This workaround is required because picker label cannot be currently styled on Android | ||
height: parseInt(defaultTokens.heightInputNormal, 10), | ||
}, | ||
}); | ||
|
||
export default Picker; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// @flow | ||
|
||
import * as React from 'react'; | ||
import { View } from 'react-native'; | ||
import { defaultTokens } from '@kiwicom/orbit-design-tokens'; | ||
|
||
import { Button } from '../Button'; | ||
import { Icon } from '../Icon'; | ||
import { Modal } from '../Modal'; | ||
import { StyleSheet } from '../PlatformStyleSheet'; | ||
import type { Props } from './PickerTypes'; | ||
import { getSelectedLabel } from './PickerHelpers'; | ||
import NativePicker from './NativePicker'; | ||
|
||
export type State = {| | ||
open: boolean, | ||
selectedValue: string, | ||
pickerValue: string, | ||
|}; | ||
|
||
export default class Picker extends React.Component<Props, State> { | ||
static defaultProps = { | ||
placeholder: '', | ||
}; | ||
|
||
constructor(props: Props) { | ||
super(props); | ||
|
||
const { selectedValue } = this.props; | ||
|
||
this.state = { | ||
open: false, | ||
selectedValue, | ||
pickerValue: selectedValue, | ||
}; | ||
} | ||
|
||
componentDidUpdate = (prevProps: Props) => { | ||
if ( | ||
this.props.selectedValue !== prevProps.selectedValue && | ||
this.props.selectedValue !== this.state.selectedValue | ||
) { | ||
this.setState({ | ||
selectedValue: this.props.selectedValue, | ||
pickerValue: this.props.selectedValue, | ||
}); | ||
} | ||
}; | ||
|
||
handleOpenPress = () => { | ||
this.setState({ | ||
open: true, | ||
}); | ||
}; | ||
|
||
handleModalClose = () => { | ||
this.setState({ | ||
open: false, | ||
}); | ||
}; | ||
|
||
handlePickerValueChange = (value: string) => { | ||
this.setState({ pickerValue: value }); | ||
}; | ||
|
||
handleOkPress = () => { | ||
const { pickerValue } = this.state; | ||
const { onValueChange } = this.props; | ||
this.setState({ | ||
open: false, | ||
selectedValue: pickerValue, | ||
}); | ||
onValueChange(pickerValue); | ||
}; | ||
|
||
render() { | ||
const { open, selectedValue, pickerValue } = this.state; | ||
const { optionsData, confirmLabel, placeholder, iconName } = this.props; | ||
const selectedLabel = getSelectedLabel( | ||
optionsData, | ||
selectedValue, | ||
placeholder, | ||
); | ||
|
||
return ( | ||
<View> | ||
<Button | ||
onPress={this.handleOpenPress} | ||
type="secondary" | ||
label={selectedLabel} | ||
rightIcon={<Icon name={iconName ?? 'chevron-right'} />} | ||
/> | ||
<Modal | ||
isVisible={open} | ||
style={styles.modal} | ||
onRequestClose={this.handleModalClose} | ||
onBackdropPress={this.handleModalClose} | ||
> | ||
<View style={styles.container}> | ||
<NativePicker | ||
optionsData={optionsData} | ||
selectedValue={pickerValue} | ||
style={styles.picker} | ||
onValueChange={this.handlePickerValueChange} | ||
/> | ||
<View style={styles.confirmContainer}> | ||
<Button | ||
onPress={this.handleOkPress} | ||
type="secondary" | ||
label={confirmLabel} | ||
/> | ||
</View> | ||
</View> | ||
</Modal> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
modal: { | ||
margin: 0, | ||
justifyContent: 'flex-end', | ||
}, | ||
container: { | ||
width: '100%', | ||
backgroundColor: defaultTokens.backgroundModal, | ||
borderTopStartRadius: parseInt(defaultTokens.borderRadiusLarge, 10), | ||
borderTopEndRadius: parseInt(defaultTokens.borderRadiusLarge, 10), | ||
paddingTop: parseInt(defaultTokens.spaceXXSmall, 10), | ||
paddingBottom: parseInt(defaultTokens.spaceXXLarge, 10), | ||
}, | ||
picker: { | ||
width: '100%', | ||
}, | ||
confirmContainer: { | ||
marginHorizontal: parseInt(defaultTokens.spaceXSmall, 10), | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
--- | ||
name: Picker | ||
menu: Components | ||
route: /picker | ||
--- | ||
|
||
import { Playground, PropsTable } from 'docz' | ||
import { View } from 'react-native' | ||
import { Picker } from '.' | ||
|
||
# Picker | ||
|
||
## Properties | ||
|
||
<PropsTable of={Picker} /> | ||
|
||
## Basic usage | ||
|
||
<Playground> | ||
<Picker | ||
optionsData={[ | ||
{ label: 'Option A', value: 'a' }, | ||
{ label: 'Option B', value: 'b' }, | ||
]} | ||
selectedValue={'a'} | ||
onValueChange={(value) => {}} | ||
/> | ||
</Playground> | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// @flow | ||
|
||
import * as React from 'react'; | ||
import { Platform } from 'react-native'; | ||
import { storiesOf } from '@storybook/react-native'; | ||
import { select, withKnobs } from '@storybook/addon-knobs'; | ||
import { action } from '@storybook/addon-actions'; | ||
|
||
import icons from '../Icon/icons.json'; | ||
|
||
import { Picker } from '.'; | ||
|
||
const optionsData = [ | ||
{ label: 'Option A', value: 'a' }, | ||
{ label: 'Option B', value: 'b' }, | ||
{ label: 'Option C', value: 'c' }, | ||
{ label: 'Option D', value: 'd' }, | ||
{ label: 'Option E', value: 'e' }, | ||
{ label: 'Option F', value: 'f' }, | ||
]; | ||
const onValueChange = action('onValueChange'); | ||
|
||
storiesOf('Picker', module) | ||
.addDecorator(withKnobs) | ||
.add('Playground', () => { | ||
const selected = select( | ||
'selectedValue', | ||
optionsData.map(data => data.value), | ||
optionsData[3].value, | ||
); | ||
const iconName = select( | ||
'Icon name', | ||
[...Object.keys(icons)], | ||
Platform.OS === 'web' ? 'chevron-down' : 'chevron-right', | ||
); | ||
|
||
return ( | ||
<Picker | ||
optionsData={optionsData} | ||
selectedValue={selected} | ||
onValueChange={onValueChange} | ||
placeholder="Select option" | ||
confirmLabel="OK" | ||
iconName={iconName} | ||
/> | ||
); | ||
}); |
Oops, something went wrong.