2015-12-17 11:09:22 -08:00
|
|
|
/**
|
2018-09-11 15:27:47 -07:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2015-12-17 11:09:22 -08:00
|
|
|
*
|
2018-02-16 18:24:55 -08:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2015-12-17 11:09:22 -08:00
|
|
|
*
|
2018-05-10 19:06:46 -07:00
|
|
|
* @format
|
2015-12-17 11:09:22 -08:00
|
|
|
* @flow
|
|
|
|
*/
|
2018-05-10 19:06:46 -07:00
|
|
|
|
2015-12-17 11:09:22 -08:00
|
|
|
'use strict';
|
|
|
|
|
2017-02-17 16:39:50 -08:00
|
|
|
const NativeModules = require('NativeModules');
|
2019-02-12 07:35:40 -08:00
|
|
|
const RCTAlertManager = NativeModules.AlertManager;
|
2017-02-17 16:39:50 -08:00
|
|
|
const Platform = require('Platform');
|
2015-12-17 11:09:22 -08:00
|
|
|
|
2017-11-05 12:01:16 -08:00
|
|
|
export type Buttons = Array<{
|
2016-08-09 06:32:41 -07:00
|
|
|
text?: string,
|
|
|
|
onPress?: ?Function,
|
|
|
|
style?: AlertButtonStyle,
|
2015-12-17 11:09:22 -08:00
|
|
|
}>;
|
|
|
|
|
2016-08-09 06:08:44 -07:00
|
|
|
type Options = {
|
2016-10-11 10:08:54 -07:00
|
|
|
cancelable?: ?boolean,
|
Optional Alert onDismiss callback to support Android default behavior
Summary:
On Android it's generally expected that alerts are dismissible by tapping outside the alert box. This is the default behavior for React Native, but until now there has been no means to listen for the dismiss event.
`Alert.alert` already takes an `options` object, so this pull request simply adds an additional option `onDismiss`, a callback function that will be called when an Alert is dismissed (rather than being closed as a result of a button press).
**Test plan**
Simply pass an `options` object to `Alert.alert` with the `onDismiss` property set to a function.
e.g. Run the following on Android, dismiss the alert by tapping outside the alert view, and monitor console output.
```
Alert.alert(
'Alert Title',
'My Alert Msg',
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ onDismiss: () => console.
Closes https://github.com/facebook/react-native/pull/12594
Differential Revision: D4619862
Pulled By: ericvicenti
fbshipit-source-id: fdd351a7b8e673dab331f0e22dc5ea2e84f24375
2017-02-27 02:15:07 -08:00
|
|
|
onDismiss?: ?Function,
|
2016-08-09 06:08:44 -07:00
|
|
|
};
|
|
|
|
|
2019-02-12 07:35:40 -08:00
|
|
|
type AlertType = $Enum<{
|
|
|
|
default: string,
|
|
|
|
'plain-text': string,
|
|
|
|
'secure-text': string,
|
|
|
|
'login-password': string,
|
|
|
|
}>;
|
|
|
|
|
|
|
|
export type AlertButtonStyle = $Enum<{
|
|
|
|
default: string,
|
|
|
|
cancel: string,
|
|
|
|
destructive: string,
|
|
|
|
}>;
|
|
|
|
|
2015-12-17 11:09:22 -08:00
|
|
|
/**
|
|
|
|
* Launches an alert dialog with the specified title and message.
|
2018-02-22 07:04:35 -08:00
|
|
|
*
|
2017-11-20 13:07:10 -08:00
|
|
|
* See http://facebook.github.io/react-native/docs/alert.html
|
2015-12-17 11:09:22 -08:00
|
|
|
*/
|
|
|
|
class Alert {
|
|
|
|
static alert(
|
2017-11-09 12:45:12 -08:00
|
|
|
title: ?string,
|
|
|
|
message?: ?string,
|
2015-12-17 11:09:22 -08:00
|
|
|
buttons?: Buttons,
|
2016-08-09 06:08:44 -07:00
|
|
|
options?: Options,
|
2015-12-17 11:09:22 -08:00
|
|
|
): void {
|
|
|
|
if (Platform.OS === 'ios') {
|
Simplified AlertIOS
Summary:
Ok, so this started as fixing #5273 but ended up getting a little more complicated. :smile:
Currently, AlertIOS has the following API:
* `alert(title, message, buttons, type)`
* `prompt(title, defaultValue, buttons, callback)`
I've changed the API to look like the following:
* `alert(title, message, callbackOrButtons)`
* `prompt(title, message, callbackOrButtons, type, defaultValue)`
I know that breaking changes are a big deal, but I find the current alert API to be fairly inconsistent and unnecessarily confusing. I'll try to justify my changes one by one:
1. Currently `type` is an optional parameter of `alert`. However, the only reason to change the alert type from the default is in order to create one of the input dialogs (text, password or username/password). So we're in a weird state where if you want a normal text input, you use `prompt`, but if you want a password input you use `alert` with the 'secure-text' type. I've moved `type` to `prompt` so all text input is now done with `pro
Closes https://github.com/facebook/react-native/pull/5286
Reviewed By: svcscm
Differential Revision: D2850400
Pulled By: androidtrunkagent
fb-gh-sync-id: 2986cfa2266225df7e4dcd703fce1e322c12b816
2016-01-21 10:48:58 -08:00
|
|
|
AlertIOS.alert(title, message, buttons);
|
2015-12-17 11:09:22 -08:00
|
|
|
} else if (Platform.OS === 'android') {
|
2016-08-09 06:08:44 -07:00
|
|
|
AlertAndroid.alert(title, message, buttons, options);
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
|
|
|
}
|
2019-02-12 07:35:40 -08:00
|
|
|
|
|
|
|
static prompt(
|
|
|
|
title: ?string,
|
|
|
|
message?: ?string,
|
|
|
|
callbackOrButtons?: ?(((text: string) => void) | Buttons),
|
|
|
|
type?: ?AlertType = 'plain-text',
|
|
|
|
defaultValue?: string,
|
|
|
|
keyboardType?: string,
|
|
|
|
): void {
|
|
|
|
if (Platform.OS === 'ios') {
|
|
|
|
AlertIOS.prompt(
|
|
|
|
title,
|
|
|
|
message,
|
|
|
|
callbackOrButtons,
|
|
|
|
type,
|
|
|
|
defaultValue,
|
|
|
|
keyboardType,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper around the iOS native module.
|
|
|
|
*/
|
|
|
|
class AlertIOS {
|
|
|
|
static alert(
|
|
|
|
title: ?string,
|
|
|
|
message?: ?string,
|
|
|
|
callbackOrButtons?: ?((() => void) | Buttons),
|
|
|
|
): void {
|
|
|
|
this.prompt(title, message, callbackOrButtons, 'default');
|
|
|
|
}
|
|
|
|
|
|
|
|
static prompt(
|
|
|
|
title: ?string,
|
|
|
|
message?: ?string,
|
|
|
|
callbackOrButtons?: ?(((text: string) => void) | Buttons),
|
|
|
|
type?: ?AlertType = 'plain-text',
|
|
|
|
defaultValue?: string,
|
|
|
|
keyboardType?: string,
|
|
|
|
): void {
|
|
|
|
if (typeof type === 'function') {
|
|
|
|
console.warn(
|
|
|
|
'You passed a callback function as the "type" argument to Alert.prompt(). React Native is ' +
|
|
|
|
'assuming you want to use the deprecated Alert.prompt(title, defaultValue, buttons, callback) ' +
|
|
|
|
'signature. The current signature is Alert.prompt(title, message, callbackOrButtons, type, defaultValue, ' +
|
|
|
|
'keyboardType) and the old syntax will be removed in a future version.',
|
|
|
|
);
|
|
|
|
|
|
|
|
const callback = type;
|
|
|
|
RCTAlertManager.alertWithArgs(
|
|
|
|
{
|
|
|
|
title: title || '',
|
|
|
|
type: 'plain-text',
|
|
|
|
defaultValue: message,
|
|
|
|
},
|
|
|
|
(id, value) => {
|
|
|
|
callback(value);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let callbacks = [];
|
|
|
|
const buttons = [];
|
|
|
|
let cancelButtonKey;
|
|
|
|
let destructiveButtonKey;
|
|
|
|
if (typeof callbackOrButtons === 'function') {
|
|
|
|
callbacks = [callbackOrButtons];
|
|
|
|
} else if (Array.isArray(callbackOrButtons)) {
|
|
|
|
callbackOrButtons.forEach((btn, index) => {
|
|
|
|
callbacks[index] = btn.onPress;
|
|
|
|
if (btn.style === 'cancel') {
|
|
|
|
cancelButtonKey = String(index);
|
|
|
|
} else if (btn.style === 'destructive') {
|
|
|
|
destructiveButtonKey = String(index);
|
|
|
|
}
|
|
|
|
if (btn.text || index < (callbackOrButtons || []).length - 1) {
|
|
|
|
const btnDef = {};
|
|
|
|
btnDef[index] = btn.text || '';
|
|
|
|
buttons.push(btnDef);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
RCTAlertManager.alertWithArgs(
|
|
|
|
{
|
|
|
|
title: title || '',
|
|
|
|
message: message || undefined,
|
|
|
|
buttons,
|
|
|
|
type: type || undefined,
|
|
|
|
defaultValue,
|
|
|
|
cancelButtonKey,
|
|
|
|
destructiveButtonKey,
|
|
|
|
keyboardType,
|
|
|
|
},
|
|
|
|
(id, value) => {
|
|
|
|
const cb = callbacks[id];
|
|
|
|
cb && cb(value);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper around the Android native module.
|
|
|
|
*/
|
|
|
|
class AlertAndroid {
|
|
|
|
static alert(
|
2017-11-09 12:45:12 -08:00
|
|
|
title: ?string,
|
|
|
|
message?: ?string,
|
2015-12-17 11:09:22 -08:00
|
|
|
buttons?: Buttons,
|
2016-08-09 06:08:44 -07:00
|
|
|
options?: Options,
|
2015-12-17 11:09:22 -08:00
|
|
|
): void {
|
2018-05-10 15:44:52 -07:00
|
|
|
let config = {
|
2015-12-17 11:09:22 -08:00
|
|
|
title: title || '',
|
|
|
|
message: message || '',
|
|
|
|
};
|
2016-08-09 06:08:44 -07:00
|
|
|
|
|
|
|
if (options) {
|
|
|
|
config = {...config, cancelable: options.cancelable};
|
|
|
|
}
|
2015-12-17 11:09:22 -08:00
|
|
|
// At most three buttons (neutral, negative, positive). Ignore rest.
|
|
|
|
// The text 'OK' should be probably localized. iOS Alert does that in native.
|
2018-05-10 19:06:46 -07:00
|
|
|
const validButtons: Buttons = buttons
|
|
|
|
? buttons.slice(0, 3)
|
|
|
|
: [{text: 'OK'}];
|
2018-05-10 15:44:52 -07:00
|
|
|
const buttonPositive = validButtons.pop();
|
|
|
|
const buttonNegative = validButtons.pop();
|
|
|
|
const buttonNeutral = validButtons.pop();
|
2015-12-17 11:09:22 -08:00
|
|
|
if (buttonNeutral) {
|
2018-05-10 19:06:46 -07:00
|
|
|
config = {...config, buttonNeutral: buttonNeutral.text || ''};
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
|
|
|
if (buttonNegative) {
|
2018-05-10 19:06:46 -07:00
|
|
|
config = {...config, buttonNegative: buttonNegative.text || ''};
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
|
|
|
if (buttonPositive) {
|
2018-05-10 19:06:46 -07:00
|
|
|
config = {...config, buttonPositive: buttonPositive.text || ''};
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
2017-02-21 10:00:06 -08:00
|
|
|
NativeModules.DialogManagerAndroid.showAlert(
|
2015-12-17 11:09:22 -08:00
|
|
|
config,
|
2018-05-10 19:06:46 -07:00
|
|
|
errorMessage => console.warn(errorMessage),
|
2015-12-17 11:09:22 -08:00
|
|
|
(action, buttonKey) => {
|
Optional Alert onDismiss callback to support Android default behavior
Summary:
On Android it's generally expected that alerts are dismissible by tapping outside the alert box. This is the default behavior for React Native, but until now there has been no means to listen for the dismiss event.
`Alert.alert` already takes an `options` object, so this pull request simply adds an additional option `onDismiss`, a callback function that will be called when an Alert is dismissed (rather than being closed as a result of a button press).
**Test plan**
Simply pass an `options` object to `Alert.alert` with the `onDismiss` property set to a function.
e.g. Run the following on Android, dismiss the alert by tapping outside the alert view, and monitor console output.
```
Alert.alert(
'Alert Title',
'My Alert Msg',
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ onDismiss: () => console.
Closes https://github.com/facebook/react-native/pull/12594
Differential Revision: D4619862
Pulled By: ericvicenti
fbshipit-source-id: fdd351a7b8e673dab331f0e22dc5ea2e84f24375
2017-02-27 02:15:07 -08:00
|
|
|
if (action === NativeModules.DialogManagerAndroid.buttonClicked) {
|
|
|
|
if (buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral) {
|
|
|
|
buttonNeutral.onPress && buttonNeutral.onPress();
|
2018-05-10 19:06:46 -07:00
|
|
|
} else if (
|
|
|
|
buttonKey === NativeModules.DialogManagerAndroid.buttonNegative
|
|
|
|
) {
|
Optional Alert onDismiss callback to support Android default behavior
Summary:
On Android it's generally expected that alerts are dismissible by tapping outside the alert box. This is the default behavior for React Native, but until now there has been no means to listen for the dismiss event.
`Alert.alert` already takes an `options` object, so this pull request simply adds an additional option `onDismiss`, a callback function that will be called when an Alert is dismissed (rather than being closed as a result of a button press).
**Test plan**
Simply pass an `options` object to `Alert.alert` with the `onDismiss` property set to a function.
e.g. Run the following on Android, dismiss the alert by tapping outside the alert view, and monitor console output.
```
Alert.alert(
'Alert Title',
'My Alert Msg',
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ onDismiss: () => console.
Closes https://github.com/facebook/react-native/pull/12594
Differential Revision: D4619862
Pulled By: ericvicenti
fbshipit-source-id: fdd351a7b8e673dab331f0e22dc5ea2e84f24375
2017-02-27 02:15:07 -08:00
|
|
|
buttonNegative.onPress && buttonNegative.onPress();
|
2018-05-10 19:06:46 -07:00
|
|
|
} else if (
|
|
|
|
buttonKey === NativeModules.DialogManagerAndroid.buttonPositive
|
|
|
|
) {
|
Optional Alert onDismiss callback to support Android default behavior
Summary:
On Android it's generally expected that alerts are dismissible by tapping outside the alert box. This is the default behavior for React Native, but until now there has been no means to listen for the dismiss event.
`Alert.alert` already takes an `options` object, so this pull request simply adds an additional option `onDismiss`, a callback function that will be called when an Alert is dismissed (rather than being closed as a result of a button press).
**Test plan**
Simply pass an `options` object to `Alert.alert` with the `onDismiss` property set to a function.
e.g. Run the following on Android, dismiss the alert by tapping outside the alert view, and monitor console output.
```
Alert.alert(
'Alert Title',
'My Alert Msg',
[
{text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ onDismiss: () => console.
Closes https://github.com/facebook/react-native/pull/12594
Differential Revision: D4619862
Pulled By: ericvicenti
fbshipit-source-id: fdd351a7b8e673dab331f0e22dc5ea2e84f24375
2017-02-27 02:15:07 -08:00
|
|
|
buttonPositive.onPress && buttonPositive.onPress();
|
|
|
|
}
|
|
|
|
} else if (action === NativeModules.DialogManagerAndroid.dismissed) {
|
|
|
|
options && options.onDismiss && options.onDismiss();
|
2015-12-17 11:09:22 -08:00
|
|
|
}
|
2018-05-10 19:06:46 -07:00
|
|
|
},
|
2015-12-17 11:09:22 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Alert;
|