Pārlūkot izejas kodu

[RN] Support children in Dialog

j8
Lyubo Marinov 8 gadus atpakaļ
vecāks
revīzija
d0476991a6

+ 21
- 22
react/features/base/dialog/components/AbstractDialog.js Parādīt failu

1
-import React, { Component } from 'react';
1
+import PropTypes from 'prop-types';
2
+import { Component } from 'react';
2
 
3
 
3
 import { hideDialog } from '../actions';
4
 import { hideDialog } from '../actions';
4
 import { DIALOG_PROP_TYPES } from '../constants';
5
 import { DIALOG_PROP_TYPES } from '../constants';
5
 
6
 
6
 /**
7
 /**
7
- * Abstract dialog to display dialogs.
8
+ * An abstract implementation of a dialog on Web/React and mobile/react-native.
8
  */
9
  */
9
 export default class AbstractDialog extends Component {
10
 export default class AbstractDialog extends Component {
10
-
11
     /**
11
     /**
12
-     * Abstract Dialog component's property types.
12
+     * <tt>AbstractDialog</tt> React <tt>Component</tt>'s prop types.
13
      *
13
      *
14
      * @static
14
      * @static
15
      */
15
      */
16
     static propTypes = {
16
     static propTypes = {
17
         ...DIALOG_PROP_TYPES,
17
         ...DIALOG_PROP_TYPES,
18
 
18
 
19
+        /**
20
+         * The React <tt>Component</tt> children of <tt>AbstractDialog</tt>
21
+         * which represents the dialog's body.
22
+         */
23
+        children: PropTypes.node,
24
+
19
         /**
25
         /**
20
          * Used to show/hide the dialog on cancel.
26
          * Used to show/hide the dialog on cancel.
21
          */
27
          */
22
-        dispatch: React.PropTypes.func
28
+        dispatch: PropTypes.func
23
     };
29
     };
24
 
30
 
25
     /**
31
     /**
26
-     * Initializes a new Dialog instance.
32
+     * Initializes a new <tt>AbstractDialog</tt> instance.
27
      *
33
      *
28
-     * @param {Object} props - The read-only properties with which the new
29
-     * instance is to be initialized.
34
+     * @param {Object} props - The read-only React <tt>Component</tt> props with
35
+     * which the new instance is to be initialized.
30
      */
36
      */
31
     constructor(props) {
37
     constructor(props) {
32
         super(props);
38
         super(props);
36
     }
42
     }
37
 
43
 
38
     /**
44
     /**
39
-     * Dispatches action to hide the dialog.
45
+     * Dispatches a redux action to hide this dialog when it's canceled.
40
      *
46
      *
47
+     * @protected
41
      * @returns {void}
48
      * @returns {void}
42
      */
49
      */
43
     _onCancel() {
50
     _onCancel() {
44
-        let hide = true;
51
+        const { onCancel } = this.props;
45
 
52
 
46
-        if (this.props.onCancel) {
47
-            hide = this.props.onCancel();
48
-        }
49
-
50
-        if (hide) {
53
+        if (!onCancel || onCancel()) {
51
             this.props.dispatch(hideDialog());
54
             this.props.dispatch(hideDialog());
52
         }
55
         }
53
     }
56
     }
54
 
57
 
55
     /**
58
     /**
56
-     * Dispatches the action when submitting the dialog.
59
+     * Dispatches a redux action to hide this dialog when it's submitted.
57
      *
60
      *
58
      * @private
61
      * @private
59
      * @param {string} value - The submitted value if any.
62
      * @param {string} value - The submitted value if any.
60
      * @returns {void}
63
      * @returns {void}
61
      */
64
      */
62
     _onSubmit(value) {
65
     _onSubmit(value) {
63
-        let hide = true;
64
-
65
-        if (this.props.onSubmit) {
66
-            hide = this.props.onSubmit(value);
67
-        }
66
+        const { onSubmit } = this.props;
68
 
67
 
69
-        if (hide) {
68
+        if (!onSubmit || onSubmit(value)) {
70
             this.props.dispatch(hideDialog());
69
             this.props.dispatch(hideDialog());
71
         }
70
         }
72
     }
71
     }

+ 102
- 17
react/features/base/dialog/components/Dialog.native.js Parādīt failu

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

+ 7
- 16
react/features/base/dialog/components/Dialog.web.js Parādīt failu

1
+import PropTypes from 'prop-types';
1
 import React from 'react';
2
 import React from 'react';
2
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
3
 
4
 
8
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
9
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
9
  */
10
  */
10
 class Dialog extends AbstractDialog {
11
 class Dialog extends AbstractDialog {
11
-
12
     /**
12
     /**
13
      * Web dialog component's property types.
13
      * Web dialog component's property types.
14
      *
14
      *
17
     static propTypes = {
17
     static propTypes = {
18
         ...AbstractDialog.propTypes,
18
         ...AbstractDialog.propTypes,
19
 
19
 
20
-        /**
21
-         * This is the body of the dialog, the component children.
22
-         */
23
-        children: React.PropTypes.node,
24
-
25
         /**
20
         /**
26
          * Whether the dialog is modal. This means clicking on the blanket will
21
          * Whether the dialog is modal. This means clicking on the blanket will
27
          * leave the dialog open. No cancel button.
22
          * leave the dialog open. No cancel button.
28
          */
23
          */
29
-        isModal: React.PropTypes.bool,
24
+        isModal: PropTypes.bool,
30
 
25
 
31
         /**
26
         /**
32
          * Disables rendering of the submit button.
27
          * Disables rendering of the submit button.
33
          */
28
          */
34
-        submitDisabled: React.PropTypes.bool,
29
+        submitDisabled: PropTypes.bool,
35
 
30
 
36
         /**
31
         /**
37
          * Width of the dialog, can be:
32
          * Width of the dialog, can be:
40
          * - integer value for pixel width
35
          * - integer value for pixel width
41
          * - string value for percentage
36
          * - string value for percentage
42
          */
37
          */
43
-        width: React.PropTypes.string
38
+        width: PropTypes.string
44
     };
39
     };
45
 
40
 
46
     /**
41
     /**
65
     render() {
60
     render() {
66
         const props = {
61
         const props = {
67
             ...this.props,
62
             ...this.props,
68
-            onSubmit: this._onSubmit,
69
-            onCancel: this._onCancel
63
+            onCancel: this._onCancel,
64
+            onSubmit: this._onSubmit
70
         };
65
         };
71
 
66
 
72
         delete props.dispatch;
67
         delete props.dispatch;
80
      * @returns {void}
75
      * @returns {void}
81
      */
76
      */
82
     _onCancel() {
77
     _onCancel() {
83
-        if (this.props.isModal) {
84
-            return;
85
-        }
86
-
87
-        super._onCancel();
78
+        this.props.isModal || super._onCancel();
88
     }
79
     }
89
 }
80
 }
