Skip to content

WheelPicker + SectionsWheelPicker - RTL support #2354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 102 additions & 49 deletions demo/src/screens/componentScreens/SectionsWheelPickerScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,55 @@
import _ from 'lodash';
import React, {useState, useCallback} from 'react';
import React, {useState, useCallback, useMemo} from 'react';
import {Alert} from 'react-native';
import {Text, View, SectionsWheelPicker, SegmentedControl, Button, Incubator} from 'react-native-ui-lib';
import {
Text,
View,
SectionsWheelPicker,
SegmentedControl,
Button,
Incubator,
Constants,
Switch
} from 'react-native-ui-lib';

const {WheelPicker} = Incubator;

const DAYS = _.times(10, i => i);
const HOURS = _.times(24, i => i);
const MINUTES = _.times(60, i => i);

const SectionsWheelPickerScreen = () => {
const [numOfSections, setNumOfSections] = useState(1);

const [disableRTL, setDisableRTL] = useState(false);
const [selectedDays, setSelectedDays] = useState(0);
const [selectedHours, setSelectedHours] = useState(0);
const [selectedMinutes, setSelectedMinutes] = useState(0);

const days = _.times(10, i => i);
const hours = _.times(24, i => i);
const minutes = _.times(60, i => i);
const shouldDisableRTL = useMemo(() => {
return Constants.isRTL && disableRTL;
}, [disableRTL]);

const shouldTranslateLabel = useMemo(() => {
return Constants.isRTL && !shouldDisableRTL;
}, [shouldDisableRTL]);

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

const onDaysChange = (item: number | string) => {
const onDaysChange = useCallback((item: number | string) => {
setSelectedDays(item as number);
};
}, []);

const onHoursChange = (item: number | string) => {
const onHoursChange = useCallback((item: number | string) => {
setSelectedHours(item as number);
};
}, []);

const onMinutesChange = (item: number | string) => {
const onMinutesChange = useCallback((item: number | string) => {
setSelectedMinutes(item as number);
};
}, []);

const onSavePress = () => {
const onSavePress = useCallback(() => {
const days = selectedDays === 1 ? 'day' : 'days';
const hours = selectedHours === 1 ? 'hour' : 'hours';
const minutes = selectedMinutes === 1 ? 'minute' : 'minutes';
Expand All @@ -52,46 +70,77 @@ const SectionsWheelPickerScreen = () => {
: numOfSections === 2
? Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days + ' and ' + selectedHours + ' ' + hours)
: Alert.alert('Your chosen duration is:\n' + selectedDays + ' ' + days);
};
}, [numOfSections, selectedDays, selectedHours, selectedMinutes]);

const onResetPress = () => {
const onResetPress = useCallback(() => {
setSelectedDays(0);
setSelectedHours(0);
setSelectedMinutes(0);
};

const sections: Incubator.WheelPickerProps[] = [
{
items: getItems(days),
onChange: onDaysChange,
initialValue: selectedDays,
label: 'Days',
align: numOfSections === 1 ? WheelPicker.alignments.CENTER : WheelPicker.alignments.RIGHT,
style: {flex: 1}
},
{
items: getItems(hours),
onChange: onHoursChange,
initialValue: selectedHours,
label: 'Hrs',
align: numOfSections === 2 ? WheelPicker.alignments.LEFT : WheelPicker.alignments.CENTER,
style: numOfSections === 2 ? {flex: 1} : undefined
},
{
items: getItems(minutes),
onChange: onMinutesChange,
initialValue: selectedMinutes,
label: 'Mins',
align: WheelPicker.alignments.LEFT,
style: {flex: 1}
}
];

const sectionsToPresent = _.slice(sections, 0, numOfSections);

const onChangeIndex = (index: number) => {
}, []);

const sections: Incubator.WheelPickerProps[] = useMemo(() => {
return [
{
items: getItems(DAYS),
onChange: onDaysChange,
initialValue: selectedDays,
label: shouldTranslateLabel ? 'ימים' : 'Days',
align:
numOfSections === 1
? WheelPicker.alignments.CENTER
: shouldDisableRTL
? WheelPicker.alignments.LEFT
: WheelPicker.alignments.RIGHT,
style: {
flex: 1,
flexDirection: numOfSections !== 1 && Constants.isRTL && !disableRTL ? 'row-reverse' : undefined
}
},
{
items: getItems(HOURS),
onChange: onHoursChange,
initialValue: selectedHours,
label: shouldTranslateLabel ? 'שעות' : 'Hrs',
align:
numOfSections === 2
? shouldDisableRTL
? WheelPicker.alignments.RIGHT
: WheelPicker.alignments.LEFT
: WheelPicker.alignments.CENTER,
style: numOfSections === 2 ? {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'} : undefined
},
{
items: getItems(MINUTES),
onChange: onMinutesChange,
initialValue: selectedMinutes,
label: shouldTranslateLabel ? 'דקות' : 'Mins',
align: shouldDisableRTL ? WheelPicker.alignments.RIGHT : WheelPicker.alignments.LEFT,
style: {flex: 1, flexDirection: shouldDisableRTL ? 'row-reverse' : 'row'}
}
];
}, [
getItems,
disableRTL,
selectedDays,
selectedHours,
selectedMinutes,
onDaysChange,
onHoursChange,
onMinutesChange,
numOfSections,
shouldDisableRTL,
shouldTranslateLabel
]);

const sectionsToPresent = useMemo(() => _.slice(sections, 0, numOfSections), [numOfSections, sections]);

const onChangeIndex = useCallback((index: number) => {
return setNumOfSections(index + 1);
};
}, []);

const updateDisableRTLValue = useCallback((value: boolean) => {
setDisableRTL(value);
}, []);

return (
<View>
Expand All @@ -104,11 +153,15 @@ const SectionsWheelPickerScreen = () => {
onChangeIndex={onChangeIndex}
throttleTime={400}
/>
<View row center>
<Text margin-s5> Disable RTL</Text>
<Switch value={disableRTL} onValueChange={updateDisableRTLValue}/>
</View>
<Text text50 marginV-20>
Pick a duration
</Text>
</View>
<SectionsWheelPicker sections={sectionsToPresent}/>
<SectionsWheelPicker disableRTL={disableRTL} sections={sectionsToPresent}/>
<Button marginH-150 marginT-40 label={'Save'} onPress={onSavePress}/>
<Button marginH-150 marginT-15 label={'Reset'} onPress={onResetPress}/>
</View>
Expand Down
26 changes: 21 additions & 5 deletions src/components/sectionsWheelPicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from 'lodash';
import React from 'react';
import {TextStyle} from 'react-native';
import {asBaseComponent} from '../../commons/new';
import {TextStyle, StyleSheet} from 'react-native';
import {Constants, asBaseComponent} from '../../commons/new';
import View from '../view';
import {WheelPicker, WheelPickerProps} from '../../incubator';

Expand Down Expand Up @@ -32,6 +32,7 @@ export type SectionsWheelPickerProps = {
* Row text style
*/
textStyle?: TextStyle;
disableRTL?: boolean;
testID?: string;
};

Expand All @@ -42,7 +43,8 @@ export type SectionsWheelPickerProps = {
*/

const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {
const {sections, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, testID} = props;
const {sections, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, disableRTL, testID} =
props;

const wheelPickerProps = {
itemHeight,
Expand All @@ -54,11 +56,19 @@ const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {

const renderSections = () =>
_.map(sections, (section, index) => {
return <WheelPicker key={index} testID={`${testID}.${index}`} {...wheelPickerProps} {...section}/>;
return (
<WheelPicker
disableRTL={disableRTL && Constants.isRTL}
key={index}
testID={`${testID}.${index}`}
{...wheelPickerProps}
{...section}
/>
);
});

return (
<View row centerH testID={testID}>
<View row centerH style={disableRTL && Constants.isRTL && styles.disableRTL} testID={testID}>
{renderSections()}
</View>
);
Expand All @@ -67,3 +77,9 @@ const SectionsWheelPicker = (props: SectionsWheelPickerProps) => {
SectionsWheelPicker.displayName = 'SectionsWheelPicker';

export default asBaseComponent<SectionsWheelPickerProps>(SectionsWheelPicker);

const styles = StyleSheet.create({
disableRTL: {
flexDirection: 'row-reverse'
}
});
29 changes: 22 additions & 7 deletions src/incubator/WheelPicker/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface ItemProps {
label: string;
value: string | number;
align?: WheelPickerAlign;
disableRTL?: boolean;
}

interface InternalProps extends ItemProps {
Expand Down Expand Up @@ -45,7 +46,8 @@ const WheelPickerItem = memo(({
style,
testID,
centerH = true,
align
align,
disableRTL
}: InternalProps) => {
const selectItem = useCallback(() => onSelect(index), [index]);
const itemOffset = index * itemHeight;
Expand All @@ -60,8 +62,12 @@ const WheelPickerItem = memo(({
}, [itemHeight]);

const containerStyle = useMemo(() => {
return [{height: itemHeight}, styles.container];
}, [itemHeight]);
return [{height: itemHeight}, styles.container, disableRTL && styles.flipOnRTL];
}, [itemHeight, disableRTL]);

const textWithLabelPaddingStyle = useMemo(() => {
return disableRTL ? {paddingRight: Spacings.s5} : {paddingLeft: Spacings.s5};
}, [disableRTL]);

return (
<AnimatedTouchableOpacity
Expand All @@ -82,12 +88,21 @@ const WheelPickerItem = memo(({
text60R
testID={`${testID}.text`}
numberOfLines={1}
style={[animatedColorStyle, style, fakeLabel ? styles.textWithLabelPadding : styles.textPadding]}
style={[animatedColorStyle, style, fakeLabel ? textWithLabelPaddingStyle : styles.textPadding]}
>
{label}
</AnimatedText>
{fakeLabel && (
<Text marginL-s2 marginR-s5 text80M $textDefaultLight {...fakeLabelProps} style={fakeLabelStyle}>
<Text
marginL-s2={!disableRTL}
marginR-s5={!disableRTL}
marginR-s2={disableRTL}
marginL-s5={disableRTL}
text80M
$textDefaultLight
{...fakeLabelProps}
style={fakeLabelStyle}
>
{fakeLabel}
</Text>
)}
Expand All @@ -105,7 +120,7 @@ const styles = StyleSheet.create({
textPadding: {
paddingHorizontal: Spacings.s5
},
textWithLabelPadding: {
paddingLeft: Spacings.s5
flipOnRTL: {
flexDirection: 'row-reverse'
}
});
Loading