Skip to content

Commit

Permalink
Fix/ WheelPicker alignment and touch area (#1464)
Browse files Browse the repository at this point in the history
* fix alignment and touch area

* PR review fixes
  • Loading branch information
lidord-wix authored Aug 11, 2021
1 parent ada2c50 commit 3dafa66
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 20 deletions.
10 changes: 7 additions & 3 deletions demo/src/screens/componentScreens/SectionsWheelPickerScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {useState, useCallback} from 'react';
import {Alert} from 'react-native';
import {Text, View, SectionsWheelPicker, SegmentedControl, Button, Incubator} from 'react-native-ui-lib';

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

Expand Down Expand Up @@ -65,21 +66,24 @@ const SectionsWheelPickerScreen = () => {
onChange: onDaysChange,
selectedValue: selectedDays,
label: 'Days',
style: numOfSections === 1 ? {flex: 1} : {flex: 1, alignItems: 'flex-end'}
align: numOfSections === 1 ? WheelPicker.alignments.CENTER : WheelPicker.alignments.RIGHT,
style: {flex: 1}
},
{
items: getItems(hours),
onChange: onHoursChange,
selectedValue: selectedHours,
label: 'Hrs',
style: numOfSections === 2 ? {flex: 1, alignItems: 'flex-start'} : undefined
align: numOfSections === 2 ? WheelPicker.alignments.LEFT : WheelPicker.alignments.CENTER,
style: numOfSections === 2 ? {flex: 1} : undefined
},
{
items: getItems(minutes),
onChange: onMinutesChange,
selectedValue: selectedMinutes,
label: 'Mins',
style: {flex: 1, alignItems: 'flex-start'}
align: WheelPicker.alignments.LEFT,
style: {flex: 1}
}
];

Expand Down
6 changes: 5 additions & 1 deletion generatedTypes/incubator/WheelPicker/Item.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';
import { TextStyle } from 'react-native';
import Animated from 'react-native-reanimated';
import { TextProps } from '../../components/text';
export interface ItemProps {
label: string;
fakeLabel?: string;
fakeLabelStyle?: TextStyle;
fakeLabelProps?: TextProps;
value: string | number;
}
interface InternalProps extends ItemProps {
Expand All @@ -16,5 +20,5 @@ interface InternalProps extends ItemProps {
testID?: string;
centerH?: boolean;
}
declare const _default: React.MemoExoticComponent<({ index, label, itemHeight, onSelect, offset, activeColor, inactiveColor, style, testID, centerH }: InternalProps) => JSX.Element>;
declare const _default: React.MemoExoticComponent<({ index, label, fakeLabel, fakeLabelStyle, fakeLabelProps, itemHeight, onSelect, offset, activeColor, inactiveColor, style, testID, centerH }: InternalProps) => JSX.Element>;
export default _default;
16 changes: 14 additions & 2 deletions generatedTypes/incubator/WheelPicker/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React from 'react';
/// <reference types="react" />
import { TextStyle, ViewStyle } from 'react-native';
import { ItemProps } from './Item';
import { TextProps } from '../../components/text';
declare enum WheelPickerAlign {
CENTER = "center",
RIGHT = "right",
LEFT = "left"
}
export interface WheelPickerProps {
/**
* Initial value (doesn't work with selectedValue)
Expand Down Expand Up @@ -61,7 +66,14 @@ export interface WheelPickerProps {
* Support passing items as children props
*/
children?: JSX.Element | JSX.Element[];
/**
* Align the content to center, right ot left (default: center)
*/
align?: WheelPickerAlign;
testID?: string;
}
declare const WheelPicker: React.MemoExoticComponent<({ items: propItems, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, label, labelStyle, labelProps, onChange, style, children, initialValue, selectedValue, testID }: WheelPickerProps) => JSX.Element>;
declare const WheelPicker: {
({ items: propItems, itemHeight, numberOfVisibleRows, activeTextColor, inactiveTextColor, textStyle, label, labelStyle, labelProps, onChange, align, style, children, initialValue, selectedValue, testID }: WheelPickerProps): JSX.Element;
alignments: typeof WheelPickerAlign;
};
export default WheelPicker;
25 changes: 23 additions & 2 deletions src/incubator/WheelPicker/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback, useMemo, memo} from 'react';
import {TextStyle, StyleSheet} from 'react-native';
import Animated, {interpolateColor, useAnimatedStyle} from 'react-native-reanimated';
import Text from '../../components/text';
import Text, {TextProps} from '../../components/text';
import TouchableOpacity from '../../components/touchableOpacity';
import {Colors, Spacings} from '../../../src/style';

Expand All @@ -10,6 +10,9 @@ const AnimatedText = Animated.createAnimatedComponent(Text);

export interface ItemProps {
label: string;
fakeLabel?: string;
fakeLabelStyle?: TextStyle;
fakeLabelProps?: TextProps;
value: string | number;
}

