diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8756ab19ed5b1..54f4691d2b2d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ Package-specific changes not released in any SDK will be added here just before
- Updated `react-native-screens` from `2.2.0` to `2.8.0`. ([#8434](https://github.com/expo/expo/pull/8424) by [@sjchmiela](https://github.com/sjchmiela))
- Updated `react-native-shared-element` from `0.5.6` to `0.7.0`. ([#8427](https://github.com/expo/expo/pull/8427) by [@IjzerenHein](https://github.com/IjzerenHein))
- Updated `react-native-reanimated` from `1.7.0` to `1.9.0`. ([#8424](https://github.com/expo/expo/pull/8424) by [@sjchmiela](https://github.com/sjchmiela))
+- Updated `@react-native-community/datetimepicker` from `2.2.2` to `2.4.0`. ([#8476](https://github.com/expo/expo/pull/8476) by [@tsapeta](https://github.com/tsapeta))
### 🛠Breaking changes
diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java
index c6ab8507a0f29..f08081b58885e 100644
--- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java
+++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDatePickerDialogFragment.java
@@ -82,18 +82,21 @@ DatePickerDialog getDialog(
onDateSetListener,
year,
month,
- day);
+ day,
+ display
+ );
default:
return new RNDismissableDatePickerDialog(
activityContext,
onDateSetListener,
year,
month,
- day
+ day,
+ display
);
}
} else {
- DatePickerDialog dialog = new RNDismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day);
+ DatePickerDialog dialog = new RNDismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day, display);
switch (display) {
case CALENDAR:
dialog.getDatePicker().setCalendarViewShown(true);
diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java
index b1b861def9ab9..4e21a2ead5f23 100644
--- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java
+++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableDatePickerDialog.java
@@ -37,9 +37,10 @@ public RNDismissableDatePickerDialog(
@Nullable DatePickerDialog.OnDateSetListener callback,
int year,
int monthOfYear,
- int dayOfMonth) {
+ int dayOfMonth,
+ RNDatePickerDisplay display) {
super(context, callback, year, monthOfYear, dayOfMonth);
- fixSpinner(context, year, monthOfYear, dayOfMonth);
+ fixSpinner(context, year, monthOfYear, dayOfMonth, display);
}
public RNDismissableDatePickerDialog(
@@ -48,9 +49,10 @@ public RNDismissableDatePickerDialog(
@Nullable DatePickerDialog.OnDateSetListener callback,
int year,
int monthOfYear,
- int dayOfMonth) {
+ int dayOfMonth,
+ RNDatePickerDisplay display) {
super(context, theme, callback, year, monthOfYear, dayOfMonth);
- fixSpinner(context, year, monthOfYear, dayOfMonth);
+ fixSpinner(context, year, monthOfYear, dayOfMonth, display);
}
@Override
@@ -62,57 +64,43 @@ protected void onStop() {
}
}
- private void fixSpinner(Context context, int year, int month, int dayOfMonth) {
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
+ private void fixSpinner(Context context, int year, int month, int dayOfMonth, RNDatePickerDisplay display) {
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && display == RNDatePickerDisplay.SPINNER) {
try {
// Get the theme's android:datePickerMode
- final int MODE_SPINNER = 2;
Class> styleableClass = Class.forName("com.android.internal.R$styleable");
Field datePickerStyleableField = styleableClass.getField("DatePicker");
int[] datePickerStyleable = (int[]) datePickerStyleableField.get(null);
-
- final TypedArray a =
- context.obtainStyledAttributes(
- null, datePickerStyleable, android.R.attr.datePickerStyle, 0);
- Field datePickerModeStyleableField = styleableClass.getField("DatePicker_datePickerMode");
- int datePickerModeStyleable = datePickerModeStyleableField.getInt(null);
- final int mode = a.getInt(datePickerModeStyleable, MODE_SPINNER);
+ final TypedArray a = context.obtainStyledAttributes(null, datePickerStyleable, android.R.attr.datePickerStyle, 0);
a.recycle();
- if (mode == MODE_SPINNER) {
- DatePicker datePicker =
- (DatePicker)
- findField(DatePickerDialog.class, DatePicker.class, "mDatePicker").get(this);
- Class> delegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
- Field delegateField = findField(DatePicker.class, delegateClass, "mDelegate");
- Object delegate = delegateField.get(datePicker);
- Class> spinnerDelegateClass;
- spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
+ DatePicker datePicker = (DatePicker)findField(DatePickerDialog.class, DatePicker.class, "mDatePicker").get(this);
+ Class> delegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
+ Field delegateField = findField(DatePicker.class, delegateClass, "mDelegate");
+ Object delegate = delegateField.get(datePicker);
+ Class> spinnerDelegateClass;
+ spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate");
- // In 7.0 Nougat for some reason the datePickerMode is ignored and the delegate is
- // DatePickerClockDelegate
- if (delegate.getClass() != spinnerDelegateClass) {
- delegateField.set(datePicker, null); // throw out the DatePickerClockDelegate!
- datePicker.removeAllViews(); // remove the DatePickerClockDelegate views
- Method createSpinnerUIDelegate =
- DatePicker.class.getDeclaredMethod(
- "createSpinnerUIDelegate",
- Context.class,
- AttributeSet.class,
- int.class,
- int.class);
- createSpinnerUIDelegate.setAccessible(true);
+ // In 7.0 Nougat for some reason the datePickerMode is ignored and the delegate is
+ // DatePickerClockDelegate
+ if (delegate.getClass() != spinnerDelegateClass) {
+ delegateField.set(datePicker, null); // throw out the DatePickerClockDelegate!
+ datePicker.removeAllViews(); // remove the DatePickerClockDelegate views
+ Method createSpinnerUIDelegate =
+ DatePicker.class.getDeclaredMethod(
+ "createSpinnerUIDelegate",
+ Context.class,
+ AttributeSet.class,
+ int.class,
+ int.class);
+ createSpinnerUIDelegate.setAccessible(true);
- // Instantiate a DatePickerSpinnerDelegate throughout createSpinnerUIDelegate method
- delegate =
- createSpinnerUIDelegate.invoke(
- datePicker, context, null, android.R.attr.datePickerStyle, 0);
- delegateField.set(
- datePicker, delegate); // set the DatePicker.mDelegate to the spinner delegate
- datePicker.setCalendarViewShown(false);
- // Initialize the date for the DatePicker delegate again
- datePicker.init(year, month, dayOfMonth, this);
- }
+ // Instantiate a DatePickerSpinnerDelegate throughout createSpinnerUIDelegate method
+ delegate = createSpinnerUIDelegate.invoke(datePicker, context, null, android.R.attr.datePickerStyle, 0);
+ delegateField.set(datePicker, delegate); // set the DatePicker.mDelegate to the spinner delegate
+ datePicker.setCalendarViewShown(false);
+ // Initialize the date for the DatePicker delegate again
+ datePicker.init(year, month, dayOfMonth, this);
}
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java
index 7c5c7ef55a93a..90192bc4125f6 100644
--- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java
+++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNDismissableTimePickerDialog.java
@@ -38,9 +38,10 @@ public RNDismissableTimePickerDialog(
@Nullable TimePickerDialog.OnTimeSetListener callback,
int hourOfDay,
int minute,
- boolean is24HourView) {
+ boolean is24HourView,
+ RNTimePickerDisplay display) {
super(context, callback, hourOfDay, minute, is24HourView);
- fixSpinner(context, hourOfDay, minute, is24HourView);
+ fixSpinner(context, hourOfDay, minute, is24HourView, display);
}
public RNDismissableTimePickerDialog(
@@ -49,9 +50,10 @@ public RNDismissableTimePickerDialog(
@Nullable TimePickerDialog.OnTimeSetListener callback,
int hourOfDay,
int minute,
- boolean is24HourView) {
+ boolean is24HourView,
+ RNTimePickerDisplay display) {
super(context, theme, callback, hourOfDay, minute, is24HourView);
- fixSpinner(context, hourOfDay, minute, is24HourView);
+ fixSpinner(context, hourOfDay, minute, is24HourView, display);
}
@Override
@@ -61,41 +63,35 @@ protected void onStop() {
}
}
- private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView) {
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
+ private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView, RNTimePickerDisplay display) {
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N && display == RNTimePickerDisplay.SPINNER) {
try {
- // Get the theme's android:timePickerMode
- final int MODE_SPINNER = 1;
Class> styleableClass = Class.forName("com.android.internal.R$styleable");
Field timePickerStyleableField = styleableClass.getField("TimePicker");
int[] timePickerStyleable = (int[]) timePickerStyleableField.get(null);
final TypedArray a = context.obtainStyledAttributes(null, timePickerStyleable, android.R.attr.timePickerStyle, 0);
- Field timePickerModeStyleableField = styleableClass.getField("TimePicker_timePickerMode");
- int timePickerModeStyleable = timePickerModeStyleableField.getInt(null);
- final int mode = a.getInt(timePickerModeStyleable, MODE_SPINNER);
a.recycle();
- if (mode == MODE_SPINNER) {
- TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this);
- Class> delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate");
- Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate");
- Object delegate = delegateField.get(timePicker);
- Class> spinnerDelegateClass;
- spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate");
- // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is TimePickerClockDelegate
- if (delegate.getClass() != spinnerDelegateClass) {
- delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate!
- timePicker.removeAllViews(); // remove the TimePickerClockDelegate views
- Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class);
- spinnerDelegateConstructor.setAccessible(true);
- // Instantiate a TimePickerSpinnerDelegate
- delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0);
- delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate
- // Set up the TimePicker again, with the TimePickerSpinnerDelegate
- timePicker.setIs24HourView(is24HourView);
- timePicker.setCurrentHour(hourOfDay);
- timePicker.setCurrentMinute(minute);
- timePicker.setOnTimeChangedListener(this);
- }
+
+ TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this);
+ Class> delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate");
+ Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate");
+ Object delegate = delegateField.get(timePicker);
+ Class> spinnerDelegateClass;
+ spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate");
+ // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is TimePickerClockDelegate
+ if (delegate.getClass() != spinnerDelegateClass) {
+ delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate!
+ timePicker.removeAllViews(); // remove the TimePickerClockDelegate views
+ Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class);
+ spinnerDelegateConstructor.setAccessible(true);
+ // Instantiate a TimePickerSpinnerDelegate
+ delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0);
+ delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate
+ // Set up the TimePicker again, with the TimePickerSpinnerDelegate
+ timePicker.setIs24HourView(is24HourView);
+ timePicker.setCurrentHour(hourOfDay);
+ timePicker.setCurrentMinute(minute);
+ timePicker.setOnTimeChangedListener(this);
}
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java
index e7dd8f9e65ad8..32e9fa22c747f 100644
--- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java
+++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/datetimepicker/RNTimePickerDialogFragment.java
@@ -81,7 +81,8 @@ static TimePickerDialog getDialog(
onTimeSetListener,
hour,
minute,
- is24hour
+ is24hour,
+ display
);
}
}
@@ -90,7 +91,8 @@ static TimePickerDialog getDialog(
onTimeSetListener,
hour,
minute,
- is24hour
+ is24hour,
+ display
);
}
diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json
index d609d56d7e9b2..cbb22b101782f 100644
--- a/apps/native-component-list/package.json
+++ b/apps/native-component-list/package.json
@@ -13,7 +13,7 @@
},
"dependencies": {
"@expo/react-native-action-sheet": "^2.0.1",
- "@react-native-community/datetimepicker": "2.2.2",
+ "@react-native-community/datetimepicker": "2.4.0",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/netinfo": "5.9.0",
"@react-native-community/segmented-control": "1.6.1",
diff --git a/apps/native-component-list/src/screens/DateTimePickerScreen.tsx b/apps/native-component-list/src/screens/DateTimePickerScreen.tsx
index d3a6abaa12044..a706cf423c9a3 100644
--- a/apps/native-component-list/src/screens/DateTimePickerScreen.tsx
+++ b/apps/native-component-list/src/screens/DateTimePickerScreen.tsx
@@ -1,24 +1,16 @@
-import {
- SafeAreaView,
- ScrollView,
- StyleSheet,
- View,
- Text,
- StatusBar,
- Button,
- Platform,
-} from 'react-native';
+import { ScrollView, StyleSheet, View, Text, Button, Platform, TextInput } from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import React, { useState } from 'react';
import moment from 'moment';
-// This example is a copy from https://github.com/react-native-community/react-native-datetimepicker/tree/master/example
+// This example is a refactored copy from https://github.com/react-native-community/react-native-datetimepicker/tree/master/example
// Please try to keep it up to date when updating @react-native-community/datetimepicker package :)
const DateTimePickerScreen = () => {
const [date, setDate] = useState(new Date(1598051730000));
const [mode, setMode] = useState('date');
const [show, setShow] = useState(false);
+ const [color, setColor] = useState();
const [display, setDisplay] = useState('default');
const onChange = (event, selectedDate) => {
@@ -45,66 +37,86 @@ const DateTimePickerScreen = () => {
const showTimepicker = () => {
showMode('time');
+ setDisplay('default');
+ };
+
+ const showTimepickerSpinner = () => {
+ showMode('time');
+ setDisplay('spinner');
};
return (
- <>
-
-
-
- {global.HermesInternal == null ? null : (
-
- Engine: Hermes
-
- )}
-
-
-
- Example DateTime Picker
-
-
-
-
-
-
-
-
-
-
-
-
- {mode === 'time' && moment.utc(date).format('HH:mm')}
- {mode === 'date' && moment.utc(date).format('MM/DD/YYYY')}
-
-
- {show && (
-
- )}
-
+
+ {global.HermesInternal == null ? null : (
+
+
+ Engine: Hermes
+
+
+ )}
+
+
+
+ Example DateTime Picker
+
+
+ text color (iOS only)
+ {
+ setColor(text.toLowerCase());
+ }}
+ placeholder="color"
+ />
+
+
+
+
+
+
+
+
+
-
-
- >
+
+
+
+
+
+ {mode === 'time' && moment.utc(date).format('HH:mm')}
+ {mode === 'date' && moment.utc(date).format('MM/DD/YYYY')}
+
+
+ {show && (
+
+ )}
+
+
+
);
};
@@ -126,21 +138,33 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
header: {
+ justifyContent: 'center',
alignItems: 'center',
- marginBottom: 20,
+ flexDirection: 'row',
},
button: {
alignItems: 'center',
- marginBottom: 20,
+ marginBottom: 10,
+ },
+ resetButton: {
+ width: 150,
},
text: {
fontSize: 20,
fontWeight: 'bold',
},
dateTimeText: {
+ paddingRight: 20,
fontSize: 16,
fontWeight: 'normal',
},
+ iOsPicker: {
+ flex: 1,
+ },
});
+DateTimePickerScreen.navigationOptions = {
+ title: 'DateTimePicker',
+};
+
export default DateTimePickerScreen;
diff --git a/ios/Exponent.xcodeproj/project.pbxproj b/ios/Exponent.xcodeproj/project.pbxproj
index 99bdb18090f63..393863b237afb 100644
--- a/ios/Exponent.xcodeproj/project.pbxproj
+++ b/ios/Exponent.xcodeproj/project.pbxproj
@@ -5,7 +5,6 @@
};
objectVersion = 46;
objects = {
-
/* Begin PBXBuildFile section */
0726F0592007E438004992E7 /* EXKernelAppRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0726F0582007E438004992E7 /* EXKernelAppRecord.m */; };
0726F05C2007E446004992E7 /* EXKernelAppRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 0726F05B2007E446004992E7 /* EXKernelAppRegistry.m */; };
diff --git a/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m b/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m
index 661e1f1781174..731ceeb17b992 100644
--- a/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m
+++ b/ios/Exponent/Versioned/Core/Api/Components/DateTimePicker/RNDateTimePickerManager.m
@@ -40,4 +40,21 @@ - (UIView *)view
RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode, UIDatePickerMode)
RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone)
+RCT_CUSTOM_VIEW_PROPERTY(textColor, UIColor, RNDateTimePicker)
+{
+ if (json) {
+ [view setValue:[RCTConvert UIColor:json] forKey:@"textColor"];
+ [view setValue:@(NO) forKey:@"highlightsToday"];
+ } else {
+ UIColor* defaultColor;
+ if (@available(iOS 13.0, *)) {
+ defaultColor = [UIColor labelColor];
+ } else {
+ defaultColor = [UIColor blackColor];
+ }
+ [view setValue:defaultColor forKey:@"textColor"];
+ [view setValue:@(YES) forKey:@"highlightsToday"];
+ }
+}
+
@end
diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json
index f24ede4b5fd61..2366d45ee9572 100644
--- a/packages/expo/bundledNativeModules.json
+++ b/packages/expo/bundledNativeModules.json
@@ -87,7 +87,7 @@
"expo-network": "~2.1.1",
"expo-store-review": "~2.1.0",
"expo-updates": "~0.2.5",
- "@react-native-community/datetimepicker": "2.2.2",
+ "@react-native-community/datetimepicker": "2.4.0",
"@react-native-community/masked-view": "0.1.6",
"@react-native-community/viewpager": "3.3.0",
"@react-native-community/segmented-control": "1.6.1",
diff --git a/yarn.lock b/yarn.lock
index 41d86b5a28df3..cc09aea4438ab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2409,10 +2409,10 @@
wcwidth "^1.0.1"
ws "^1.1.0"
-"@react-native-community/datetimepicker@2.2.2":
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-2.2.2.tgz#4c6388631179098cc5b289146e879764f79af4c1"
- integrity sha512-J4Z1tuZQszLR+BNu+UusZlK6/S+CpI6AHzolqTdPS2tRlyVbVim3KyjXrn8trtKxQncR5LEqF9OHw9zsRfEdXA==
+"@react-native-community/datetimepicker@2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-2.4.0.tgz#6b3cf050f507f9b70d31d5a572e1153bb5bd50c9"
+ integrity sha512-ZXPwNAQt4T66PTL20l2nSEbtsn6vtsvFqdYWBfx8aaNKBoCPDygR6SsYzWcIoexKH5wmX0zctSzIsryl+Gtngg==
dependencies:
invariant "^2.2.4"