Skip to content

Commit

Permalink
fix: change timepicker bumped version to 2.0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
farhoudshapouran committed May 26, 2024
1 parent b30f154 commit e7d9364
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 249 deletions.
48 changes: 25 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,29 +99,31 @@ For more, take a look at the `/example` directory.

## Styling props

| Name | Type | Default | Description |
| ------------------------ | ----------- | ----------- | --------------------------------------------------------------------------------------- |
| calendarTextStyle | `TextStyle` | `null` | Defines all text styles inside the calendar (Days, Months, Years, Hours, and Minutes) |
| selectedTextStyle | `TextStyle` | `null` | Defines selected (Day, Month, Year) text styles |
| selectedItemColor | `string` | `'#0047FF'` | Defines selected (Day, Month, Year) background and border colors |
| headerContainerStyle | `ViewStyle` | `null` | Defines calendar header container style |
| headerTextContainerStyle | `ViewStyle` | `null` | Defines calendar header texts (Month, Year, Time) containers style |
| headerTextStyle | `TextStyle` | `null` | Defines calendar header text styles (Month, Year, Time) |
| headerButtonStyle | `ViewStyle` | `null` | Defines calendar header "prev and next buttons" containers style |
| headerButtonColor | `string` | `null` | Defines calendar header "prev and next buttons" icon color |
| headerButtonSize | `number` | `18` | Defines calendar header "prev and next buttons" icon size |
| headerButtonsPosition | `string` | `'around'` | Defines calendar header "prev and next buttons" positions `['around', 'right', 'left']` |
| buttonPrevIcon | `ReactNode` | `undefined` | Defines calendar header "prev button" custom icon |
| buttonNextIcon | `ReactNode` | `undefined` | Defines calendar header "next button" custom icon |
| dayContainerStyle | `ViewStyle` | `null` | Defines days containers style |
| todayContainerStyle | `ViewStyle` | `null` | Defines today container style |
| todayTextStyle | `TextStyle` | `null` | Defines today text style |
| monthContainerStyle | `ViewStyle` | `null` | Defines months containers style |
| yearContainerStyle | `ViewStyle` | `null` | Defines years containers style |
| weekDaysContainerStyle | `ViewStyle` | `null` | Defines weekdays container style |
| weekDaysTextStyle | `TextStyle` | `null` | Defines weekdays texts style |
| timePickerContainerStyle | `ViewStyle` | `null` | Defines time picker container style |
| timePickerTextStyle | `TextStyle` | `null` | Defines time picker (Hours, Minutes) texts style |
| Name | Type | Default | Description |
| -------------------------- | ------------------------------ | ----------- | --------------------------------------------------------------------------------------------- |
| calendarTextStyle | `TextStyle` | `null` | Defines all text styles inside the calendar (Days, Months, Years, Hours, and Minutes) |
| selectedTextStyle | `TextStyle` | `null` | Defines selected (Day, Month, Year) text styles |
| selectedItemColor | `string` | `'#0047FF'` | Defines selected (Day, Month, Year) background and border colors |
| headerContainerStyle | `ViewStyle` | `null` | Defines calendar header container style |
| headerTextContainerStyle | `ViewStyle` | `null` | Defines calendar header texts (Month, Year, Time) containers style |
| headerTextStyle | `TextStyle` | `null` | Defines calendar header text styles (Month, Year, Time) |
| headerButtonStyle | `ViewStyle` | `null` | Defines calendar header "prev and next buttons" containers style |
| headerButtonColor | `string` | `null` | Defines calendar header "prev and next buttons" icon color |
| headerButtonSize | `number` | `18` | Defines calendar header "prev and next buttons" icon size |
| headerButtonsPosition | `string` | `'around'` | Defines calendar header "prev and next buttons" positions `['around', 'right', 'left']` |
| buttonPrevIcon | `ReactNode` | `undefined` | Defines calendar header "prev button" custom icon |
| buttonNextIcon | `ReactNode` | `undefined` | Defines calendar header "next button" custom icon |
| dayContainerStyle | `ViewStyle` | `null` | Defines days containers style |
| todayContainerStyle | `ViewStyle` | `null` | Defines today container style |
| todayTextStyle | `TextStyle` | `null` | Defines today text style |
| monthContainerStyle | `ViewStyle` | `null` | Defines months containers style |
| yearContainerStyle | `ViewStyle` | `null` | Defines years containers style |
| weekDaysContainerStyle | `ViewStyle` | `null` | Defines weekdays container style |
| weekDaysTextStyle | `TextStyle` | `null` | Defines weekdays texts style |
| timePickerContainerStyle | `ViewStyle` | `null` | Defines time picker container style |
| timePickerTextStyle | `TextStyle` | `null` | Defines time picker (Hours, Minutes) texts style |
| timePickerIndicatorStyle | `ViewStyle` | `null` | Defines selected time indicator style |
| timePickerDecelerationRate | `'normal'`, `'fast'`, `number` | `'fast'` | Defines how quickly the underlying scroll view decelerates after the user lifts their finger. |

