Skip to content

Commit 5861042

Browse files
authored
feat: expose imperative api for android picker (#574)
BREAKING CHANGE: actually, should not be breaking but there were changes in typings
1 parent 2e4d3da commit 5861042

21 files changed

+1482
-959
lines changed

README.md

Lines changed: 94 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
### 🚧🚧 Looking for collaborators and backers 🚧🚧
22

3-
See this [issue](https://github.com/react-native-datetimepicker/datetimepicker/issues/313)
3+
See this [issue](https://github.com/react-native-datetimepicker/datetimepicker/issues/313).
44

55
### Backers
66

7-
Support us with a monthly donation and help us continue our activities. [Become a backer on OpenCollective](https://opencollective.com/react-native-datetimepicker) or [sponsor us on GitHub Sponsors](https://github.com/sponsors/react-native-datetimepicker)
7+
Support us with a monthly donation and help us continue our activities. [Become a backer on OpenCollective](https://opencollective.com/react-native-datetimepicker) or [sponsor us on GitHub Sponsors](https://github.com/sponsors/react-native-datetimepicker).
88

99
<a href="https://opencollective.com/react-native-datetimepicker/donate" target="_blank">
1010
<img src="https://opencollective.com/react-native-datetimepicker/backers.svg?width=890" width=890 />
@@ -22,9 +22,11 @@ The module is still published on `npm` under the old namespace (as documented) b
2222

2323
React Native date & time picker component for iOS, Android and Windows.
2424

25+
## Screenshots
26+
2527
<details>
2628
<summary>Expand for screenshots</summary>
27-
29+
2830
<table>
2931
<tr><td colspan=2><strong>iOS</strong></td></tr>
3032
<tr>
@@ -48,18 +50,16 @@ React Native date & time picker component for iOS, Android and Windows.
4850

4951
</details>
5052

51-
## Table of Contents
53+
## Table of contents
5254

5355
- [React Native DateTimePicker](#react-native-datetimepicker)
54-
- [Table of Contents](#table-of-contents)
56+
- [Table of contents](#table-of-contents)
5557
- [Expo users notice](#expo-users-notice)
5658
- [Getting started](#getting-started)
57-
- [RN >= 0.60](#rn--060)
58-
- [RN < 0.60](#rn--060-1)
59-
- [General Usage](#general-usage)
60-
- [Basic usage with state](#basic-usage-with-state)
59+
- [Usage](#usage)
6160
- [Localization note](#localization-note)
62-
- [Props](#props)
61+
- [Android imperative API](#android-imperative-api)
62+
- [Props / params](#component-props--params-of-the-android-imperative-api)
6363
- [`mode` (`optional`)](#mode-optional)
6464
- [`display` (`optional`)](#display-optional)
6565
- [`onChange` (`optional`)](#onchange-optional)
@@ -79,15 +79,10 @@ React Native date & time picker component for iOS, Android and Windows.
7979
- [`minuteInterval` (`optional`)](#minuteinterval-optional)
8080
- [`style` (`optional`, `iOS only`)](#style-optional-ios-only)
8181
- [`disabled` (`optional`, `iOS only`)](#disabled-optional-ios-only)
82+
- [`onError` (`optional`, `Android only`)](#onError-optional-android-only)
8283
- [Migration from the older components](#migration-from-the-older-components)
83-
- [DatePickerIOS](#datepickerios)
84-
- [DatePickerAndroid](#datepickerandroid)
85-
- [TimePickerAndroid](#timepickerandroid)
8684
- [Contributing to the component](#contributing-to-the-component)
8785
- [Manual installation](#manual-installation)
88-
- [iOS](#ios)
89-
- [Android](#android)
90-
- [Windows](#windows)
9186
- [Running the example app](#running-the-example-app)
9287

9388
## Requirements
@@ -117,27 +112,74 @@ Autolinking is not yet implemented on Windows, so [manual installation ](/docs/m
117112

118113
If you are using RN >= 0.60, only run `npx pod-install`. Then rebuild your project.
119114

120-
## General Usage
115+
## Usage
121116

122117
```js
123118
import DateTimePicker from '@react-native-community/datetimepicker';
124119
```
125120

126-
### Basic usage with state
121+
<details>
122+
<summary>Expand for examples</summary>
123+
124+
We give two equivalent examples on how to use the package on all supported platforms.
125+
126+
### Recommended imperative api usage on Android
127+
128+
While the component-approach as given in the second paragraph works on Android, the recommended approach is to use the imperative api given in the first paragraph.
129+
130+
Read more about the motivation in [Android imperative API](#android-imperative-api).
127131

128132
```js
129-
import React, {useState} from 'react';
130-
import {View, Button, Platform} from 'react-native';
131-
import DateTimePicker from '@react-native-community/datetimepicker';
133+
export const App = () => {
134+
const [date, setDate] = useState(new Date(1598051730000));
135+
136+
const onChange = (event, selectedDate) => {
137+
const currentDate = selectedDate;
138+
setDate(currentDate);
139+
};
140+
141+
const showMode = (currentMode) => {
142+
DateTimePickerAndroid.open({
143+
value: date,
144+
onChange,
145+
mode: currentMode,
146+
is24Hour: true
147+
})
148+
};
149+
150+
const showDatepicker = () => {
151+
showMode('date');
152+
};
153+
154+
const showTimepicker = () => {
155+
showMode('time');
156+
};
157+
158+
return (
159+
<View>
160+
<View>
161+
<Button onPress={showDatepicker} title="Show date picker!" />
162+
</View>
163+
<View>
164+
<Button onPress={showTimepicker} title="Show time picker!" />
165+
</View>
166+
<Text>selected: {date.toLocaleString()}</Text>
167+
</View>
168+
);
169+
}
170+
```
171+
172+
### Component usage on iOS / Android / Windows
132173

174+
```js
133175
export const App = () => {
134176
const [date, setDate] = useState(new Date(1598051730000));
135177
const [mode, setMode] = useState('date');
136178
const [show, setShow] = useState(false);
137179

138180
const onChange = (event, selectedDate) => {
139-
const currentDate = selectedDate || date;
140-
setShow(Platform.OS === 'ios');
181+
const currentDate = selectedDate;
182+
setShow(false);
141183
setDate(currentDate);
142184
};
143185

@@ -162,21 +204,24 @@ export const App = () => {
162204
<View>
163205
<Button onPress={showTimepicker} title="Show time picker!" />
164206
</View>
207+
<Text>selected: {date.toLocaleString()}</Text>
165208
{show && (
166209
<DateTimePicker
167210
testID="dateTimePicker"
168211
value={date}
169212
mode={mode}
170213
is24Hour={true}
171-
display="default"
172214
onChange={onChange}
173215
/>
174216
)}
175217
</View>
176218
);
177-
};
219+
}
178220
```
179221

222+
</details>
223+
224+
180225
## Localization note
181226

182227
On Android, the picker will be controlled by the system locale. If you wish to change it, [see instructions here](https://stackoverflow.com/a/2900144/2070942).
@@ -191,11 +236,29 @@ There is also the iOS-only locale prop that can be used to force locale in some
191236

192237
For Expo, follow the [localization docs](https://docs.expo.dev/distribution/app-stores/#localizing-your-ios-app).
193238

194-
## Props
239+
240+
### Android imperative api
241+
242+
On Android, you have a choice between using the component API (regular React component) or an imperative api (think something like `ReactNative.alert()`).
243+
244+
While the component API has the benefit of writing the same code on all platforms, for start we recommend to use the imperative API on Android.
245+
246+
The `params` is an object with the same properties as the component props documented in the next paragraph. (This is also because the component api internally uses the imperative one.)
247+
248+
```js
249+
import { DateTimePickerAndroid } from '@react-native-community/datetimepicker';
250+
251+
DateTimePickerAndroid.open(params: AndroidNativeProps)
252+
DateTimePickerAndroid.dismiss(mode: AndroidNativeProps['mode'])
253+
```
254+
255+
Reason we recommend the imperative API is: on Android, the date/time picker opens in a dialog, similar to `ReactNative.alert()` from core react native. The imperative api models this behavior better than the declarative component api. While the component approach is perfectly functional, based on the issue tracker history, it appears to be more prone to introducing bugs.
256+
257+
## Component props / params of the Android imperative api
195258

196259
> Please note that this library currently exposes functionality from [`UIDatePicker`](https://developer.apple.com/documentation/uikit/uidatepicker?language=objc) on iOS and [DatePickerDialog](https://developer.android.com/reference/android/app/DatePickerDialog) + [TimePickerDialog](https://developer.android.com/reference/android/app/TimePickerDialog) on Android, and [`CalendarDatePicker`](https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/calendar-date-picker) +[TimePicker](https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.timepicker?view=winrt-19041) on Windows.
197260
>
198-
> These native classes offer only limited configuration, while there are dozens of possible options you as a developer may need. It follows that if your requirement is not supported by the backing native views, this library will _not_ be able to implement your requirement. When you open an issue with a feature request, please document if (or how) the feature can be implemented using the aforementioned native views. If those views do not support what you need, such feature requests will be closed as not actionable.
261+
> These native classes offer only limited configuration, while there are dozens of possible options you as a developer may need. It follows that if your requirement is not supported by the backing native views, this library will _not_ be able to implement your requirement. When you open an issue with a feature request, please document if (or how) the feature can be implemented using the aforementioned native views. If the native views do not support what you need, such feature requests will be closed as not actionable.
199262
200263
#### `mode` (`optional`)
201264

@@ -395,6 +458,10 @@ Alternatively, use the `themeVariant` prop or [opt-out from dark mode (discourag
395458

396459
If true, the user won't be able to interact with the view.
397460

461+
#### `onError` (`optional`, `Android only`)
462+
463+
Callback that is called when an error occurs inside the date picker native code (such as null activity).
464+
398465
## Migration from the older components
399466

400467
Please see [migration.md](/docs/migration.md)

RNDateTimePicker.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
1010
s.license = package['license']
1111
s.author = package['author']
1212
s.homepage = package['homepage']
13-
s.platform = :ios, "10.0"
13+
s.platform = :ios, "11.0"
1414
s.source = { :git => "https://github.com/react-native-community/datetimepicker", :tag => "v#{s.version}" }
1515
s.source_files = "ios/*.{h,m}"
1616
s.requires_arc = true

example/e2e/detoxTest.spec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ const {
1717
} = require('./utils/actions');
1818
const {isIOS, wait, Platform} = require('./utils/utils');
1919
const {device} = require('detox');
20+
const {describe} = require('jest-circus');
2021

21-
describe('Example', () => {
22+
describe('e2e tests', () => {
2223
const getPickerDisplay = () => {
2324
return isIOS() ? 'spinner' : 'default';
2425
};

example/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ target "example" do
2121
#
2222
# Note that if you have use_frameworks! enabled, Flipper will not work and
2323
# you should disable these next few lines.
24-
use_flipper!()
24+
# use_flipper!()
2525
end
2626

2727
post_install do |installer|

0 commit comments

Comments
 (0)