Bläddra i källkod

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 år sedan
förälder
incheckning
fdee6dc360

+ 22
- 0
css/_videolayout_default.scss Visa fil

378
 .remote-video-menu-trigger {
378
 .remote-video-menu-trigger {
379
     margin-top: 7px;
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
  * Audio indicator on video thumbnails.
405
  * Audio indicator on video thumbnails.

+ 34
- 26
react/features/connection-indicator/components/ConnectionIndicator.js Visa fil

1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
3
 
3
 
4
 import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
4
 import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
123
         };
123
         };
124
 
124
 
125
         // Bind event handlers so they are only bound once for every instance.
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
         this._onStatsUpdated = this._onStatsUpdated.bind(this);
128
         this._onStatsUpdated = this._onStatsUpdated.bind(this);
130
         this._onToggleShowMore = this._onToggleShowMore.bind(this);
129
         this._onToggleShowMore = this._onToggleShowMore.bind(this);
131
     }
130
     }
175
      */
174
      */
176
     render() {
175
     render() {
177
         return (
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
                     content = { this._renderStatisticsTable() }
182
                     content = { this._renderStatisticsTable() }
181
                     isOpen = { this.state.showStats }
183
                     isOpen = { this.state.showStats }
182
-                    onClose = { this._onStatsClose }
183
                     position = { this.props.statsPopoverPosition }>
184
                     position = { this.props.statsPopoverPosition }>
184
-                    <div
185
-                        className = 'popover-trigger'
186
-                        onClick = { this._onStatsToggle }>
185
+                    <div className = 'popover-trigger'>
187
                         <div className = 'connection-indicator indicator'>
186
                         <div className = 'connection-indicator indicator'>
188
                             <div className = 'connection indicatoricon'>
187
                             <div className = 'connection indicatoricon'>
189
                                 { this._renderIcon() }
188
                                 { this._renderIcon() }
190
                             </div>
189
                             </div>
191
                         </div>
190
                         </div>
192
                     </div>
191
                     </div>
193
-                </AKInlineDialog>
192
+                </Popover>
194
             </div>
193
             </div>
195
         );
194
         );
196
     }
195
     }
201
      * @private
200
      * @private
202
      * @returns {void}
201
      * @returns {void}
203
      */
202
      */
204
-    _onStatsClose() {
203
+    _onHideStats() {
205
         this.setState({ showStats: false });
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
      * @private
210
      * @private
212
      * @returns {void}
211
      * @returns {void}
213
      */
212
      */
214
-    _onStatsToggle() {
213
+    _onShowStats() {
215
         if (this.props.enableStatsDisplay) {
214
         if (this.props.enableStatsDisplay) {
216
-            this.setState({ showStats: !this.state.showStats });
215
+            this.setState({ showStats: true });
217
         }
216
         }
218
     }
217
     }
219
 
218
 
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
      * @returns {ReactElement}
302
      * @returns {ReactElement}
302
      */
303
      */
311
         } = this.state.stats;
312
         } = this.state.stats;
312
 
313
 
313
         return (
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 Visa fil

1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
3
 
3
 
4
 import {
4
 import {
88
         this._rootElement = null;
88
         this._rootElement = null;
89
 
89
 
90
         // Bind event handlers so they are only bound once for every instance.
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
         }
106
         }
107
 
107
 
108
         return (
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
      * @private
131
      * @private
131
      * @returns {void}
132
      * @returns {void}
132
      */
133
      */
133
-    _onRemoteMenuClose() {
134
+    _onHideRemoteMenu() {
134
         this.setState({ showRemoteMenu: false });
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
      * @private
141
      * @private
141
      * @returns {void}
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
                 <MuteButton
172
                 <MuteButton
176
                     isAudioMuted = { isAudioMuted }
173
                     isAudioMuted = { isAudioMuted }
177
                     key = 'mute'
174
                     key = 'mute'
178
-                    onClick = { this._onRemoteMenuClose }
175
+                    onClick = { this._onHideRemoteMenu }
179
                     participantID = { participantID } />
176
                     participantID = { participantID } />
180
             );
177
             );
181
             buttons.push(
178
             buttons.push(
182
                 <KickButton
179
                 <KickButton
183
                     key = 'kick'
180
                     key = 'kick'
184
-                    onClick = { this._onRemoteMenuClose }
181
+                    onClick = { this._onHideRemoteMenu }
185
                     participantID = { participantID } />
182
                     participantID = { participantID } />
186
             );
183
             );
187
         }
184
         }
207
 
204
 
208
         if (buttons.length > 0) {
205
         if (buttons.length > 0) {
209
             return (
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 Visa fil

1
-import AKInlineDialog from '@atlaskit/inline-dialog';
1
+import { default as Popover } from '@atlaskit/inline-dialog';
2
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
3
 import { connect } from 'react-redux';
3
 import { connect } from 'react-redux';
4
 
4
 
106
         };
106
         };
107
 
107
 
108
         // Bind event handlers so they are only bound once for every instance.
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
         return (
163
         return (
164
             <div
164
             <div
165
                 className = { classNames }
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
                     isOpen = { this.state.showVideoQualityDialog }
171
                     isOpen = { this.state.showVideoQualityDialog }
170
-                    onClose = { this._onDialogClose }
171
                     position = { 'left top' }>
172
                     position = { 'left top' }>
172
                     <div
173
                     <div
173
-                        className = 'video-quality-label-status'
174
-                        onClick = { this._onDialogToggle }>
174
+                        className = 'video-quality-label-status'>
175
                         { _audioOnly
175
                         { _audioOnly
176
                             ? <i className = 'icon-visibility-off' />
176
                             ? <i className = 'icon-visibility-off' />
177
                             : this._mapResolutionToTranslation(_resolution) }
177
                             : this._mapResolutionToTranslation(_resolution) }
178
                     </div>
178
                     </div>
179
-                </AKInlineDialog>
179
+                </Popover>
180
             </div>
180
             </div>
181
         );
181
         );
182
     }
182
     }
211
     }
211
     }
212
 
212
 
213
     /**
213
     /**
214
-     * Toggles the display of the {@code VideoQualityDialog}.
214
+     * Shows the {@code VideoQualityDialog}.
215
      *
215
      *
216
      * @private
216
      * @private
217
      * @returns {void}
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
      * @private
226
      * @private
229
      * @returns {void}
227
      * @returns {void}
230
      */
228
      */
231
-    _onDialogClose() {
229
+    _onHideQualityDialog() {
232
         this.setState({ showVideoQualityDialog: false });
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
 /**

Laddar…
Avbryt
Spara