90
 
81
 

+ 10
- 10
react/features/base/dialog/constants.js Parādīt failu

1
-import React from 'react';
1
+import PropTypes from 'prop-types';
2
 
2
 
3
 export const DIALOG_PROP_TYPES = {
3
 export const DIALOG_PROP_TYPES = {
4
     /**
4
     /**
5
      * Whether cancel button is disabled. Enabled by default.
5
      * Whether cancel button is disabled. Enabled by default.
6
      */
6
      */
7
-    cancelDisabled: React.PropTypes.bool,
7
+    cancelDisabled: PropTypes.bool,
8
 
8
 
9
     /**
9
     /**
10
      * Optional i18n key to change the cancel button title.
10
      * Optional i18n key to change the cancel button title.
11
      */
11
      */
12
-    cancelTitleKey: React.PropTypes.string,
12
+    cancelTitleKey: PropTypes.string,
13
 
13
 
14
     /**
14
     /**
15
      * Is ok button enabled/disabled. Enabled by default.
15
      * Is ok button enabled/disabled. Enabled by default.
16
      */
16
      */
17
-    okDisabled: React.PropTypes.bool,
17
+    okDisabled: PropTypes.bool,
18
 
18
 
19
     /**
19
     /**
20
      * Optional i18n key to change the ok button title.
20
      * Optional i18n key to change the ok button title.
21
      */
21
      */
22
-    okTitleKey: React.PropTypes.string,
22
+    okTitleKey: PropTypes.string,
23
 
23
 
24
     /**
24
     /**
25
      * The handler for onCancel event.
25
      * The handler for onCancel event.
26
      */
26
      */
27
-    onCancel: React.PropTypes.func,
27
+    onCancel: PropTypes.func,
28
 
28
 
29
     /**
29
     /**
30
      * The handler for the event when submitting the dialog.
30
      * The handler for the event when submitting the dialog.
31
      */
31
      */
32
-    onSubmit: React.PropTypes.func,
32
+    onSubmit: PropTypes.func,
33
 
33
 
34
     /**
34
     /**
35
      * Used to obtain translations in children classes.
35
      * Used to obtain translations in children classes.
36
      */
36
      */
37
-    t: React.PropTypes.func,
37
+    t: PropTypes.func,
38
 
38
 
39
     /**
39
     /**
40
      * Key to use for showing a title.
40
      * Key to use for showing a title.
41
      */
41
      */
42
-    titleKey: React.PropTypes.string,
42
+    titleKey: PropTypes.string,
43
 
43
 
44
     /**
44
     /**
45
      * The string to use as a title instead of {@code titleKey}. If a truthy
45
      * The string to use as a title instead of {@code titleKey}. If a truthy
46
      * value is specified, it takes precedence over {@code titleKey} i.e.
46
      * value is specified, it takes precedence over {@code titleKey} i.e.
47
      * the latter is unused.
47
      * the latter is unused.
48
      */
48
      */
49
-    titleString: React.PropTypes.string
49
+    titleString: PropTypes.string
50
 };
50
 };

Notiek ielāde…
Atcelt
Saglabāt