Last active
September 28, 2024 19:48
-
-
Save AspireOne/a5f80737b7675794a7eff6d1aa7a1a1d to your computer and use it in GitHub Desktop.
React Native DateTimePicker that is compatible with both iOS and android. The iOS version has an additional Modal wrapper around the DateTimePicker itself.
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
import * as React from "react"; | |
import { Platform } from "react-native"; | |
import DateTimePicker, { | |
AndroidNativeProps, | |
type IOSNativeProps, | |
} from "@react-native-community/datetimepicker"; | |
import { DateTimePickerModal } from "@/components/DateTimePickerModal"; | |
type CustomProps = { | |
iosModalLabel: React.ReactNode; | |
visible: boolean; | |
close: () => void; | |
}; | |
type iOSProps = IOSNativeProps; | |
type AndroidProps = AndroidNativeProps; | |
type Props = (iOSProps | AndroidProps) & CustomProps; | |
/** | |
* DateTimePicker that works on both iOS and Android. | |
* @param props | |
* @constructor | |
*/ | |
export const CompatDateTimePicker = (props: Props) => { | |
const { iosModalLabel, onChange, visible, close, display, ...rest } = props; | |
function _onChange(e: any, selected: any) { | |
if (Platform.OS === "android") close(); | |
onChange?.(e, selected); | |
} | |
if (Platform.OS === "android") { | |
return ( | |
visible && ( | |
<DateTimePicker | |
onChange={_onChange} | |
display={display ?? ("default" as any)} | |
{...rest} | |
/> | |
) | |
); | |
} else { | |
return ( | |
<DateTimePickerModal | |
title={iosModalLabel} | |
visible={visible} | |
close={close} | |
onChange={_onChange} | |
display={display ?? ("spinner" as any)} | |
{...rest} | |
/> | |
); | |
} | |
}; |
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
import * as React from "react"; | |
import { Modal, Platform, StyleSheet, Text, TouchableOpacity, View } from "react-native"; | |
import { Trans } from "@lingui/macro"; | |
import type { IOSNativeProps } from "@react-native-community/datetimepicker"; | |
import DateTimePicker, { | |
AndroidNativeProps, | |
} from "@react-native-community/datetimepicker"; | |
import { colors } from "@/ui"; | |
type CustomProps = { | |
visible: boolean; | |
close: () => void; | |
title: React.ReactNode; | |
}; | |
/** | |
* A modal version of a DateTimePicker. Useful for iOS, where the native DateTimePicker | |
* alone is buggy. | |
* @param props | |
* @constructor | |
*/ | |
export const DateTimePickerModal = ( | |
props: IOSNativeProps & CustomProps /*| (AndroidNativeProps & CustomProps)*/, | |
) => { | |
const { mode, display, style, title, ...rest } = props; | |
return ( | |
<Modal | |
visible={props.visible} | |
transparent={true} | |
animationType="fade" | |
onRequestClose={props.close} | |
> | |
<View style={styles.modalOverlay}> | |
<View style={styles.modalContainer}> | |
<Text style={styles.modalTitle}>{title}</Text> | |
<DateTimePicker | |
mode={mode || "time"} | |
display={display || "spinner"} // calendar, compact... | |
style={[styles.picker, style]} | |
{...rest} | |
/> | |
<View style={styles.modalButtons}> | |
<TouchableOpacity style={styles.modalButton} onPress={props.close}> | |
<Text style={styles.modalButtonText}> | |
<Trans>Zrušit</Trans> | |
</Text> | |
</TouchableOpacity> | |
<TouchableOpacity style={styles.modalButton} onPress={props.close}> | |
<Text style={styles.modalButtonText}> | |
<Trans>Potvrdit</Trans> | |
</Text> | |
</TouchableOpacity> | |
</View> | |
</View> | |
</View> | |
</Modal> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
modalOverlay: { | |
flex: 1, | |
backgroundColor: "rgba(0,0,0,0.5)", | |
justifyContent: "flex-end", | |
}, | |
modalContainer: { | |
backgroundColor: "white", | |
paddingTop: 20, | |
paddingBottom: Platform.OS === "ios" ? 40 : 20, | |
paddingHorizontal: 20, | |
borderTopLeftRadius: 20, | |
borderTopRightRadius: 20, | |
}, | |
modalTitle: { | |
fontSize: 18, | |
fontWeight: "bold", | |
textAlign: "center", | |
marginBottom: 10, | |
}, | |
picker: { | |
backgroundColor: "white", | |
}, | |
modalButtons: { | |
flexDirection: "row", | |
justifyContent: "space-around", | |
marginTop: 10, | |
}, | |
modalButton: { | |
padding: 10, | |
}, | |
modalButtonText: { | |
color: colors.primary[500], | |
fontSize: 16, | |
fontWeight: "bold", | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment