ソースを参照

fix(inline-dialog): reimplement popover display on mouse move

Create empty elements within InlineDialog content that can be
used to bridge mouse movement from the InlineDialog trigger to
the InlineDialog content. The empty elements are positioned
absolute so they can break out of the InlineDialog container
and not affect popper's position calculations.
master
Leonard Kim 7年前
コミット
fdee6dc360

+ 22
- 0
css/_videolayout_default.scss ファイルの表示

@@ -378,6 +378,28 @@
378 378
 .remote-video-menu-trigger {
379 379
     margin-top: 7px;
380 380
 }
381
+.popover-mousemove-padding-bottom {
382
+    bottom: -15px;
383
+    height: 20px;
384
+    position: absolute;
385
+    right: 0;
386
+    width: 100%;
387
+}
388
+.popover-mousemove-padding-right {
389
+    height: 100%;
390
+    position: absolute;
391
+    right: -20;
392
+    top: 0;
393
+    width: 40px;
394
+}
395
+
396
+.popover-mouse-top-padding {
397
+    height: 30px;
398
+    position: absolute;
399
+    right: 0;
400
+    top: -25px;
401
+    width: 100%;
402
+}
381 403
 
382 404
 /**
383 405
  * Audio indicator on video thumbnails.

+ 34
- 26
react/features/connection-indicator/components/ConnectionIndicator.js ファイルの表示

@@ -1,4 +1,4 @@
1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2 2
 import React, { Component } from 'react';
3 3
 
4 4
 import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
@@ -123,9 +123,8 @@ class ConnectionIndicator extends Component {
123 123
         };
124 124
 
125 125
         // Bind event handlers so they are only bound once for every instance.
126
-        this._onStatsUpdated = this._onStatsUpdated.bind(this);
127
-        this._onStatsClose = this._onStatsClose.bind(this);
128
-        this._onStatsToggle = this._onStatsToggle.bind(this);
126
+        this._onHideStats = this._onHideStats.bind(this);
127
+        this._onShowStats = this._onShowStats.bind(this);
129 128
         this._onStatsUpdated = this._onStatsUpdated.bind(this);
130 129
         this._onToggleShowMore = this._onToggleShowMore.bind(this);
131 130
     }
@@ -175,22 +174,22 @@ class ConnectionIndicator extends Component {
175 174
      */
176 175
     render() {
177 176
         return (
178
-            <div className = 'indicator-container'>
179
-                <AKInlineDialog
177
+            <div
178
+                className = 'indicator-container'
179
+                onMouseEnter = { this._onShowStats }
180
+                onMouseLeave = { this._onHideStats }>
181
+                <Popover
180 182
                     content = { this._renderStatisticsTable() }
181 183
                     isOpen = { this.state.showStats }
182
-                    onClose = { this._onStatsClose }
183 184
                     position = { this.props.statsPopoverPosition }>
184
-                    <div
185
-                        className = 'popover-trigger'
186
-                        onClick = { this._onStatsToggle }>
185
+                    <div className = 'popover-trigger'>
187 186
                         <div className = 'connection-indicator indicator'>
188 187
                             <div className = 'connection indicatoricon'>
189 188
                                 { this._renderIcon() }
190 189
                             </div>
191 190
                         </div>
192 191
                     </div>
193
-                </AKInlineDialog>
192
+                </Popover>
194 193
             </div>
195 194
         );
196 195
     }
