-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: change timepicker bumped version to 2.0.3
- Loading branch information
1 parent
b30f154
commit e7d9364
Showing
8 changed files
with
298 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} /> | ||
); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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', | ||
}, | ||
}); |
Oops, something went wrong.