Skip to content

Instantly share code, notes, and snippets.

@AspireOne
Last active September 28, 2024 19:48
Show Gist options
  • Save AspireOne/a5f80737b7675794a7eff6d1aa7a1a1d to your computer and use it in GitHub Desktop.
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.
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}
/>
);
}
};
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