Expand All @@ -28,6 +31,9 @@ interface InternalProps extends ItemProps {
export default memo(({
index,
label,
fakeLabel,
fakeLabelStyle,
fakeLabelProps,
itemHeight,
onSelect,
offset,
Expand Down Expand Up @@ -63,16 +69,31 @@ export default memo(({
// @ts-ignore reanimated2
index={index}
testID={testID}
row
>
<AnimatedText text60R style={[animatedColorStyle, style]}>
<AnimatedText
text60R
style={[animatedColorStyle, style, fakeLabel ? styles.textWithLabelPadding : styles.textPadding]}
>
{label}
</AnimatedText>
{fakeLabel && (
<Text marginL-s2 marginR-s5 text80M color={'white'} {...fakeLabelProps} style={fakeLabelStyle}>
{fakeLabel}
</Text>
)}
</AnimatedTouchableOpacity>
);
});

const styles = StyleSheet.create({
container: {
minWidth: Spacings.s10
},
textPadding: {
paddingHorizontal: Spacings.s5
},
textWithLabelPadding: {
paddingLeft: Spacings.s5
}
});
72 changes: 60 additions & 12 deletions src/incubator/WheelPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import Text, {TextProps} from '../../components/text';

const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);

enum WheelPickerAlign {
CENTER = 'center',
RIGHT = 'right',
LEFT = 'left'
}

export interface WheelPickerProps {
/**
* Initial value (doesn't work with selectedValue)
Expand Down Expand Up @@ -72,10 +78,14 @@ export interface WheelPickerProps {
* Support passing items as children props
*/
children?: JSX.Element | JSX.Element[];
/**
* Align the content to center, right ot left (default: center)
*/
align?: WheelPickerAlign;
testID?: string;
}

const WheelPicker = React.memo(({
const WheelPicker = ({
items: propItems,
itemHeight = 44,
numberOfVisibleRows = 5,
Expand All @@ -86,6 +96,7 @@ const WheelPicker = React.memo(({
labelStyle,
labelProps,
onChange,
align,
style,
children,
initialValue,
Expand Down Expand Up @@ -115,6 +126,7 @@ const WheelPicker = React.memo(({

const prevIndex = useRef(currentIndex);
const [scrollOffset, setScrollOffset] = useState(currentIndex * itemHeight);
const [flatListWidth, setFlatListWidth] = useState(0);
const keyExtractor = useCallback((item: ItemProps, index: number) => `${item}.${index}`, []);

/* This effect enforce the index to be controlled by selectedValue passed by the user */
Expand Down Expand Up @@ -168,6 +180,14 @@ const WheelPicker = React.memo(({
},
[onChange]);

const alignmentStyle = useMemo(() =>
align === WheelPickerAlign.RIGHT
? {alignSelf: 'flex-end'}
: align === WheelPickerAlign.LEFT
? {alignSelf: 'flex-start'}
: {alignSelf: 'center'},
[align]);

const renderItem = useCallback(({item, index}) => {
return (
<Item
Expand All @@ -178,6 +198,9 @@ const WheelPicker = React.memo(({
inactiveColor={inactiveTextColor}
style={textStyle}
{...item}
fakeLabel={label}
fakeLabelStyle={labelStyle}
fakeLabelProps={labelProps}
centerH={!label}
onSelect={selectItem}
testID={`${testID}.item_${index}`}
Expand All @@ -194,15 +217,22 @@ const WheelPicker = React.memo(({
);
}, []);

const labelContainerStyle = useMemo(() => {
return [{position: 'absolute', top: 0, bottom: 0}, alignmentStyle];
}, [alignmentStyle]);

const labelContainer = useMemo(() => {
return (
<View centerV>
<Text marginL-s2 text80M {...labelProps} color={activeTextColor} style={labelStyle}>
{label}
</Text>
// @ts-expect-error
<View style={labelContainerStyle} width={flatListWidth} pointerEvents="none">
<View style={styles.label} centerV pointerEvents="none">
<Text marginL-s2 marginR-s5 text80M {...labelProps} color={activeTextColor} style={labelStyle}>
{label}
</Text>
</View>
</View>
);
}, []);
}, [flatListWidth, labelContainerStyle, label, labelProps, activeTextColor, labelStyle]);

const fader = useMemo(() => (position: FaderPosition) => {
return <Fader visible position={position} size={60}/>;
Expand All @@ -214,14 +244,23 @@ const WheelPicker = React.memo(({
},
[itemHeight]);

const updateFlatListWidth = useCallback((width: number) => {
setFlatListWidth(width);
}, []);

const contentContainerStyle = useMemo(() => {
return {paddingVertical: height / 2 - itemHeight / 2};
}, [height, itemHeight]);
return [
{
paddingVertical: height / 2 - itemHeight / 2
},
alignmentStyle
];
}, [height, itemHeight, alignmentStyle]);

return (
<View testID={testID} bg-white style={style}>
<View row marginH-s5 centerH>
<View>
<View row centerH>
<View flexG>
<AnimatedFlatList
testID={`${testID}.list`}
height={height}
Expand All @@ -235,23 +274,26 @@ const WheelPicker = React.memo(({
onLayout={scrollToPassedIndex}
// @ts-ignore
ref={scrollView}
// @ts-expect-error
contentContainerStyle={contentContainerStyle}
snapToInterval={itemHeight}
decelerationRate={Constants.isAndroid ? 0.98 : 'normal'}
renderItem={renderItem}
getItemLayout={getItemLayout}
initialScrollIndex={currentIndex}
onContentSizeChange={updateFlatListWidth}
/>
</View>
{label && labelContainer}
</View>
{label && labelContainer}
{fader(FaderPosition.BOTTOM)}
{fader(FaderPosition.TOP)}
{separators}
</View>
);
});
};

WheelPicker.alignments = WheelPickerAlign;
export default WheelPicker;

const styles = StyleSheet.create({
Expand All @@ -260,5 +302,11 @@ const styles = StyleSheet.create({
borderBottomWidth: 1,
height: Spacings.s9,
borderColor: Colors.grey60
},
label: {
position: 'absolute',
right: 0,
top: 0,
bottom: 0
}
});

0 comments on commit 3dafa66

Please sign in to comment.