@tchesa/react-native-modern-datepicker
Version:
A customizable calendar, time & month picker for React Native (including Persian Jalaali calendar & locale)
198 lines • 8.23 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from 'react';
import { View, StyleSheet, Text, Animated, FlatList, Easing, TouchableOpacity, I18nManager, } from 'react-native';
import { useCalendar } from '../DatePicker';
const AnimatedFlatList = Animated.createAnimatedComponent((FlatList));
const TimeScroller = ({ title, data, onChange, }) => {
const { options, utils } = useCalendar();
const [itemSize, setItemSize] = useState(0);
const style = styles(options);
const scrollAnimatedValue = useRef(new Animated.Value(0)).current;
const scrollListener = useRef();
const active = useRef(0);
data = ['', '', ...data, '', ''];
useEffect(() => {
if (scrollListener.current !== undefined) {
clearInterval(parseInt(scrollListener.current));
}
scrollListener.current = scrollAnimatedValue.addListener(({ value }) => (active.current = value));
return () => {
if (scrollListener.current !== undefined) {
clearInterval(parseInt(scrollListener.current));
}
};
}, [scrollAnimatedValue]);
const changeItemWidth = ({ nativeEvent }) => {
const { width } = nativeEvent.layout;
!itemSize && setItemSize(width / 5);
};
const renderItem = ({ item, index }) => {
const makeAnimated = (a, b, c) => {
return {
inputRange: [...data.map((_, i) => i * itemSize)],
outputRange: [
...data.map((_, i) => {
const center = i + 2;
if (center === index) {
return a;
}
else if (center + 1 === index || center - 1 === index) {
return b;
}
else {
return c;
}
}),
],
};
};
return (_jsx(Animated.View, { style: [
{
width: itemSize,
opacity: scrollAnimatedValue.interpolate(makeAnimated(1, 0.6, 0.3)),
transform: [
{
scale: scrollAnimatedValue.interpolate(makeAnimated(1.2, 0.9, 0.8)),
},
{
scaleX: I18nManager.isRTL ? -1 : 1,
},
],
},
style.listItem,
], children: _jsx(Text, { style: style.listItemText, children: utils.toPersianNumber(String(item).length === 1 ? '0' + item : item) }) }));
};
return (_jsxs(View, { style: style.row, onLayout: changeItemWidth, children: [_jsx(Text, { style: style.title, children: title }), _jsx(AnimatedFlatList, { pagingEnabled: true, showsHorizontalScrollIndicator: false, horizontal: true, snapToInterval: itemSize, decelerationRate: 'fast', onScroll: Animated.event([{ nativeEvent: { contentOffset: { x: scrollAnimatedValue } } }], {
useNativeDriver: true,
}), data: I18nManager.isRTL ? data.reverse() : data, onMomentumScrollEnd: () => {
const index = Math.round(active.current / itemSize);
onChange(data[index + 2]);
}, keyExtractor: (_, i) => String(i), renderItem: renderItem, inverted: I18nManager.isRTL, contentContainerStyle: I18nManager.isRTL && {
transform: [
{
scaleX: -1,
},
],
} })] }));
};
const SelectTime = () => {
const { options, state, utils, mode, minuteInterval, onTimeChange } = useCalendar();
const [mainState, setMainState] = state;
const [show, setShow] = useState(false);
const [time, setTime] = useState({
minute: 0,
hour: 0,
});
const style = styles(options);
const openAnimation = useRef(new Animated.Value(0)).current;
useEffect(() => {
show &&
setTime({
minute: 0,
hour: 0,
});
}, [show]);
useEffect(() => {
mainState.timeOpen && setShow(true);
Animated.timing(openAnimation, {
toValue: mainState.timeOpen ? 1 : 0,
duration: 350,
useNativeDriver: true,
easing: Easing.bezier(0.17, 0.67, 0.46, 1),
}).start(() => {
!mainState.timeOpen && setShow(false);
});
}, [mainState.timeOpen, openAnimation]);
const selectTime = () => {
const newTime = utils.getDate(mainState.activeDate);
newTime.hour(time.hour).minute(time.minute);
setMainState({
type: 'set',
activeDate: utils.getFormated(newTime),
selectedDate: mainState.selectedDate
? utils.getFormated(utils
.getDate(mainState.selectedDate)
.hour(time.hour)
.minute(time.minute))
: '',
});
onTimeChange === null || onTimeChange === void 0 ? void 0 : onTimeChange(utils.getFormated(newTime, 'timeFormat'));
mode !== 'time' &&
setMainState({
type: 'toggleTime',
});
};
const containerStyle = [
style.container,
{
opacity: openAnimation,
transform: [
{
scale: openAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1.1, 1],
}),
},
],
},
];
return show ? (_jsxs(Animated.View, { style: containerStyle, children: [_jsx(TimeScroller, { title: utils.config.hour, data: Array.from({ length: 24 }, (_, i) => i).map(String), onChange: hour => setTime(Object.assign(Object.assign({}, time), { hour: parseInt(hour) })) }), _jsx(TimeScroller, { title: utils.config.minute, data: Array.from({ length: 60 / minuteInterval }, (_, i) => i * minuteInterval).map(String), onChange: minute => setTime(Object.assign(Object.assign({}, time), { minute: parseInt(minute) })) }), _jsxs(View, { style: style.footer, children: [_jsx(TouchableOpacity, { style: style.button, activeOpacity: 0.8, onPress: selectTime, children: _jsx(Text, { style: style.btnText, children: utils.config.timeSelect }) }), mode !== 'time' && (_jsx(TouchableOpacity, { style: [style.button, style.cancelButton], onPress: () => setMainState({
type: 'toggleTime',
}), activeOpacity: 0.8, children: _jsx(Text, { style: style.btnText, children: utils.config.timeClose }) }))] })] })) : null;
};
const styles = (theme) => StyleSheet.create({
container: {
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
right: 0,
backgroundColor: theme.backgroundColor,
borderRadius: 10,
flexDirection: 'column',
justifyContent: 'center',
zIndex: 999,
},
row: {
flexDirection: 'column',
alignItems: 'center',
marginVertical: 5,
},
title: {
fontSize: theme.textHeaderFontSize,
color: theme.mainColor,
fontFamily: theme.headerFont,
},
listItem: {
height: 60,
alignItems: 'center',
justifyContent: 'center',
},
listItemText: {
fontSize: theme.textHeaderFontSize,
color: theme.textDefaultColor,
fontFamily: theme.defaultFont,
},
footer: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 15,
},
button: {
paddingVertical: 10,
paddingHorizontal: 25,
borderRadius: 8,
backgroundColor: theme.mainColor,
margin: 8,
},
btnText: {
fontSize: theme.textFontSize,
color: theme.selectedTextColor,
fontFamily: theme.defaultFont,
},
cancelButton: {
backgroundColor: theme.textSecondaryColor,
},
});
export { SelectTime };
//# sourceMappingURL=SelectTime.js.map