Alert.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. */
  10. 'use strict';
  11. import Platform from '../Utilities/Platform';
  12. import NativeDialogManagerAndroid, {
  13. type DialogOptions,
  14. } from '../NativeModules/specs/NativeDialogManagerAndroid';
  15. import RCTAlertManager from './RCTAlertManager';
  16. export type AlertType =
  17. | 'default'
  18. | 'plain-text'
  19. | 'secure-text'
  20. | 'login-password';
  21. export type AlertButtonStyle = 'default' | 'cancel' | 'destructive';
  22. export type Buttons = Array<{
  23. text?: string,
  24. onPress?: ?Function,
  25. style?: AlertButtonStyle,
  26. ...
  27. }>;
  28. type Options = {
  29. cancelable?: ?boolean,
  30. onDismiss?: ?() => void,
  31. ...
  32. };
  33. /**
  34. * Launches an alert dialog with the specified title and message.
  35. *
  36. * See https://reactnative.dev/docs/alert.html
  37. */
  38. class Alert {
  39. static alert(
  40. title: ?string,
  41. message?: ?string,
  42. buttons?: Buttons,
  43. options?: Options,
  44. ): void {
  45. if (Platform.OS === 'ios') {
  46. Alert.prompt(title, message, buttons, 'default');
  47. } else if (Platform.OS === 'android') {
  48. if (!NativeDialogManagerAndroid) {
  49. return;
  50. }
  51. const constants = NativeDialogManagerAndroid.getConstants();
  52. const config: DialogOptions = {
  53. title: title || '',
  54. message: message || '',
  55. cancelable: false,
  56. };
  57. if (options && options.cancelable) {
  58. config.cancelable = options.cancelable;
  59. }
  60. // At most three buttons (neutral, negative, positive). Ignore rest.
  61. // The text 'OK' should be probably localized. iOS Alert does that in native.
  62. const defaultPositiveText = 'OK';
  63. const validButtons: Buttons = buttons
  64. ? buttons.slice(0, 3)
  65. : [{text: defaultPositiveText}];
  66. const buttonPositive = validButtons.pop();
  67. const buttonNegative = validButtons.pop();
  68. const buttonNeutral = validButtons.pop();
  69. if (buttonNeutral) {
  70. config.buttonNeutral = buttonNeutral.text || '';
  71. }
  72. if (buttonNegative) {
  73. config.buttonNegative = buttonNegative.text || '';
  74. }
  75. if (buttonPositive) {
  76. config.buttonPositive = buttonPositive.text || defaultPositiveText;
  77. }
  78. const onAction = (action, buttonKey) => {
  79. if (action === constants.buttonClicked) {
  80. if (buttonKey === constants.buttonNeutral) {
  81. buttonNeutral.onPress && buttonNeutral.onPress();
  82. } else if (buttonKey === constants.buttonNegative) {
  83. buttonNegative.onPress && buttonNegative.onPress();
  84. } else if (buttonKey === constants.buttonPositive) {
  85. buttonPositive.onPress && buttonPositive.onPress();
  86. }
  87. } else if (action === constants.dismissed) {
  88. options && options.onDismiss && options.onDismiss();
  89. }
  90. };
  91. const onError = errorMessage => console.warn(errorMessage);
  92. NativeDialogManagerAndroid.showAlert(config, onError, onAction);
  93. }
  94. }
  95. static prompt(
  96. title: ?string,
  97. message?: ?string,
  98. callbackOrButtons?: ?(((text: string) => void) | Buttons),
  99. type?: ?AlertType = 'plain-text',
  100. defaultValue?: string,
  101. keyboardType?: string,
  102. ): void {
  103. if (Platform.OS === 'ios') {
  104. let callbacks = [];
  105. const buttons = [];
  106. let cancelButtonKey;
  107. let destructiveButtonKey;
  108. if (typeof callbackOrButtons === 'function') {
  109. callbacks = [callbackOrButtons];
  110. } else if (Array.isArray(callbackOrButtons)) {
  111. callbackOrButtons.forEach((btn, index) => {
  112. callbacks[index] = btn.onPress;
  113. if (btn.style === 'cancel') {
  114. cancelButtonKey = String(index);
  115. } else if (btn.style === 'destructive') {
  116. destructiveButtonKey = String(index);
  117. }
  118. if (btn.text || index < (callbackOrButtons || []).length - 1) {
  119. const btnDef = {};
  120. btnDef[index] = btn.text || '';
  121. buttons.push(btnDef);
  122. }
  123. });
  124. }
  125. RCTAlertManager.alertWithArgs(
  126. {
  127. title: title || '',
  128. message: message || undefined,
  129. buttons,
  130. type: type || undefined,
  131. defaultValue,
  132. cancelButtonKey,
  133. destructiveButtonKey,
  134. keyboardType,
  135. },
  136. (id, value) => {
  137. const cb = callbacks[id];
  138. cb && cb(value);
  139. },
  140. );
  141. }
  142. }
  143. }
  144. module.exports = Alert;