@@ -201,19 +200,19 @@ class ConnectionIndicator extends Component {
201 200
      * @private
202 201
      * @returns {void}
203 202
      */
204
-    _onStatsClose() {
203
+    _onHideStats() {
205 204
         this.setState({ showStats: false });
206 205
     }
207 206
 
208 207
     /**
209
-     * Sets the state to show or hide the Statistics Table popover.
208
+     * Sets the state to show the Statistics Table popover.
210 209
      *
211 210
      * @private
212 211
      * @returns {void}
213 212
      */
214
-    _onStatsToggle() {
213
+    _onShowStats() {
215 214
         if (this.props.enableStatsDisplay) {
216
-            this.setState({ showStats: !this.state.showStats });
215
+            this.setState({ showStats: true });
217 216
         }
218 217
     }
219 218
 
@@ -296,7 +295,9 @@ class ConnectionIndicator extends Component {
296 295
     }
297 296
 
298 297
     /**
299
-     * Creates a {@code ConnectionStatisticsTable} instance.
298
+     * Creates a {@code ConnectionStatisticsTable} instance and an empty div
299
+     * for preventing mouseleave events when moving from the icon to the
300
+     * popover.
300 301
      *
301 302
      * @returns {ReactElement}
302 303
      */
@@ -311,16 +312,23 @@ class ConnectionIndicator extends Component {
311 312
         } = this.state.stats;
312 313
 
313 314
         return (
314
-            <ConnectionStatsTable
315
-                bandwidth = { bandwidth }
316
-                bitrate = { bitrate }
317
-                framerate = { framerate }
318
-                isLocalVideo = { this.props.isLocalVideo }
319
-                onShowMore = { this._onToggleShowMore }
320
-                packetLoss = { packetLoss }
321
-                resolution = { resolution }
322
-                shouldShowMore = { this.state.showMoreStats }
323
-                transport = { transport } />
315
+            <div>
316
+                <ConnectionStatsTable
317
+                    bandwidth = { bandwidth }
318
+                    bitrate = { bitrate }
319
+                    framerate = { framerate }
320
+                    isLocalVideo = { this.props.isLocalVideo }
321
+                    onShowMore = { this._onToggleShowMore }
322
+                    packetLoss = { packetLoss }
323
+                    resolution = { resolution }
324
+                    shouldShowMore = { this.state.showMoreStats }
325
+                    transport = { transport } />
326
+                <div className = 'popover-mouse-top-padding' />
327
+                <div
328
+                    className = { interfaceConfig.VERTICAL_FILMSTRIP
329
+                        ? 'popover-mousemove-padding-right'
330
+                        : 'popover-mousemove-padding-bottom' } />
331
+            </div>
324 332
         );
325 333
     }
326 334
 }

+ 35
- 32
react/features/remote-video-menu/components/RemoteVideoMenuTriggerButton.js ファイルの表示

@@ -1,4 +1,4 @@
1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2 2
 import React, { Component } from 'react';
3 3
 
4 4
 import {
@@ -88,8 +88,8 @@ class RemoteVideoMenuTriggerButton extends Component {
88 88
         this._rootElement = null;
89 89
 
90 90
         // Bind event handlers so they are only bound once for every instance.
91
-        this._onRemoteMenuClose = this._onRemoteMenuClose.bind(this);
92
-        this._onRemoteMenuToggle = this._onRemoteMenuToggle.bind(this);
91
+        this._onHideRemoteMenu = this._onHideRemoteMenu.bind(this);
92
+        this._onShowRemoteMenu = this._onShowRemoteMenu.bind(this);
93 93
     }
94 94
 
95 95
     /**
@@ -106,21 +106,22 @@ class RemoteVideoMenuTriggerButton extends Component {
106 106
         }
107 107
 
108 108
         return (
109
-            <AKInlineDialog
110
-                content = { content }
111
-                isOpen = { this.state.showRemoteMenu }
112
-                onClose = { this._onRemoteMenuClose }
113
-                position = { interfaceConfig.VERTICAL_FILMSTRIP
114
-                    ? 'left middle' : 'top center' }
115
-                shouldFlip = { true }>
116
-                <span
117
-                    className = 'popover-trigger remote-video-menu-trigger'
118
-                    onClick = { this._onRemoteMenuToggle }>
119
-                    <i
120
-                        className = 'icon-thumb-menu'
121
-                        title = 'Remote user controls' />
122
-                </span>
123
-            </AKInlineDialog>
109
+            <div
110
+                onMouseEnter = { this._onShowRemoteMenu }
111
+                onMouseLeave = { this._onHideRemoteMenu }>
112
+                <Popover
113
+                    content = { content }
114
+                    isOpen = { this.state.showRemoteMenu }
115
+                    position = { interfaceConfig.VERTICAL_FILMSTRIP
116
+                        ? 'left middle' : 'top center' }>
117
+                    <span
118
+                        className = 'popover-trigger remote-video-menu-trigger'>
119
+                        <i
120
+                            className = 'icon-thumb-menu'
121
+                            title = 'Remote user controls' />
122
+                    </span>
123
+                </Popover>
124
+            </div>
124 125
         );
125 126
     }
126 127
 
@@ -130,24 +131,20 @@ class RemoteVideoMenuTriggerButton extends Component {
130 131
      * @private
131 132
      * @returns {void}
132 133
      */
133
-    _onRemoteMenuClose() {
134
+    _onHideRemoteMenu() {
134 135
         this.setState({ showRemoteMenu: false });
135 136
     }
136 137
 
137 138
     /**
138
-     * Opens or closes the {@code RemoteVideoMenu}.
139
+     * Opens the {@code RemoteVideoMenu}.
139 140
      *
140 141
      * @private
141 142
      * @returns {void}
142 143
      */
143
-    _onRemoteMenuToggle() {
144
-        const willShowRemoteMenu = !this.state.showRemoteMenu;
144
+    _onShowRemoteMenu() {
145
+        this.props.onMenuDisplay();
145 146
 
146
-        if (willShowRemoteMenu) {
147
-            this.props.onMenuDisplay();
148
-        }
149
-
150
-        this.setState({ showRemoteMenu: willShowRemoteMenu });
147
+        this.setState({ showRemoteMenu: true });
151 148
     }
152 149
 
153 150
     /**
@@ -175,13 +172,13 @@ class RemoteVideoMenuTriggerButton extends Component {
175 172
                 <MuteButton
176 173
                     isAudioMuted = { isAudioMuted }
177 174
                     key = 'mute'
178
-                    onClick = { this._onRemoteMenuClose }
175
+                    onClick = { this._onHideRemoteMenu }
179 176
                     participantID = { participantID } />
180 177
             );
181 178
             buttons.push(
182 179
                 <KickButton
183 180
                     key = 'kick'
184
-                    onClick = { this._onRemoteMenuClose }
181
+                    onClick = { this._onHideRemoteMenu }
185 182
                     participantID = { participantID } />
186 183
             );
187 184
         }
@@ -207,9 +204,15 @@ class RemoteVideoMenuTriggerButton extends Component {
207 204
 
208 205
         if (buttons.length > 0) {
209 206
             return (
210
-                <RemoteVideoMenu id = { participantID }>
211
-                    { buttons }
212
-                </RemoteVideoMenu>
207
+                <div>
208
+                    <RemoteVideoMenu id = { participantID }>
209
+                        { buttons }
210
+                    </RemoteVideoMenu>
211
+                    <div
212
+                        className = { interfaceConfig.VERTICAL_FILMSTRIP
213
+                            ? 'popover-mousemove-padding-right'
214
+                            : 'popover-mousemove-padding-bottom' } />
215
+                </div>
213 216
             );
214 217
         }
215 218
 

+ 30
- 17
react/features/video-quality/components/VideoQualityLabel.web.js ファイルの表示

@@ -1,4 +1,4 @@
1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2 2
 import React, { Component } from 'react';
3 3
 import { connect } from 'react-redux';
4 4
 
@@ -106,8 +106,8 @@ export class VideoQualityLabel extends Component {
106 106
         };
107 107
 
108 108
         // Bind event handlers so they are only bound once for every instance.
109
-        this._onDialogClose = this._onDialogClose.bind(this);
110
-        this._onDialogToggle = this._onDialogToggle.bind(this);
109
+        this._onHideQualityDialog = this._onHideQualityDialog.bind(this);
110
+        this._onShowQualityDialog = this._onShowQualityDialog.bind(this);
111 111
     }
112 112
 
113 113
     /**
@@ -163,20 +163,20 @@ export class VideoQualityLabel extends Component {
163 163
         return (
164 164
             <div
165 165
                 className = { classNames }
166
-                id = 'videoResolutionLabel'>
167
-                <AKInlineDialog
168
-                    content = { <VideoQualityDialog /> }
166
+                id = 'videoResolutionLabel'
167
+                onMouseEnter = { this._onShowQualityDialog }
168
+                onMouseLeave = { this._onHideQualityDialog }>
169
+                <Popover
170
+                    content = { this._renderQualityDialog() }
169 171
                     isOpen = { this.state.showVideoQualityDialog }
170
-                    onClose = { this._onDialogClose }
171 172
                     position = { 'left top' }>
172 173
                     <div
173
-                        className = 'video-quality-label-status'
174
-                        onClick = { this._onDialogToggle }>
174
+                        className = 'video-quality-label-status'>
175 175
                         { _audioOnly
176 176
                             ? <i className = 'icon-visibility-off' />
177 177
                             : this._mapResolutionToTranslation(_resolution) }
178 178
                     </div>
179
-                </AKInlineDialog>
179
+                </Popover>
180 180
             </div>
181 181
         );
182 182
     }
@@ -211,26 +211,39 @@ export class VideoQualityLabel extends Component {
211 211
     }
212 212
 
213 213
     /**
214
-     * Toggles the display of the {@code VideoQualityDialog}.
214
+     * Shows the {@code VideoQualityDialog}.
215 215
      *
216 216
      * @private
217 217
      * @returns {void}
218 218
      */
219
-    _onDialogToggle() {
220
-        this.setState({
221
-            showVideoQualityDialog: !this.state.showVideoQualityDialog
222
-        });
219
+    _onShowQualityDialog() {
220
+        this.setState({ showVideoQualityDialog: true });
223 221
     }
224 222
 
225 223
     /**
226
-     * Hides the attached inline dialog.
224
+     * Hides the {@code VideoQualityDialog}.
227 225
      *
228 226
      * @private
229 227
      * @returns {void}
230 228
      */
231
-    _onDialogClose() {
229
+    _onHideQualityDialog() {
232 230
         this.setState({ showVideoQualityDialog: false });
233 231
     }
232
+
233
+    /**
234
+     * Returns a React Element for choosing a maximum receive video quality.
235
+     *
236
+     * @private
237
+     * @returns {ReactElement}
238
+     */
239
+    _renderQualityDialog() {
240
+        return (
241
+            <div>
242
+                <VideoQualityDialog />
243
+                <div className = 'popover-mousemove-padding-right' />
244
+            </div>
245
+        );
246
+    }
234 247
 }
235 248
 
236 249
 /**

読み込み中…
キャンセル
保存