## Contributing

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-ui-datepicker",
"version": "2.0.2",
"version": "2.0.3",
"description": "Customizable date picker for React Native",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down Expand Up @@ -174,6 +174,7 @@
"dependencies": {
"dayjs": "^1.11.10",
"lodash": "^4.17.21",
"react-native-wheely": "^0.6.0",
"uninstall": "^0.0.0"
}
}
215 changes: 12 additions & 203 deletions src/components/TimePicker/Wheel.tsx
Original file line number Diff line number Diff line change
@@ -1,209 +1,18 @@
import {
Animated,
PanResponder,
StyleSheet,
TextStyle,
View,
ViewStyle,
Platform,
} from 'react-native';
import React, { memo, useMemo, useRef } from 'react';
import { sin } from './AnimatedMath';
import { CALENDAR_HEIGHT } from '../../enums';
import React from 'react';
import { Platform } from 'react-native';
import WheelNative from './WheelNative';
import WheelWeb from './WheelWeb';

export interface WheelStyleProps {
containerStyle?: ViewStyle;
itemHeight?: number;
selectedColor?: string;
disabledColor?: string;
textStyle?: TextStyle;
wheelHeight?: number;
displayCount?: number;
}

export interface WheelProps extends WheelStyleProps {
interface WheelProps {
value: number;
setValue?: (value: number) => void;
items: number[];
items: string[];
}

const Wheel = ({
value,
setValue = () => {},
items,
containerStyle,
textStyle,
itemHeight,
selectedColor = 'black',
disabledColor = 'gray',
wheelHeight,
displayCount = 5,
}: WheelProps) => {
const translateY = useRef(new Animated.Value(0)).current;
const renderCount =
displayCount * 2 < items.length ? displayCount * 8 : displayCount * 2 - 1;
const circular = items.length >= displayCount;
const height =
typeof containerStyle?.height === 'number' ? containerStyle.height : 130;
const radius = wheelHeight != null ? wheelHeight / 2 : height / 2;

const valueIndex = useMemo(() => items.indexOf(value), [items, value]);

const panResponder = useMemo(() => {
return PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onPanResponderGrant: () => {
translateY.setValue(0);
},
onPanResponderMove: (evt, gestureState) => {
translateY.setValue(gestureState.dy);
evt.stopPropagation();
},
onPanResponderRelease: (_, gestureState) => {
translateY.extractOffset();
let newValueIndex =
valueIndex -
Math.round(gestureState.dy / ((radius * 2) / displayCount));
if (circular) {
newValueIndex = (newValueIndex + items.length) % items.length;
} else {
if (newValueIndex < 0) {
newValueIndex = 0;
} else if (newValueIndex >= items.length) {
newValueIndex = items.length - 1;
}
}
const newValue = items[newValueIndex] || 0;
if (newValue === value) {
translateY.setOffset(0);
translateY.setValue(0);
} else {
setValue(newValue);
}
},
});
}, [
circular,
displayCount,
radius,
setValue,
value,
valueIndex,
items,
translateY,
]);

