diff --git a/README.md b/README.md index 68a4a40f..6c68ff39 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,9 @@ See this [issue](https://github.com/react-native-datetimepicker/datetimepicker/i This repository was moved out of the react native community GH organization, in accordance to [this proposal](https://github.com/react-native-community/discussions-and-proposals/issues/176). The module is still published on `npm` under the old namespace (as documented) but will be published under a new namespace at some point, with a major version bump. -![CircleCI Status][circle-ci-status] +[![npm downloads][npm-downloads-badge]][npm-downloads-link] ![Supports Android and iOS][support-badge] ![MIT License][license-badge] -[![Lean Core Badge][lean-core-badge]][lean-core-issue] React Native date & time picker component for iOS, Android and Windows (please note Windows is not actively maintained). @@ -74,28 +73,30 @@ React Native date & time picker component for iOS, Android and Windows (please n - [Expo users notice](#expo-users-notice) - [Getting started](#getting-started) - [Usage](#usage) - - [React Native Support](#react-native-support) - [Localization note](#localization-note) - [Android imperative API](#android-imperative-api) - [Android styling](#android-styling) - [Props / params](#component-props--params-of-the-android-imperative-api) - [`mode` (`optional`)](#mode-optional) - [`display` (`optional`)](#display-optional) - - [`design` (`optional`, `Android only`)](#design-optional) + - [`design` (`optional`, `Android only`)](#design-optional-android-only) - [`initialInputMode` (`optional`, `Android only`)](#initialinputmode-optional-android-only) - [`title` (`optional`, `Android only`)](#title-optional-android-only) - [`fullscreen` (`optional`, `Android only`)](#fullscreen-optional-android-only) - [`startOnYearSelection` (`optional`, `Android only`)](#startOnYearSelection-optional-android-only) - - [`onChange` (`optional`)](#onchange-optional) + - [`onValueChange` (`optional`)](#onvaluechange-optional) + - [`onDismiss` (`optional`)](#ondismiss-optional) + - [`onNeutralButtonPress` (`optional`, `Android only`)](#onneutralbuttonpress-optional-android-only) + - [`onChange` (`optional`, `deprecated`)](#onchange-optional-deprecated) - [`value` (`required`)](#value-required) - [`maximumDate` (`optional`)](#maximumdate-optional) - [`minimumDate` (`optional`)](#minimumdate-optional) - [`timeZoneName` (`optional`, `iOS or Android only`)](#timeZoneName-optional-ios-and-android-only) - [`timeZoneOffsetInMinutes` (`optional`, `iOS or Android only`)](#timezoneoffsetinminutes-optional-ios-and-android-only) - - [`timeZoneOffsetInSeconds` (`optional`, `Windows only`)](#timezoneoffsetinsecond-optional-windows-only) + - [`timeZoneOffsetInSeconds` (`optional`, `Windows only`)](#timezoneoffsetinseconds-optional-windows-only) - [`dayOfWeekFormat` (`optional`, `Windows only`)](#dayOfWeekFormat-optional-windows-only) - [`dateFormat` (`optional`, `Windows only`)](#dateFormat-optional-windows-only) - - [`firstDayOfWeek` (`optional`, `Windows only`)](#firstDayOfWeek-optional-windows-only) + - [`firstDayOfWeek` (`optional`, `Android and Windows only`)](#firstdayofweek-optional-android-and-windows-only) - [`textColor` (`optional`, `iOS only`)](#textColor-optional-ios-only) - [`accentColor` (`optional`, `iOS only`)](#accentColor-optional-ios-only) - [`themeVariant` (`optional`, `iOS only`)](#themevariant-optional-ios-only) @@ -117,15 +118,12 @@ React Native date & time picker component for iOS, Android and Windows (please n ## Requirements -- Only Android API level >=21 (Android 5), iOS >= 11 are supported. -- Tested with Xcode 14.0 and RN 0.72.7. Other configurations are very likely to work as well but have not been tested. - -The module supports the [new React Native architecture](https://reactnative.dev/docs/next/the-new-architecture/why) (Fabric rendering of iOS components, and turbomodules on Android). If you are using the new architecture, you will need to use React Native 0.71.4 or higher. +The module supports the [new React Native architecture](https://reactnative.dev/docs/next/the-new-architecture/why) (Fabric rendering of iOS components, and turbomodules on Android). ## Expo users notice -This module is part of Expo Managed Workflow - [see docs](https://docs.expo.io/versions/latest/sdk/date-time-picker/). However, Expo SDK in the Managed Workflow may not contain the latest version of the module and therefore, the newest features and bugfixes may not be available in Expo Managed Workflow. -If you use the Managed Workflow, use the command `expo install @react-native-community/datetimepicker` (not `yarn` or `npm`) to install this module - Expo will automatically install the latest version compatible with your Expo SDK (which may _not_ be the latest version of the module available). +This module is part of Expo Go - [see docs](https://docs.expo.io/versions/latest/sdk/date-time-picker/). However, Expo Go may not contain the latest version of the module and therefore, the newest features and bugfixes may not be available. +If you use Expo Go, use the command `npx expo install @react-native-community/datetimepicker` (not `yarn` or `npm`) to install this module - Expo will automatically install the latest version compatible with your Expo SDK (which may _not_ be the latest version of the module available). If you're using a [Dev Client](https://docs.expo.dev/development/create-development-builds/), rebuild the Dev Client after installing the dependencies. @@ -145,20 +143,7 @@ yarn add @react-native-community/datetimepicker Autolinking is not yet implemented on Windows, so [manual installation ](/docs/manual-installation.md) is needed. -#### RN >= 0.60 - -If you are using RN >= 0.60, only run `npx pod-install`. Then rebuild your project. - -## React Native Support - -Check the `react-native` version support table below to find the corresponding `datetimepicker` version to meet support requirements. Maintenance is only provided for last 3 stable react-native versions. - -| react-native version | version | -| -------------------- | ------- | -| 0.73.0+ | 7.6.3+ | -| <=0.72.0 | <=7.6.2 | -| 0.70.0+ | 7.0.1+ | -| <0.70.0 | <=7.0.0 | +On iOS, run `npx pod-install` after installing. Then rebuild your project. ## Usage @@ -181,15 +166,10 @@ Read more about the motivation in [Android imperative API](#android-imperative-a export const App = () => { const [date, setDate] = useState(new Date(1598051730000)); - const onChange = (event, selectedDate) => { - const currentDate = selectedDate; - setDate(currentDate); - }; - const showMode = (currentMode) => { DateTimePickerAndroid.open({ value: date, - onChange, + onValueChange: (event, selectedDate) => setDate(selectedDate), mode: currentMode, is24Hour: true, }); @@ -221,12 +201,6 @@ export const App = () => { const [mode, setMode] = useState('date'); const [show, setShow] = useState(false); - const onChange = (event, selectedDate) => { - const currentDate = selectedDate; - setShow(false); - setDate(currentDate); - }; - const showMode = (currentMode) => { setShow(true); setMode(currentMode); @@ -251,7 +225,8 @@ export const App = () => { value={date} mode={mode} is24Hour={true} - onChange={onChange} + onValueChange={(event, selectedDate) => setDate(selectedDate)} + onDismiss={() => setShow(false)} /> )} @@ -358,7 +333,36 @@ List of possible values ``` -#### `onChange` (`optional`) +#### `onValueChange` (`optional`) + +Called when the user selects a date or time. Receives an `event` with `nativeEvent: { timestamp, utcOffset }` and the selected `Date`. + +```js + setDate(date)} /> +``` + +#### `onDismiss` (`optional`) + +Called when the picker is dismissed without selecting a value. Receives no arguments. + +```js + setShow(false)} /> +``` + +#### `onNeutralButtonPress` (`optional`, `Android only`) + +Called when the neutral button is pressed. Receives no arguments. See [`neutralButton`](#neutralButton-optional-android-only). + +```js + clearDate()} +/> +``` + +#### `onChange` (`optional`, `deprecated`) + +> **Deprecated:** Use `onValueChange`, `onDismiss`, and `onNeutralButtonPress` instead. If the new specific listeners are provided, they take precedence over `onChange` for their respective event types. Date change handler. @@ -554,7 +558,7 @@ Set the positive button label and text color. #### `neutralButton` (`optional`, `Android only`) Allows displaying neutral button on picker dialog. -Pressing button can be observed in onChange handler as `event.type === 'neutralButtonPressed'` +Pressing the button can be observed via the [`onNeutralButtonPress`](#onneutralbuttonpress-optional-android-only) callback. ```js @@ -643,9 +647,7 @@ Please see [manual-installation.md](/docs/manual-installation.md) This project is tested with BrowserStack. -[circle-ci-badge]: https://img.shields.io/circleci/project/github/react-native-community/datetimepicker/master.svg?style=flat-square -[circle-ci-status]: https://circleci.com/gh/react-native-datetimepicker/datetimepicker.svg?style=svg +[npm-downloads-badge]: https://img.shields.io/npm/dm/@react-native-community/datetimepicker.svg?style=flat-square +[npm-downloads-link]: https://www.npmjs.com/package/@react-native-community/datetimepicker [support-badge]: https://img.shields.io/badge/platforms-android%20%7C%20ios%20%7C%20windows-lightgrey.svg?style=flat-square -[license-badge]: https://img.shields.io/npm/l/@react-native-community/slider.svg?style=flat-square -[lean-core-badge]: https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg?style=flat-square -[lean-core-issue]: https://github.com/facebook/react-native/issues/23313 +[license-badge]: https://img.shields.io/npm/l/@react-native-community/datetimepicker.svg?style=flat-square diff --git a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDateTimePickerPackage.java b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDateTimePickerPackage.java index 7b9274b9..bfab8277 100644 --- a/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDateTimePickerPackage.java +++ b/android/src/main/java/com/reactcommunity/rndatetimepicker/RNDateTimePickerPackage.java @@ -1,6 +1,7 @@ package com.reactcommunity.rndatetimepicker; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.react.BaseReactPackage; @@ -15,7 +16,7 @@ public class RNDateTimePickerPackage extends BaseReactPackage { @Nullable @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { + public NativeModule getModule(String name, @NonNull ReactApplicationContext reactContext) { if (name.equals(DatePickerModule.NAME)) { return new DatePickerModule(reactContext); } else if (name.equals(TimePickerModule.NAME)) { @@ -29,6 +30,7 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext) } } + @NonNull @Override public ReactModuleInfoProvider getReactModuleInfoProvider() { return () -> { @@ -61,7 +63,6 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { MaterialDatePickerModule.NAME, false, // canOverrideExistingModule false, // needsEagerInit - false, // hasConstants false, // isCxxModule isTurboModule // isTurboModule )); @@ -72,7 +73,6 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { MaterialTimePickerModule.NAME, false, // canOverrideExistingModule false, // needsEagerInit - false, // hasConstants false, // isCxxModule isTurboModule // isTurboModule )); diff --git a/example/App.js b/example/App.js index b6346e51..f984c6ed 100644 --- a/example/App.js +++ b/example/App.js @@ -138,29 +138,31 @@ export const App = () => { setDate(undefined); }; - const onChange = (event, selectedDate) => { + const onValueChange = (event, selectedDate) => { if (Platform.OS === 'android') { setShow(false); } - if (event.type === 'dismissed') { - Alert.alert( - 'picker was dismissed', - undefined, - [ - { - text: 'great', - }, - ], - {cancelable: true}, - ); - return; - } + setDate(selectedDate); + }; - if (event.type === 'neutralButtonPressed') { - setDate(new Date(0)); - } else { - setDate(selectedDate); + const onDismiss = () => { + if (Platform.OS === 'android') { + setShow(false); } + Alert.alert( + 'picker was dismissed', + undefined, + [ + { + text: 'great', + }, + ], + {cancelable: true}, + ); + }; + + const onNeutralButtonPress = () => { + setDate(new Date(0)); }; const onTimeChange = (event: any, newTime?: Date) => { @@ -523,7 +525,9 @@ export const App = () => { is24Hour locale="en-US" display={display} - onChange={onChange} + onValueChange={onValueChange} + onDismiss={onDismiss} + onNeutralButtonPress={onNeutralButtonPress} textColor={textColor || undefined} accentColor={accentColor || undefined} neutralButton={{label: neutralButtonLabel}} @@ -621,7 +625,7 @@ export const App = () => { { mode="time" value={time} style={{width: 300, opacity: 1, height: 30, marginTop: 50}} - onChange={onTimeChange} + onValueChange={onTimeChange} is24Hour={is24Hours} minuteInterval={interval} /> diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b75436ef..68a3bb83 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1810,7 +1810,7 @@ PODS: - React-Core - React-jsi - ReactTestApp-Resources (1.0.0-dev) - - RNDateTimePicker (8.6.0): + - RNDateTimePicker (9.0.0): - hermes-engine - RCTRequired - RCTTypeSafety @@ -2176,7 +2176,7 @@ SPEC CHECKSUMS: ReactNativeHost: 147a222a7c577801639023140b694160987738ef ReactTestApp-DevSupport: 0e7676c00b33b0545e72d89ea09f990d737db6d3 ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf - RNDateTimePicker: 9c0a849bbe1c256f0854fea255734b715f5ea876 + RNDateTimePicker: a8b45651bfa11872964f1439d1cae9a1712dc108 RNLocalize: 390c6e0c4061855a7bd7a91e21dd6a317b45c46c Yoga: 1f66b0bb07f6c5f0199562b772bfb2ac54cad91a diff --git a/src/DateTimePickerAndroid.android.js b/src/DateTimePickerAndroid.android.js index 8ed335b8..6f5bb3d2 100644 --- a/src/DateTimePickerAndroid.android.js +++ b/src/DateTimePickerAndroid.android.js @@ -25,6 +25,7 @@ import { createNeutralEvtParams, } from './eventCreators'; import {processColor} from 'react-native'; +import {warnIfOnChangeIsUsed} from './utils'; function open(props: AndroidNativeProps) { const { @@ -38,6 +39,9 @@ function open(props: AndroidNativeProps) { timeZoneOffsetInMinutes, timeZoneName, onChange, + onValueChange, + onDismiss, + onNeutralButtonPress, onError, positiveButton, negativeButton, @@ -51,6 +55,7 @@ function open(props: AndroidNativeProps) { startOnYearSelection, } = props; validateAndroidProps(props); + warnIfOnChangeIsUsed(onChange); invariant(originalValue, 'A date or time must be specified as `value` prop.'); const valueTimestamp = originalValue.getTime(); @@ -99,20 +104,32 @@ function open(props: AndroidNativeProps) { case DATE_SET_ACTION: case TIME_SET_ACTION: { const date = new Date(timestamp); - const [event] = createDateTimeSetEvtParams(date, utcOffset); - onChange?.(event, date); + if (onValueChange) { + onValueChange({nativeEvent: {timestamp, utcOffset}}, date); + } else { + const [event] = createDateTimeSetEvtParams(date, utcOffset); + onChange?.(event, date); + } break; } case NEUTRAL_BUTTON_ACTION: { - const [event] = createNeutralEvtParams(originalValue, utcOffset); - onChange?.(event, originalValue); + if (onNeutralButtonPress) { + onNeutralButtonPress(); + } else { + const [event] = createNeutralEvtParams(originalValue, utcOffset); + onChange?.(event, originalValue); + } break; } case DISMISS_ACTION: default: { - const [event] = createDismissEvtParams(originalValue, utcOffset); - onChange?.(event, originalValue); + if (onDismiss) { + onDismiss(); + } else { + const [event] = createDismissEvtParams(originalValue, utcOffset); + onChange?.(event, originalValue); + } break; } } diff --git a/src/datetimepicker.android.js b/src/datetimepicker.android.js index 3bf75f0b..8bea7d26 100644 --- a/src/datetimepicker.android.js +++ b/src/datetimepicker.android.js @@ -18,10 +18,13 @@ export default function RNDateTimePickerAndroid( display = ANDROID_DISPLAY.default, value, onChange, + onValueChange, is24Hour, minimumDate, maximumDate, minuteInterval, + onDismiss, + onNeutralButtonPress, onError, timeZoneOffsetInMinutes, timeZoneName, @@ -56,6 +59,9 @@ export default function RNDateTimePickerAndroid( minuteInterval, timeZoneOffsetInMinutes, timeZoneName, + onValueChange, + onDismiss, + onNeutralButtonPress, onError, onChange, positiveButton, @@ -75,7 +81,14 @@ export default function RNDateTimePickerAndroid( // as an alternative, use the DateTimePickerAndroid whose reason for existence is described in // https://github.com/react-native-datetimepicker/datetimepicker/pull/327#issuecomment-723160992 // eslint-disable-next-line react-hooks/exhaustive-deps - [onChange, valueTimestamp, mode], + [ + onChange, + onValueChange, + onDismiss, + onNeutralButtonPress, + valueTimestamp, + mode, + ], ); return null; diff --git a/src/datetimepicker.ios.js b/src/datetimepicker.ios.js index d8819f76..2925c161 100644 --- a/src/datetimepicker.ios.js +++ b/src/datetimepicker.ios.js @@ -10,7 +10,11 @@ * @flow strict-local */ import RNDateTimePicker from './picker'; -import {dateToMilliseconds, sharedPropsValidation} from './utils'; +import { + dateToMilliseconds, + sharedPropsValidation, + warnIfOnChangeIsUsed, +} from './utils'; import { IOS_DISPLAY, EVENT_TYPE_SET, @@ -55,41 +59,56 @@ export default function Picker({ accentColor, themeVariant, onChange, + onValueChange, + onDismiss: onDismissProp, mode = IOS_MODE.date, display: providedDisplay = IOS_DISPLAY.default, // $FlowFixMe[incompatible-type] disabled = false, ...other }: IOSNativeProps): React.Node { - sharedPropsValidation({value, timeZoneOffsetInMinutes, timeZoneName, minimumDate, maximumDate}); + sharedPropsValidation({ + value, + timeZoneOffsetInMinutes, + timeZoneName, + minimumDate, + maximumDate, + }); + warnIfOnChangeIsUsed(onChange); const display = getDisplaySafe(providedDisplay); const _onChange = (event: NativeEventIOS) => { const timestamp = event.nativeEvent.timestamp; - const unifiedEvent: DateTimePickerEvent = { - ...event, - type: EVENT_TYPE_SET, - }; - const date = timestamp !== undefined ? new Date(timestamp) : undefined; - onChange && onChange(unifiedEvent, date); + if (onValueChange && date) { + onValueChange(event, date); + } else if (onChange) { + const unifiedEvent: DateTimePickerEvent = { + ...event, + type: EVENT_TYPE_SET, + }; + onChange(unifiedEvent, date); + } }; const onDismiss = () => { - // TODO introduce separate onDismissed event listener - onChange && - onChange( - { - type: EVENT_TYPE_DISMISSED, - nativeEvent: { - timestamp: value.getTime(), - utcOffset: 0, // TODO vonovak - the dismiss event should not carry any date information + if (onDismissProp) { + onDismissProp(); + } else { + onChange && + onChange( + { + type: EVENT_TYPE_DISMISSED, + nativeEvent: { + timestamp: value.getTime(), + utcOffset: 0, + }, }, - }, - value, - ); + value, + ); + } }; return ( diff --git a/src/datetimepicker.windows.js b/src/datetimepicker.windows.js index 92b10ec1..ab14c93d 100644 --- a/src/datetimepicker.windows.js +++ b/src/datetimepicker.windows.js @@ -6,10 +6,7 @@ */ 'use strict'; -import { - requireNativeComponent, - StyleSheet, -} from 'react-native'; +import {requireNativeComponent, StyleSheet} from 'react-native'; import type { WindowsNativeProps, WindowsDatePickerChangeEvent, @@ -17,7 +14,7 @@ import type { } from './types'; import * as React from 'react'; import {EVENT_TYPE_SET, WINDOWS_MODE} from './constants'; -import {sharedPropsValidation} from './utils'; +import {sharedPropsValidation, warnIfOnChangeIsUsed} from './utils'; const styles = StyleSheet.create({ rnDatePicker: { @@ -38,6 +35,7 @@ export default function RNDateTimePickerQWE( props: WindowsNativeProps, ): React.Node { sharedPropsValidation({value: props?.value}); + warnIfOnChangeIsUsed(props.onChange); const localProps = { accessibilityLabel: props.accessibilityLabel, @@ -53,18 +51,23 @@ export default function RNDateTimePickerQWE( }; const _onChange = (event: WindowsDatePickerChangeEvent) => { - const {onChange} = props; - const unifiedEvent: DateTimePickerEvent = { - ...event, - nativeEvent: { - ...event.nativeEvent, - timestamp: event.nativeEvent.newDate, - utcOffset: 0, - }, - type: EVENT_TYPE_SET, - }; + const {onChange, onValueChange} = props; + const date = new Date(event.nativeEvent.newDate); - onChange && onChange(unifiedEvent, new Date(event.nativeEvent.newDate)); + if (onValueChange) { + onValueChange({nativeEvent: {timestamp: event.nativeEvent.newDate, utcOffset: 0}}, date); + } else if (onChange) { + const unifiedEvent: DateTimePickerEvent = { + ...event, + nativeEvent: { + ...event.nativeEvent, + timestamp: event.nativeEvent.newDate, + utcOffset: 0, + }, + type: EVENT_TYPE_SET, + }; + onChange(unifiedEvent, date); + } }; // $FlowFixMe[recursive-definition] diff --git a/src/index.d.ts b/src/index.d.ts index 451f3e63..423a7fab 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -26,6 +26,13 @@ export type DateTimePickerEvent = { }; }; +export type DateTimePickerChangeEvent = { + nativeEvent: { + timestamp: number; + utcOffset: number; + }; +}; + type BaseOptions = { /** * The currently selected date. @@ -33,12 +40,28 @@ type BaseOptions = { value: Date; /** - * Date change handler. + * @deprecated Use onValueChange, onDismiss, and onNeutralButtonPress instead. * - * This is called when the user changes the date or time in the UI. - * The first argument is an Event, the second a selected Date. + * Called when the user changes the date/time, dismisses the picker, + * or presses the neutral button. The event type is encoded in event.type. + * If the new specific listeners are provided, they take precedence. */ onChange?: (event: DateTimePickerEvent, date?: Date) => void; + + /** + * Called when the user selects a date or time. + */ + onValueChange?: (event: DateTimePickerChangeEvent, date: Date) => void; + + /** + * Called when the picker is dismissed without selecting a value. + */ + onDismiss?: () => void; + + /** + * Called when the neutral button is pressed (Android only). + */ + onNeutralButtonPress?: () => void; }; type DateOptions = BaseOptions & { diff --git a/src/types.js b/src/types.js index 94c9cb22..81847c04 100644 --- a/src/types.js +++ b/src/types.js @@ -43,6 +43,15 @@ export type DateTimePickerEvent = { ... }; +export type DateTimePickerChangeEvent = { + nativeEvent: $ReadOnly<{ + timestamp: number, + utcOffset: number, + ... + }>, + ... +}; + type BaseOptions = {| /** * The currently selected date. @@ -50,13 +59,28 @@ type BaseOptions = {| value: Date, /** - * change handler. + * @deprecated Use onValueChange, onDismiss, and onNeutralButtonPress instead. * - * This is called when the user changes the date or time in the UI. - * Or when they clear / dismiss the dialog. - * The first argument is an Event, the second a selected Date. + * Called when the user changes the date/time, dismisses the picker, + * or presses the neutral button. The event type is encoded in event.type. + * If the new specific listeners are provided, they take precedence. */ onChange?: ?(event: DateTimePickerEvent, date?: Date) => void, + + /** + * Called when the user selects a date or time. + */ + onValueChange?: ?(event: DateTimePickerChangeEvent, date: Date) => void, + + /** + * Called when the picker is dismissed without selecting a value. + */ + onDismiss?: ?() => void, + + /** + * Called when the neutral button is pressed (Android only). + */ + onNeutralButtonPress?: ?() => void, |}; type DateOptions = {| diff --git a/src/utils.js b/src/utils.js index b7775256..96e4b21c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -67,3 +67,13 @@ export function sharedPropsValidation({ ); } } + +let hasWarnedOnChange = false; +export function warnIfOnChangeIsUsed(onChange: ?Function) { + if (__DEV__ && onChange && !hasWarnedOnChange) { + hasWarnedOnChange = true; + console.warn( + 'DateTimePicker: `onChange` is deprecated. Use `onValueChange`, `onDismiss`, and `onNeutralButtonPress` instead.', + ); + } +}