Skip to content

Commit 1ee09ba

Browse files
mendyEdriethanshar
andauthored
Feat/new wheel picker integration (#1083)
* Change prop name to match current picker * Fix Container type, when no panDirection set - fixing scrollable content to be avoided * added logic to support the current WheelPicker api and behaviour, added option to pass selected predefined value * Support integrating new WeelPicker * New WheelPicker integration * WIP - picker item needs to be created * Fix build issue by reorder methods * Using reanimated tests stub to fix failing tests * fix WheelPicker demo screen * align items in demo screen * showcase both options to manage WeelPicker style * typescript * Fix extra space on the bottom of the wheel, use onLayout for starting-index instead timer * replace native WheelPicker in android with our new WheelPicker * replaced Android's WheelPicker when useNativePicker - with our new WheelPicker * support WheelPicker to be fully controlled * added WheelPicker presenter * implement WheelPicker presenter * WheelPicker unittests * lint fix * ts file * fix android import * wheel-picker import style * Fixing demo screen * ts fix * PR Comments - naming * Demo screen structure code * PR Comment - spacing * Avoid check when offset send is -1 (prior render) * API naming * API naming + demo fixes * PR Comments - added component memo, remove unnecessary memo from separators * Style is based on parent, so no need for extra * fix lint errors * Fixing issue when not passing back the onChange event * lint Co-authored-by: Ethan Sharabi <[email protected]>
1 parent 70e2978 commit 1ee09ba

File tree

13 files changed

+449
-123
lines changed

13 files changed

+449
-123
lines changed

demo/src/screens/incubatorScreens/WheelPickerScreen.tsx

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, {useCallback} from 'react';
1+
import React, {useCallback, useState} from 'react';
22
import {View, Text, Incubator, Colors, Typography} from 'react-native-ui-lib';
33
import _ from 'lodash';
4-
import {ItemProps} from 'src/incubator/WheelPicker/Item';
54

65
// Months
76
const months = [
@@ -22,27 +21,61 @@ const months = [
2221
// Years
2322
const years = _.times(2020, i => i);
2423

25-
export default () => {
24+
const useData = (initialMonth?: string, initialYear?: string) => {
25+
26+
const [selectedMonth, setMonth] = useState<string | undefined>(initialMonth);
27+
const [selectedYear, setYear] = useState<string | undefined>(initialYear);
28+
29+
const onMonthChange = (item: string | undefined, _: number) => {
30+
setMonth(item);
31+
};
32+
33+
const onYearChange = (item: string | undefined, _: number) => {
34+
setYear(item);
35+
};
36+
37+
const getMonths = useCallback(() => {
38+
return _.map(months, item => ({label: item, value: item}));
39+
}, []);
2640

27-
const onChange = useCallback((index: number, item?: ItemProps) => {
28-
console.log(item, index);
41+
const getYears = useCallback(() => {
42+
return _.map(years, item => ({label: '' + item, value: item}));
2943
}, []);
3044

45+
return {
46+
getMonths,
47+
getYears,
48+
onMonthChange,
49+
onYearChange,
50+
selectedMonth,
51+
selectedYear
52+
};
53+
};
54+
55+
export default () => {
56+
57+
const {selectedMonth, onMonthChange, getMonths, selectedYear, onYearChange, getYears} = useData('February', undefined);
58+
3159
return (
3260
<View flex padding-page>
3361
<Text h1>Wheel Picker</Text>
34-
<View flex centerV centerH paddingT-page>
62+
63+
<View flex centerV centerH>
3564
<Text h3>Months</Text>
3665
<Incubator.WheelPicker
37-
onChange={onChange}
66+
style={{width: '100%'}}
67+
onChange={onMonthChange}
3868
activeTextColor={Colors.primary}
3969
inactiveTextColor={Colors.grey20}
40-
items={_.map(months, i => ({text: i, value: i}))}
41-
textStyle={{...Typography.text60R}}
70+
items={getMonths()}
71+
textStyle={Typography.text60R}
72+
selectedValue={selectedMonth}
4273
/>
43-
44-
<Text h3 marginT-s5>Years</Text>
45-
<Incubator.WheelPicker onChange={onChange} items={_.map(years, i => ({text: '' + i, value: i}))} />
74+
75+
<Text h3>Years</Text>
76+
<View height={300} width={'100%'}>
77+
<Incubator.WheelPicker onChange={onYearChange} selectedValue={selectedYear} items={getYears()}/>
78+
</View>
4679
</View>
4780
</View>
4881
);

generatedTypes/incubator/WheelPicker/Item.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference types="react" />
22
import { TextStyle } from 'react-native';
33
export interface ItemProps {
4-
text: string;
4+
label: string;
55
value: string | number;
66
}
77
interface InternalProps extends ItemProps {
@@ -13,5 +13,5 @@ interface InternalProps extends ItemProps {
1313
style?: TextStyle;
1414
onSelect: (index: number) => void;
1515
}
16-
declare const _default: ({ index, text, itemHeight, onSelect, offset, activeColor, inactiveColor, style }: InternalProps) => JSX.Element;
16+
declare const _default: ({ index, label, itemHeight, onSelect, offset, activeColor, inactiveColor, style }: InternalProps) => JSX.Element;
1717
export default _default;
Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,56 @@
11
/// <reference types="react" />
2-
import { TextStyle } from 'react-native';
3-
import { ItemProps } from './Item';
2+
import {TextStyle} from 'react-native';
3+
import {ItemProps} from './Item';
44
export interface WheelPickerProps {
5-
/**
6-
* Data source for WheelPicker
7-
*/
8-
items?: ItemProps[];
9-
/**
10-
* Describe the height of each item in the WheelPicker
11-
*/
12-
itemHeight?: number;
13-
/**
14-
* Text color for the focused row
15-
*/
16-
activeTextColor?: string;
17-
/**
18-
* Text color for other, non-focused rows
19-
*/
20-
inactiveTextColor?: string;
21-
/**
22-
* Row text style
23-
*/
24-
textStyle?: TextStyle;
25-
/**
26-
* Event, on active row change
27-
*/
28-
onChange: (index: number, item?: ItemProps) => void;
5+
/**
6+
* Data source for WheelPicker
7+
*/
8+
items?: ItemProps[];
9+
/**
10+
* Describe the height of each item in the WheelPicker
11+
* default value: 44
12+
*/
13+
itemHeight?: number;
14+
/**
15+
* Describe the number of rows visible
16+
* default value: 5
17+
*/
18+
numberOfVisibleRows?: number;
19+
/**
20+
* Text color for the focused row
21+
*/
22+
activeTextColor?: string;
23+
/**
24+
* Text color for other, non-focused rows
25+
*/
26+
inactiveTextColor?: string;
27+
/**
28+
* Row text style
29+
*/
30+
textStyle?: TextStyle;
31+
/**
32+
* Event, on active row change
33+
*/
34+
onChange?: (item: string | undefined, index: number) => void;
35+
/**
36+
* Container's ViewStyle, height is computed according to itemHeight * numberOfVisibleRows
37+
*/
38+
style?: Omit<ViewStyle, 'height'>;
39+
/**
40+
* Support passing items as children props
41+
*/
42+
children?: JSX.Element | JSX.Element[];
43+
/**
44+
* WheelPicker initial value, can be ItemProps.value, number as index
45+
*/
46+
selectedValue?: ItemProps | string | number;
2947
}
30-
declare const WheelPicker: ({ items, itemHeight, activeTextColor, inactiveTextColor, textStyle, onChange: onChangeEvent }: WheelPickerProps) => JSX.Element;
48+
declare const WheelPicker: ({
49+
items,
50+
itemHeight,
51+
activeTextColor,
52+
inactiveTextColor,
53+
textStyle,
54+
onChange: onChangeEvent
55+
}: WheelPickerProps) => JSX.Element;
3156
export default WheelPicker;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference types="react" />
2+
import { ItemProps } from './Item';
3+
declare type ItemValueTypes = ItemProps | number | string;
4+
export { ItemValueTypes };
5+
declare type PropTypes = {
6+
selectedValue: ItemValueTypes;
7+
children?: JSX.Element | JSX.Element[];
8+
items?: ItemProps[];
9+
itemHeight: number;
10+
preferredNumVisibleRows: number;
11+
};
12+
declare type RowItem = {
13+
value: string | number;
14+
index: number;
15+
};
16+
interface Presenter {
17+
items: ItemProps[];
18+
shouldControlComponent: (offset: number) => boolean;
19+
index: number;
20+
height: number;
21+
getRowItemAtOffset: (offset: number) => RowItem;
22+
}
23+
declare const usePresenter: ({ selectedValue, children, items: propItems, itemHeight, preferredNumVisibleRows }: PropTypes) => Presenter;
24+
export default usePresenter;

jest-setup.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ jest.spyOn(AccessibilityInfo, 'isScreenReaderEnabled').mockImplementation(() =>
66
// mock native modules
77
jest.mock('@react-native-community/blur', () => {});
88
jest.mock('@react-native-community/netinfo', () => {});
9-
jest.mock('react-native-reanimated', () => ({}));
9+
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
1010
jest.mock('react-native-gesture-handler', () => {});
1111
jest.mock('@react-native-picker/picker', () => ({Picker: {Item: {}}}));

src/components/dialog/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,18 @@ class Dialog extends Component<DialogProps, DialogState> {
211211
}
212212
};
213213

214+
getContainerType = () => {
215+
const {panDirection, renderPannableHeader} = this.props;
216+
if (!panDirection || renderPannableHeader) {
217+
return View;
218+
}
219+
return PanListenerView;
220+
}
221+
214222
renderDialogView = () => {
215-
const {children, renderPannableHeader, panDirection = PanningProvider.Directions.DOWN, containerStyle, testID} = this.props;
223+
const {children, panDirection = PanningProvider.Directions.DOWN, containerStyle, testID} = this.props;
216224
const {dialogVisibility} = this.state;
217-
const Container = renderPannableHeader ? View : PanListenerView;
225+
const Container = this.getContainerType();
218226

219227
return (
220228
<View testID={testID} style={[this.styles.dialogViewSize]} pointerEvents="box-none">

src/components/picker/NativePicker.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import _ from 'lodash';
22
import React from 'react';
33
import {BaseComponent} from '../../commons';
44
import TextField from '../textField';
5-
import {WheelPicker} from '../../nativeComponents';
65
import PickerDialog from './PickerDialog';
76
import TouchableOpacity from '../touchableOpacity';
87
import {Colors} from '../../style';
8+
import {WheelPicker} from '../../nativeComponents';
99

1010
class NativePicker extends BaseComponent {
1111
static displayName = 'IGNORE';
@@ -15,6 +15,11 @@ class NativePicker extends BaseComponent {
1515
showDialog: false
1616
};
1717

18+
NUMBER_OF_ROWS = 5;
19+
ROW_HEIGHT = 44;
20+
MENU_HEIGHT = 44;
21+
PICKER_HEIGHT = this.NUMBER_OF_ROWS * this.ROW_HEIGHT + this.MENU_HEIGHT;
22+
1823
extractPickerItems(props) {
1924
const {children, useNativePicker} = props;
2025
if (useNativePicker) {
@@ -59,9 +64,10 @@ class NativePicker extends BaseComponent {
5964

6065
renderPickerDialog = () => {
6166
const {selectedValue, showDialog} = this.state;
62-
67+
6368
return (
6469
<PickerDialog
70+
height={this.PICKER_HEIGHT + this.MENU_HEIGHT}
6571
{...this.getThemeProps()}
6672
visible={showDialog}
6773
panDirection={null}

src/components/picker/PickerDialog.android.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Dialog from '../dialog';
99
import View from '../view';
1010
import Text from '../text';
1111
import {Colors, BorderRadiuses} from '../../style';
12-
import {WheelPicker} from '../../nativeComponents';
12+
import {WheelPicker} from '../../incubator';
1313

1414
class PickerDialog extends BaseComponent {
1515
static displayName = 'IGNORE';
@@ -74,7 +74,7 @@ class PickerDialog extends BaseComponent {
7474
return renderNativePicker(this.props);
7575
}
7676
return (
77-
<WheelPicker onValueChange={onValueChange} selectedValue={selectedValue} {...wheelPickerProps}>
77+
<WheelPicker selectedValue={selectedValue} onChange={onValueChange} {...wheelPickerProps}>
7878
{children}
7979
</WheelPicker>
8080
);

src/components/picker/PickerDialog.ios.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Dialog from '../dialog';
99
import View from '../view';
1010
import Text from '../text';
1111
import {Colors} from '../../style';
12-
import {WheelPicker} from '../../nativeComponents';
12+
import {WheelPicker} from '../../incubator';
1313

1414
class PickerDialog extends BaseComponent {
1515
static displayName = 'IGNORE';
@@ -40,12 +40,12 @@ class PickerDialog extends BaseComponent {
4040
}
4141

4242
renderPicker() {
43-
const {children, onValueChange, selectedValue, renderNativePicker} = this.props;
43+
const {children, onValueChange, selectedValue, renderNativePicker, pickerStyle} = this.props;
4444
if (_.isFunction(renderNativePicker)) {
4545
return renderNativePicker(this.props);
4646
}
4747
return (
48-
<WheelPicker onValueChange={onValueChange} selectedValue={selectedValue}>
48+
<WheelPicker style={pickerStyle} selectedValue={selectedValue} onChange={onValueChange}>
4949
{children}
5050
</WheelPicker>
5151
);
@@ -56,12 +56,13 @@ class PickerDialog extends BaseComponent {
5656
// TODO: should be taken from dialogProps but there's an issue with "babel-plugin-typescript-to-proptypes" plugin
5757
const {panDirection} = this.props;
5858
return (
59-
<Dialog {...dialogProps} height={250} width="100%" migrate bottom animationConfig={{duration: 300}} panDirection={panDirection}>
59+
<Dialog {...dialogProps} width="100%" migrate bottom animationConfig={{duration: 300}} panDirection={panDirection}>
6060
<View flex bg-white>
6161
{this.renderHeader()}
6262
<View centerV flex>
6363
{this.renderPicker()}
6464
</View>
65+
<View useSafeArea/>
6566
</View>
6667
</Dialog>
6768
);

src/incubator/WheelPicker/Item.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const AnimatedTouchableOpacity = Animated.createAnimatedComponent(
1111
const AnimatedText = Animated.createAnimatedComponent(Text);
1212

1313
export interface ItemProps {
14-
text: string;
14+
label: string;
1515
value: string | number;
1616
}
1717

@@ -27,7 +27,7 @@ interface InternalProps extends ItemProps {
2727

2828
export default ({
2929
index,
30-
text,
30+
label,
3131
itemHeight,
3232
onSelect,
3333
offset,
@@ -64,7 +64,7 @@ export default ({
6464
>
6565
{/* @ts-ignore reanimated2*/}
6666
<AnimatedText text60R style={{color, ...style}}>
67-
{text}
67+
{label}
6868
</AnimatedText>
6969
</AnimatedTouchableOpacity>
7070
);

0 commit comments

Comments
 (0)