const displayValues = useMemo(() => {
const centerIndex = Math.floor(renderCount / 2);

return Array.from({ length: renderCount }, (_, index) => {
let targetIndex = valueIndex + index - centerIndex;
if (targetIndex < 0 || targetIndex >= items.length) {
if (!circular) {
return 0;
}
targetIndex = (targetIndex + items.length) % items.length;
}
return items[targetIndex] || 0;
});
}, [renderCount, valueIndex, items, circular]);

const animatedAngles = useMemo(() => {
//translateY.setValue(0);
translateY.setOffset(0);
const currentIndex = displayValues.indexOf(value);
return displayValues && displayValues.length > 0
? displayValues.map((_, index) =>
translateY
.interpolate({
inputRange: [-radius, radius],
outputRange: [
-radius +
((radius * 2) / displayCount) * (index - currentIndex),
radius + ((radius * 2) / displayCount) * (index - currentIndex),
],
extrapolate: 'extend',
})
.interpolate({
inputRange: [-radius, radius],
outputRange: [-Math.PI / 2, Math.PI / 2],
extrapolate: 'clamp',
})
)
: [];
}, [displayValues, radius, value, displayCount, translateY]);

return (
<View
style={[styles.container, containerStyle]}
{...panResponder.panHandlers}
>
{displayValues?.map((displayValue, index) => {
const animatedAngle = animatedAngles[index];
return (
<Animated.Text
key={`${displayValue}-${index}`}
style={[
textStyle,
// eslint-disable-next-line react-native/no-inline-styles
{
position: 'absolute',
height: itemHeight,
transform: animatedAngle
? [
{
translateY: Animated.multiply(
radius,
sin(animatedAngle)
),
},
{
rotateX: animatedAngle.interpolate({
inputRange: [-Math.PI / 2, Math.PI / 2],
outputRange: ['-89deg', '89deg'],
extrapolate: 'clamp',
}),
},
]
: [],
color: displayValue === value ? selectedColor : disabledColor,
},
]}
>
{typeof displayValue === 'number' && displayValue < 10
? `0${displayValue}`
: `${displayValue}`}
</Animated.Text>
);
})}
</View>
);
};

const styles = StyleSheet.create({
container: {
minWidth: 30,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center',
height: CALENDAR_HEIGHT / 2,
...Platform.select({
web: {
cursor: 'pointer',
userSelect: 'none',
},
}),
},
contentContainer: {
justifyContent: 'space-between',
alignItems: 'center',
},
});

export default memo(Wheel, (prevProps, nextProps) => {
return (
prevProps.value === nextProps.value &&
prevProps.setValue === nextProps.setValue
export default function Wheel(props: WheelProps) {
return Platform.OS === 'web' ? (
<WheelWeb {...props} />
) : (
<WheelNative {...props} />
);
});
}
52 changes: 52 additions & 0 deletions src/components/TimePicker/WheelNative.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { StyleSheet, Platform } from 'react-native';
import WheelPicker from 'react-native-wheely';
import { useCalendarContext } from '../../CalendarContext';

interface WheelProps {
value: number;
setValue?: (value: number) => void;
items: string[];
}

export default function WheelNative({
value,
setValue = () => {},
items,
}: WheelProps) {
const { theme } = useCalendarContext();

return (
<WheelPicker
selectedIndex={value}
options={items}
onChange={setValue}
containerStyle={{
...styles.container,
...theme?.timePickerContainerStyle,
}}
itemTextStyle={{
...styles.timePickerText,
...theme?.timePickerTextStyle,
}}
selectedIndicatorStyle={{ ...theme?.timePickerIndicatorStyle }}
itemHeight={45}
decelerationRate={theme?.timePickerDecelerationRate}
/>
);
}

const styles = StyleSheet.create({
container: {
display: 'flex',
...Platform.select({
web: {
userSelect: 'none',
},
}),
},
timePickerText: {
fontSize: 24,
fontWeight: 'bold',
},
});
Loading

0 comments on commit e7d9364

Please sign in to comment.