Files
react-native/Libraries/Alert/Alert.js
T
luoxuhai 47bd78f64f Added userInterfaceStyle to Alert to override user interface style for iOS 13+ (#33553)
Summary:
Support to override Alert interface style to match your app. For example, You want to change the style on the alert.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Added] - Add userInterfaceStyle to Alert to override user interface style for iOS 13+

Pull Request resolved: https://github.com/facebook/react-native/pull/33553

Test Plan:
**`userInterfaceStyle: 'light'`:**
<img width="320" src="https://user-images.githubusercontent.com/37284154/161358408-50dbf0a5-ae46-458e-a075-8595cce1b046.png"  />

**`userInterfaceStyle: 'dark'`:**
<img width="320" src="https://user-images.githubusercontent.com/37284154/161358326-bc54effb-1635-43df-97e0-522328713259.PNG"  />

Reviewed By: philIip

Differential Revision: D35371697

Pulled By: ryancat

fbshipit-source-id: 597c1a97ca94571abada2b5fb97cb2adcb5337f5
2022-06-08 18:28:16 -07:00

167 lines
4.8 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
import type {DialogOptions} from '../NativeModules/specs/NativeDialogManagerAndroid';
import Platform from '../Utilities/Platform';
import RCTAlertManager from './RCTAlertManager';
export type AlertType =
| 'default'
| 'plain-text'
| 'secure-text'
| 'login-password';
export type AlertButtonStyle = 'default' | 'cancel' | 'destructive';
export type Buttons = Array<{
text?: string,
onPress?: ?Function,
style?: AlertButtonStyle,
...
}>;
type Options = {
cancelable?: ?boolean,
userInterfaceStyle?: 'unspecified' | 'light' | 'dark',
onDismiss?: ?() => void,
...
};
/**
* Launches an alert dialog with the specified title and message.
*
* See https://reactnative.dev/docs/alert
*/
class Alert {
static alert(
title: ?string,
message?: ?string,
buttons?: Buttons,
options?: Options,
): void {
if (Platform.OS === 'ios') {
Alert.prompt(
title,
message,
buttons,
'default',
undefined,
undefined,
options,
);
} else if (Platform.OS === 'android') {
const NativeDialogManagerAndroid =
require('../NativeModules/specs/NativeDialogManagerAndroid').default;
if (!NativeDialogManagerAndroid) {
return;
}
const constants = NativeDialogManagerAndroid.getConstants();
const config: DialogOptions = {
title: title || '',
message: message || '',
cancelable: false,
};
if (options && options.cancelable) {
config.cancelable = options.cancelable;
}
// At most three buttons (neutral, negative, positive). Ignore rest.
// The text 'OK' should be probably localized. iOS Alert does that in native.
const defaultPositiveText = 'OK';
const validButtons: Buttons = buttons
? buttons.slice(0, 3)
: [{text: defaultPositiveText}];
const buttonPositive = validButtons.pop();
const buttonNegative = validButtons.pop();
const buttonNeutral = validButtons.pop();
if (buttonNeutral) {
config.buttonNeutral = buttonNeutral.text || '';
}
if (buttonNegative) {
config.buttonNegative = buttonNegative.text || '';
}
if (buttonPositive) {
config.buttonPositive = buttonPositive.text || defaultPositiveText;
}
const onAction = (action, buttonKey) => {
if (action === constants.buttonClicked) {
if (buttonKey === constants.buttonNeutral) {
buttonNeutral.onPress && buttonNeutral.onPress();
} else if (buttonKey === constants.buttonNegative) {
buttonNegative.onPress && buttonNegative.onPress();
} else if (buttonKey === constants.buttonPositive) {
buttonPositive.onPress && buttonPositive.onPress();
}
} else if (action === constants.dismissed) {
options && options.onDismiss && options.onDismiss();
}
};
const onError = errorMessage => console.warn(errorMessage);
NativeDialogManagerAndroid.showAlert(config, onError, onAction);
}
}
static prompt(
title: ?string,
message?: ?string,
callbackOrButtons?: ?(((text: string) => void) | Buttons),
type?: ?AlertType = 'plain-text',
defaultValue?: string,
keyboardType?: string,
options?: Options,
): void {
if (Platform.OS === 'ios') {
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: {[number]: string} = {};
btnDef[index] = btn.text || '';
buttons.push(btnDef);
}
});
}
RCTAlertManager.alertWithArgs(
{
title: title || '',
message: message || undefined,
buttons,
type: type || undefined,
defaultValue,
cancelButtonKey,
destructiveButtonKey,
keyboardType,
userInterfaceStyle: options?.userInterfaceStyle || undefined,
},
(id, value) => {
const cb = callbacks[id];
cb && cb(value);
},
);
}
}
}
module.exports = Alert;