Quellcode durchsuchen

fix(chat): maintain bottom scroll on input resize

j8
Leonard Kim vor 6 Jahren
Ursprung
Commit
d86b60ea72

+ 17
- 1
react/features/chat/components/web/Chat.js Datei anzeigen

47
 
47
 
48
         // Bind event handlers so they are only bound once for every instance.
48
         // Bind event handlers so they are only bound once for every instance.
49
         this._renderPanelContent = this._renderPanelContent.bind(this);
49
         this._renderPanelContent = this._renderPanelContent.bind(this);
50
+
51
+        // Bind event handlers so they are only bound once for every instance.
52
+        this._onChatInputResize = this._onChatInputResize.bind(this);
50
     }
53
     }
51
 
54
 
52
     /**
55
     /**
87
         );
90
         );
88
     }
91
     }
89
 
92
 
93
+    _onChatInputResize: () => void;
94
+
95
+    /**
96
+     * Callback invoked when {@code ChatInput} changes height. Preserves
97
+     * displaying the latest message if it is scrolled to.
98
+     *
99
+     * @private
100
+     * @returns {void}
101
+     */
102
+    _onChatInputResize() {
103
+        this._messageContainerRef.current.maybeUpdateBottomScroll();
104
+    }
105
+
90
     /**
106
     /**
91
      * Returns a React Element for showing chat messages and a form to send new
107
      * Returns a React Element for showing chat messages and a form to send new
92
      * chat messages.
108
      * chat messages.
100
                 <MessageContainer
116
                 <MessageContainer
101
                     messages = { this.props._messages }
117
                     messages = { this.props._messages }
102
                     ref = { this._messageContainerRef } />
118
                     ref = { this._messageContainerRef } />
103
-                <ChatInput />
119
+                <ChatInput onResize = { this._onChatInputResize } />
104
             </>
120
             </>
105
         );
121
         );
106
     }
122
     }

+ 7
- 0
react/features/chat/components/web/ChatInput.js Datei anzeigen

22
      */
22
      */
23
     dispatch: Dispatch<any>,
23
     dispatch: Dispatch<any>,
24
 
24
 
25
+    /**
26
+     * Optional callback to invoke when the chat textarea has auto-resized to
27
+     * fit overflowing text.
28
+     */
29
+    onResize: ?Function,
30
+
25
     /**
31
     /**
26
      * Invoked to obtain translated strings.
32
      * Invoked to obtain translated strings.
27
      */
33
      */
120
                         inputRef = { this._setTextAreaRef }
126
                         inputRef = { this._setTextAreaRef }
121
                         maxRows = { 5 }
127
                         maxRows = { 5 }
122
                         onChange = { this._onMessageChange }
128
                         onChange = { this._onMessageChange }
129
+                        onHeightChange = { this.props.onResize }
123
                         onKeyDown = { this._onDetectSubmit }
130
                         onKeyDown = { this._onDetectSubmit }
124
                         placeholder = { this.props.t('chat.messagebox') }
131
                         placeholder = { this.props.t('chat.messagebox') }
125
                         value = { this.state.message } />
132
                         value = { this.state.message } />

+ 50
- 1
react/features/chat/components/web/MessageContainer.js Datei anzeigen

13
  * @extends AbstractMessageContainer
13
  * @extends AbstractMessageContainer
14
  */
14
  */
15
 export default class MessageContainer extends AbstractMessageContainer {
15
 export default class MessageContainer extends AbstractMessageContainer {
16
+    /**
17
+     * Whether or not chat has been scrolled to the bottom of the screen. Used
18
+     * to determine if chat should be scrolled automatically to the bottom when
19
+     * the {@code ChatInput} resizes.
20
+     */
21
+    _isScrolledToBottom: boolean;
22
+
16
     /**
23
     /**
17
      * Reference to the HTML element at the end of the list of displayed chat
24
      * Reference to the HTML element at the end of the list of displayed chat
18
      * messages. Used for scrolling to the end of the chat messages.
25
      * messages. Used for scrolling to the end of the chat messages.
19
      */
26
      */
20
     _messagesListEndRef: Object;
27
     _messagesListEndRef: Object;
21
 
28
 
29
+    /**
30
+     * A React ref to the HTML element containing all {@code ChatMessageGroup}
31
+     * instances.
32
+     */
33
+    _messageListRef: Object;
34
+
22
     /**
35
     /**
23
      * Initializes a new {@code MessageContainer} instance.
36
      * Initializes a new {@code MessageContainer} instance.
24
      *
37
      *
28
     constructor(props: Props) {
41
     constructor(props: Props) {
29
         super(props);
42
         super(props);
30
 
43
 
44
+        this._isScrolledToBottom = true;
45
+
46
+        this._messageListRef = React.createRef();
31
         this._messagesListEndRef = React.createRef();
47
         this._messagesListEndRef = React.createRef();
48
+
49
+        this._onChatScroll = this._onChatScroll.bind(this);
32
     }
50
     }
33
 
51
 
34
     /**
52
     /**
50
         });
68
         });
51
 
69
 
52
         return (
70
         return (
53
-            <div id = 'chatconversation'>
71
+            <div
72
+                id = 'chatconversation'
73
+                onScroll = { this._onChatScroll }
74
+                ref = { this._messageListRef }>
54
                 { messages }
75
                 { messages }
55
                 <div ref = { this._messagesListEndRef } />
76
                 <div ref = { this._messagesListEndRef } />
56
             </div>
77
             </div>
57
         );
78
         );
58
     }
79
     }
59
 
80
 
81
+    /**
82
+     * Scrolls to the bottom again if the instance had previously been scrolled
83
+     * to the bottom. This method is used when a resize has occurred below the
84
+     * instance and bottom scroll needs to be maintained.
85
+     *
86
+     * @returns {void}
87
+     */
88
+    maybeUpdateBottomScroll() {
89
+        if (this._isScrolledToBottom) {
90
+            this.scrollToBottom(false);
91
+        }
92
+    }
93
+
60
     /**
94
     /**
61
      * Automatically scrolls the displayed chat messages down to the latest.
95
      * Automatically scrolls the displayed chat messages down to the latest.
62
      *
96
      *
71
     }
105
     }
72
 
106
 
73
     _getMessagesGroupedBySender: () => Array<Array<Object>>;
107
     _getMessagesGroupedBySender: () => Array<Array<Object>>;
108
+
109
+    _onChatScroll: () => void;
110
+
111
+    /**
112
+     * Callback invoked to listen to the current scroll location.
113
+     *
114
+     * @private
115
+     * @returns {void}
116
+     */
117
+    _onChatScroll() {
118
+        const element = this._messageListRef.current;
119
+
120
+        this._isScrolledToBottom
121
+            = element.scrollHeight - element.scrollTop === element.clientHeight;
122
+    }
74
 }
123
 }

Laden…
Abbrechen
Speichern