Skip to content

Commit 23d9ae3

Browse files
authored
WheelPicker + SectionsWheelPicker - RTL support (#2354)
* WheelPicker + SectionsWheelPicker - RTL support * fix passed prop * Fix android alignments * rename style * memoize style * shouldDisableRTL * change screen translations * upgrade screen * update screen
1 parent 14643b4 commit 23d9ae3

File tree

4 files changed

+241
-75
lines changed

4 files changed

+241
-75
lines changed
Lines changed: 135 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,52 @@
11
import _ from 'lodash';
2-
import React, {useState, useCallback} from 'react';
3-
import {Alert} from 'react-native';
4-
import {Text, View, SectionsWheelPicker, SegmentedControl, Button, Incubator} from 'react-native-ui-lib';
2+
import React, {useState, useCallback, useMemo} from 'react';
3+
import {Alert, StyleSheet} from 'react-native';
4+
import {
5+
Text,
6+
View,
7+
SectionsWheelPicker,
8+
SegmentedControl,
9+
Button,
10+
Incubator,
11+
Constants,
12+
Switch,
13+
Colors
14+
} from 'react-native-ui-lib';
515

616
const {WheelPicker} = Incubator;
17+
18+
const DAYS = _.times(10, i => i);
19+
const HOURS = _.times(24, i => i);
20+
const MINUTES = _.times(60, i => i);
21+
722
const SectionsWheelPickerScreen = () => {
823
const [numOfSections, setNumOfSections] = useState(1);
9-
24+
const [disableRTL, setDisableRTL] = useState(false);
1025
const [selectedDays, setSelectedDays] = useState(0);
1126
const [selectedHours, setSelectedHours] = useState(0);
1227
const [selectedMinutes, setSelectedMinutes] = useState(0);
1328

14-
const days = _.times(10, i => i);
15-
const hours = _.times(24, i => i);
16-
const minutes = _.times(60, i => i);
29+
const shouldDisableRTL = useMemo(() => {
30+
return Constants.isRTL && disableRTL;
31+
}, [disableRTL]);
1732

1833
const getItems = useCallback(values => {
1934
return _.map(values, item => ({label: '' + item, value: item}));
2035
}, []);
2136

22-
const onDaysChange = (item: number | string) => {
37+
const onDaysChange = useCallback((item: number | string) => {
2338
setSelectedDays(item as number);
24-
};
39+
}, []);
2540

26-
const onHoursChange = (item: number | string) => {
41+
const onHoursChange = useCallback((item: number | string) => {
2742
setSelectedHours(item as number);
28-
};
43+
}, []);
2944

30-
const onMinutesChange = (item: number | string) => {
45+
const onMinutesChange = useCallback((item: number | string) => {
3146
setSelectedMinutes(item as number);
32-
};
47+
}, []);
3348

34-
const onSavePress = () => {
49+
const onSavePress = useCallback(() => {
3550
const days = selectedDays === 1 ? 'day' : 'days';
3651
const hours = selectedHours === 1 ? 'hour' : 'hours';
3752
const minutes = selectedMinutes === 1 ? 'minute' : 'minutes';
@@ -52,67 +67,132 @@ const SectionsWheelPickerScreen = () => {
5267
: numOfSections === 2
5368
? Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days + ' and ' + selectedHours + ' ' + hours)
5469
: Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days);
55-
};
70+
}, [numOfSections, selectedDays, selectedHours, selectedMinutes]);
5671

57-
const onResetPress = () => {
72+
const onResetPress = useCallback(() => {
5873
setSelectedDays(0);
5974
setSelectedHours(0);
6075
setSelectedMinutes(0);
61-
};
62-
63-
const sections: Incubator.WheelPickerProps[] = [
64-
{
65-
items: getItems(days),
66-
onChange: onDaysChange,
67-
initialValue: selectedDays,
68-
label: 'Days',
69-
align: numOfSections === 1 ? WheelPicker.alignments.CENTER : WheelPicker.alignments.RIGHT,
70-
style: {flex: 1}
71-
},
72-
{
73-
items: getItems(hours),
74-
onChange: onHoursChange,
75-
initialValue: selectedHours,
76-
label: 'Hrs',
77-
align: numOfSections === 2 ? WheelPicker.alignments.LEFT : WheelPicker.alignments.CENTER,
78-
style: numOfSections === 2 ? {flex: 1} : undefined
79-
},
80-
{
81-
items: getItems(minutes),
82-
onChange: onMinutesChange,
83-
initialValue: selectedMinutes,
84-
label: 'Mins',
85-
align: WheelPicker.alignments.LEFT,
86-
style: {flex: 1}
87-
}
88-
];
89-
90-
const sectionsToPresent = _.slice(sections, 0, numOfSections);
91-
92-
const onChangeIndex = (index: number) => {
76+
}, []);
77+
78+
const sections: Incubator.WheelPickerProps[] = useMemo(() => {
79+
return [
80+
{
81+
items: getItems(DAYS),
82+
onChange: onDaysChange,
83+
initialValue: selectedDays,
84+
label: Constants.isRTL ? 'ימים' : 'Days',
85+
align:
86+
numOfSections === 1
87+
? WheelPicker.alignments.CENTER
88+
: shouldDisableRTL
89+
? WheelPicker.alignments.LEFT
90+
: WheelPicker.alignments.RIGHT,
91+
style: {
92+
flex: 1,
93+
flexDirection: numOfSections !== 1 && Constants.isRTL && !disableRTL ? 'row-reverse' : undefined
94+
}
95+
},
96+
{
97+
items: getItems(HOURS),
98+
onChange: onHoursChange,
99+
initialValue: selectedHours,
100+
label: Constants.isRTL ? 'שעות' : 'Hrs',
101+
align:
102+
numOfSections === 2
103+
? shouldDisableRTL
104+
? WheelPicker.alignments.RIGHT
105+
: WheelPicker.alignments.LEFT
106+
: WheelPicker.alignments.CENTER,
107+
style: numOfSections === 2 ? {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'} : undefined
108+
},
109+
{
110+
items: getItems(MINUTES),
111+
onChange: onMinutesChange,
112+
initialValue: selectedMinutes,
113+
label: Constants.isRTL ? 'דקות' : 'Mins',
114+
align: shouldDisableRTL ? WheelPicker.alignments.RIGHT : WheelPicker.alignments.LEFT,
115+
style: {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'}
116+
}
117+
];
118+
}, [
119+
getItems,
120+
disableRTL,
121+
selectedDays,
122+
selectedHours,
123+
selectedMinutes,
124+
onDaysChange,
125+
onHoursChange,
126+
onMinutesChange,
127+
numOfSections,
128+
shouldDisableRTL
129+
]);
130+
131+
const sectionsToPresent = useMemo(() => _.slice(sections, 0, numOfSections), [numOfSections, sections]);
132+
133+
const timeSections = useMemo(() => {
134+
return [
135+
{
136+
items: getItems(_.times(24, i => i + 1))
137+
},
138+
{
139+
items: getItems(_.times(12, i => {
140+
if (i < 2) {
141+
return `0${i * 5}`;
142+
}
143+
return i * 5;
144+
}))
145+
}
146+
];
147+
}, [getItems]);
148+
149+
const onChangeIndex = useCallback((index: number) => {
93150
return setNumOfSections(index + 1);
94-
};
151+
}, []);
152+
153+
const updateDisableRTLValue = useCallback((value: boolean) => {
154+
setDisableRTL(value);
155+
}, []);
95156

96157
return (
97158
<View>
98159
<Text text40 marginL-10 marginT-20>
99160
Sections Wheel Picker
100161
</Text>
101-
<View centerH marginT-40>
162+
<View row center style={styles.bottomDivider}>
163+
<Text margin-s5> Disable RTL</Text>
164+
<Switch value={shouldDisableRTL} onValueChange={updateDisableRTLValue}/>
165+
</View>
166+
<View centerH marginT-20>
167+
<Text text60 marginB-20>
168+
Pick a duration
169+
</Text>
102170
<SegmentedControl
103171
segments={[{label: '1 section'}, {label: '2 sections'}, {label: '3 sections'}]}
104172
onChangeIndex={onChangeIndex}
105173
throttleTime={400}
106174
/>
107-
<Text text50 marginV-20>
108-
Pick a duration
175+
</View>
176+
<SectionsWheelPicker numberOfVisibleRows={4} disableRTL={disableRTL} sections={sectionsToPresent}/>
177+
<View paddingB-20 center spread row style={styles.bottomDivider}>
178+
<Button marginR-40 link label={'Save'} onPress={onSavePress}/>
179+
<Button label={'Reset'} link onPress={onResetPress}/>
180+
</View>
181+
<View>
182+
<Text center text60 marginV-20>
183+
Pick a time
109184
</Text>
185+
<SectionsWheelPicker disableRTL={disableRTL} sections={timeSections}/>
110186
</View>
111-
<SectionsWheelPicker sections={sectionsToPresent}/>
112-
<Button marginH-150 marginT-40 label={'Save'} onPress={onSavePress}/>
113-
<Button marginH-150 marginT-15 label={'Reset'} onPress={onResetPress}/>
114187
</View>
115188
);
116189
};
117190

118191
export default SectionsWheelPickerScreen;
192+
193+
const styles = StyleSheet.create({
194+
bottomDivider: {
195+
borderBottomColor: Colors.$outlineDefault,
196+
borderBottomWidth: 4
197+
}
198+
});

src/components/sectionsWheelPicker/index.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import _ from 'lodash';
2-
import React from 'react';
3-
import {TextStyle} from 'react-native';
4-
import {asBaseComponent} from '../../commons/new';
2+
import React, {useMemo} from 'react';
3+
import {TextStyle, StyleSheet} from 'react-native';
4+
import {Constants, asBaseComponent} from '../../commons/new';
55
import View from '../view';
66
import {WheelPicker, WheelPickerProps} from '../../incubator';
77

@@ -32,6 +32,7 @@ export type SectionsWheelPickerProps = {
3232
* Row text style
3333
*/
3434
textStyle?: TextStyle;
35+
disableRTL?: boolean;
3536
testID?: string;
3637
};
3738

@@ -42,7 +43,8 @@ export type SectionsWheelPickerProps = {
4243
*/
4344

4445
const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {
45-
const {sections, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, testID} = props;
46+
const {sections, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, disableRTL, testID} =
47+
props;
4648

4749
const wheelPickerProps = {
4850
itemHeight,
@@ -52,13 +54,25 @@ const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {
5254
textStyle
5355
};
5456

57+
const shouldDisableRTL = useMemo(() => {
58+
return Constants.isRTL && disableRTL;
59+
}, [disableRTL]);
60+
5561
const renderSections = () =>
5662
_.map(sections, (section, index) => {
57-
return <WheelPicker key={index} testID={`${testID}.${index}`} {...wheelPickerProps} {...section}/>;
63+
return (
64+
<WheelPicker
65+
disableRTL={shouldDisableRTL}
66+
key={index}
67+
testID={`${testID}.${index}`}
68+
{...wheelPickerProps}
69+
{...section}
70+
/>
71+
);
5872
});
5973

6074
return (
61-
<View row centerH testID={testID}>
75+
<View row centerH style={shouldDisableRTL && styles.disableRTL} testID={testID}>
6276
{renderSections()}
6377
</View>
6478
);
@@ -67,3 +81,9 @@ const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {
6781
SectionsWheelPicker.displayName = 'SectionsWheelPicker';
6882

6983
export default asBaseComponent<SectionsWheelPickerProps>(SectionsWheelPicker);
84+
85+
const styles = StyleSheet.create({
86+
disableRTL: {
87+
flexDirection: 'row-reverse'
88+
}
89+
});

src/incubator/WheelPicker/Item.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface ItemProps {
1414
label: string;
1515
value: string | number;
1616
align?: WheelPickerAlign;
17+
disableRTL?: boolean;
1718
}
1819

1920
interface InternalProps extends ItemProps {
@@ -45,7 +46,8 @@ const WheelPickerItem = memo(({
4546
style,
4647
testID,
4748
centerH = true,
48-
align
49+
align,
50+
disableRTL
4951
}: InternalProps) => {
5052
const selectItem = useCallback(() => onSelect(index), [index]);
5153
const itemOffset = index * itemHeight;
@@ -60,8 +62,16 @@ const WheelPickerItem = memo(({
6062
}, [itemHeight]);
6163

6264
const containerStyle = useMemo(() => {
63-
return [{height: itemHeight}, styles.container];
64-
}, [itemHeight]);
65+
return [{height: itemHeight}, styles.container, disableRTL && styles.disableRTL];
66+
}, [itemHeight, disableRTL]);
67+
68+
const textWithLabelPaddingStyle = useMemo(() => {
69+
return disableRTL ? {marginRight: Spacings.s5} : {marginLeft: Spacings.s5};
70+
}, [disableRTL]);
71+
72+
const textStyle = useMemo(() => {
73+
return [animatedColorStyle, style, fakeLabel ? textWithLabelPaddingStyle : styles.textPadding];
74+
}, [style, fakeLabel, animatedColorStyle, textWithLabelPaddingStyle]);
6575

6676
return (
6777
<AnimatedTouchableOpacity
@@ -82,12 +92,17 @@ const WheelPickerItem = memo(({
8292
text60R
8393
testID={`${testID}.text`}
8494
numberOfLines={1}
85-
style={[animatedColorStyle, style, fakeLabel ? styles.textWithLabelPadding : styles.textPadding]}
95+
style={textStyle}
8696
>
8797
{label}
8898
</AnimatedText>
8999
{fakeLabel && (
90-
<Text marginL-s2 marginR-s5 text80M $textDefaultLight {...fakeLabelProps} style={fakeLabelStyle}>
100+
<Text
101+
text80M
102+
$textDefaultLight
103+
{...fakeLabelProps}
104+
style={fakeLabelStyle}
105+
>
91106
{fakeLabel}
92107
</Text>
93108
)}
@@ -105,7 +120,7 @@ const styles = StyleSheet.create({
105120
textPadding: {
106121
paddingHorizontal: Spacings.s5
107122
},
108-
textWithLabelPadding: {
109-
paddingLeft: Spacings.s5
123+
disableRTL: {
124+
flexDirection: 'row-reverse'
110125
}
111126
});

0 commit comments

Comments
 (0)