You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Dialog.native.js 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import PropTypes from 'prop-types';
  2. import React from 'react';
  3. import { TextInput } from 'react-native';
  4. import Prompt from 'react-native-prompt';
  5. import { connect } from 'react-redux';
  6. import { translate } from '../../i18n';
  7. import AbstractDialog from './AbstractDialog';
  8. /**
  9. * Implements <tt>AbstractDialog</tt> on react-native using <tt>Prompt</tt>.
  10. */
  11. class Dialog extends AbstractDialog {
  12. /**
  13. * <tt>AbstractDialog</tt>'s React <tt>Component</tt> prop types.
  14. *
  15. * @static
  16. */
  17. static propTypes = {
  18. ...AbstractDialog.propTypes,
  19. /**
  20. * I18n key to put as body title.
  21. */
  22. bodyKey: PropTypes.string
  23. };
  24. /**
  25. * Implements React's {@link Component#render()}.
  26. *
  27. * @inheritdoc
  28. * @returns {ReactElement}
  29. */
  30. render() {
  31. const {
  32. bodyKey,
  33. cancelDisabled,
  34. cancelTitleKey = 'dialog.Cancel',
  35. children,
  36. okDisabled,
  37. okTitleKey = 'dialog.Ok',
  38. t,
  39. titleKey,
  40. titleString
  41. } = this.props;
  42. /* eslint-disable react/jsx-wrap-multilines */
  43. let element
  44. = <Prompt
  45. cancelText = { cancelDisabled ? undefined : t(cancelTitleKey) }
  46. onCancel = { this._onCancel }
  47. onSubmit = { this._onSubmit }
  48. placeholder = { t(bodyKey) }
  49. submitText = { okDisabled ? undefined : t(okTitleKey) }
  50. title = { titleString || t(titleKey) }
  51. visible = { true } />;
  52. /* eslint-enable react/jsx-wrap-multilines */
  53. if (React.Children.count(children)) {
  54. // XXX The following implements a workaround with knowledge of the
  55. // implementation of react-native-prompt.
  56. element
  57. = this._replaceFirstElementOfType(
  58. // eslint-disable-next-line no-extra-parens, new-cap
  59. (new (element.type)(element.props)).render(),
  60. TextInput,
  61. children);
  62. }
  63. return element;
  64. }
  65. /**
  66. * Creates a deep clone of a specific <tt>ReactElement</tt> with the results
  67. * of calling a specific function on every node of a specific
  68. * <tt>ReactElement</tt> tree.
  69. *
  70. * @param {ReactElement} element - The <tt>ReactElement</tt> to clone and
  71. * call the specified <tt>f</tt> on.
  72. * @param {Function} f - The function to call on every node of the
  73. * <tt>ReactElement</tt> tree represented by the specified <tt>element</tt>.
  74. * @private
  75. * @returns {ReactElement}
  76. */
  77. _mapReactElement(element, f) {
  78. if (!element || !element.props || !element.type) {
  79. return element;
  80. }
  81. let mapped = f(element);
  82. if (mapped === element) {
  83. mapped
  84. = React.cloneElement(
  85. element,
  86. /* props */ undefined,
  87. ...React.Children.toArray(React.Children.map(
  88. element.props.children,
  89. function(element) { // eslint-disable-line no-shadow
  90. // eslint-disable-next-line no-invalid-this
  91. return this._mapReactElement(element, f);
  92. },
  93. this)));
  94. }
  95. return mapped;
  96. }
  97. /**
  98. * Replaces the first <tt>ReactElement</tt> of a specific type found in a
  99. * specific <tt>ReactElement</tt> tree with a specific replacement
  100. * <tt>ReactElement</tt>.
  101. *
  102. * @param {ReactElement} element - The <tt>ReactElement</tt> tree to search
  103. * through and replace in.
  104. * @param {*} type - The type of the <tt>ReactElement</tt> to be replaced.
  105. * @param {ReactElement} replacement - The <tt>ReactElement</tt> to replace
  106. * the first <tt>ReactElement</tt> in <tt>element</tt> of the specified
  107. * <tt>type</tt>.
  108. * @private
  109. * @returns {ReactElement}
  110. */
  111. _replaceFirstElementOfType(element, type, replacement) {
  112. // eslint-disable-next-line no-shadow
  113. return this._mapReactElement(element, element => {
  114. if (replacement && element.type === type) {
  115. /* eslint-disable no-param-reassign */
  116. element = replacement;
  117. replacement = undefined;
  118. /* eslint-enable no-param-reassign */
  119. }
  120. return element;
  121. });
  122. }
  123. }
  124. export default translate(connect()(Dialog));