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.
This commit is contained in:
parent
5f55b3198c
commit
fdee6dc360
|
@ -378,6 +378,28 @@
|
|||
.remote-video-menu-trigger {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.popover-mousemove-padding-bottom {
|
||||
bottom: -15px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.popover-mousemove-padding-right {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: -20;
|
||||
top: 0;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.popover-mouse-top-padding {
|
||||
height: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -25px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio indicator on video thumbnails.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import AKInlineDialog from '@atlaskit/inline-dialog';
|
||||
import { default as Popover } from '@atlaskit/inline-dialog';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { JitsiParticipantConnectionStatus } from '../../base/lib-jitsi-meet';
|
||||
|
@ -123,9 +123,8 @@ class ConnectionIndicator extends Component {
|
|||
};
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onStatsUpdated = this._onStatsUpdated.bind(this);
|
||||
this._onStatsClose = this._onStatsClose.bind(this);
|
||||
this._onStatsToggle = this._onStatsToggle.bind(this);
|
||||
this._onHideStats = this._onHideStats.bind(this);
|
||||
this._onShowStats = this._onShowStats.bind(this);
|
||||
this._onStatsUpdated = this._onStatsUpdated.bind(this);
|
||||
this._onToggleShowMore = this._onToggleShowMore.bind(this);
|
||||
}
|
||||
|
@ -175,22 +174,22 @@ class ConnectionIndicator extends Component {
|
|||
*/
|
||||
render() {
|
||||
return (
|
||||
<div className = 'indicator-container'>
|
||||
<AKInlineDialog
|
||||
<div
|
||||
className = 'indicator-container'
|
||||
onMouseEnter = { this._onShowStats }
|
||||
onMouseLeave = { this._onHideStats }>
|
||||
<Popover
|
||||
content = { this._renderStatisticsTable() }
|
||||
isOpen = { this.state.showStats }
|
||||
onClose = { this._onStatsClose }
|
||||
position = { this.props.statsPopoverPosition }>
|
||||
<div
|
||||
className = 'popover-trigger'
|
||||
onClick = { this._onStatsToggle }>
|
||||
<div className = 'popover-trigger'>
|
||||
<div className = 'connection-indicator indicator'>
|
||||
<div className = 'connection indicatoricon'>
|
||||
{ this._renderIcon() }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AKInlineDialog>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -201,19 +200,19 @@ class ConnectionIndicator extends Component {
|
|||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onStatsClose() {
|
||||
_onHideStats() {
|
||||
this.setState({ showStats: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state to show or hide the Statistics Table popover.
|
||||
* Sets the state to show the Statistics Table popover.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onStatsToggle() {
|
||||
_onShowStats() {
|
||||
if (this.props.enableStatsDisplay) {
|
||||
this.setState({ showStats: !this.state.showStats });
|
||||
this.setState({ showStats: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,7 +295,9 @@ class ConnectionIndicator extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code ConnectionStatisticsTable} instance.
|
||||
* Creates a {@code ConnectionStatisticsTable} instance and an empty div
|
||||
* for preventing mouseleave events when moving from the icon to the
|
||||
* popover.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
|
@ -311,16 +312,23 @@ class ConnectionIndicator extends Component {
|
|||
} = this.state.stats;
|
||||
|
||||
return (
|
||||
<ConnectionStatsTable
|
||||
bandwidth = { bandwidth }
|
||||
bitrate = { bitrate }
|
||||
framerate = { framerate }
|
||||
isLocalVideo = { this.props.isLocalVideo }
|
||||
onShowMore = { this._onToggleShowMore }
|
||||
packetLoss = { packetLoss }
|
||||
resolution = { resolution }
|
||||
shouldShowMore = { this.state.showMoreStats }
|
||||
transport = { transport } />
|
||||
<div>
|
||||
<ConnectionStatsTable
|
||||
bandwidth = { bandwidth }
|
||||
bitrate = { bitrate }
|
||||
framerate = { framerate }
|
||||
isLocalVideo = { this.props.isLocalVideo }
|
||||
onShowMore = { this._onToggleShowMore }
|
||||
packetLoss = { packetLoss }
|
||||
resolution = { resolution }
|
||||
shouldShowMore = { this.state.showMoreStats }
|
||||
transport = { transport } />
|
||||
<div className = 'popover-mouse-top-padding' />
|
||||
<div
|
||||
className = { interfaceConfig.VERTICAL_FILMSTRIP
|
||||
? 'popover-mousemove-padding-right'
|
||||
: 'popover-mousemove-padding-bottom' } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import AKInlineDialog from '@atlaskit/inline-dialog';
|
||||
import { default as Popover } from '@atlaskit/inline-dialog';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import {
|
||||
|
@ -88,8 +88,8 @@ class RemoteVideoMenuTriggerButton extends Component {
|
|||
this._rootElement = null;
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onRemoteMenuClose = this._onRemoteMenuClose.bind(this);
|
||||
this._onRemoteMenuToggle = this._onRemoteMenuToggle.bind(this);
|
||||
this._onHideRemoteMenu = this._onHideRemoteMenu.bind(this);
|
||||
this._onShowRemoteMenu = this._onShowRemoteMenu.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,21 +106,22 @@ class RemoteVideoMenuTriggerButton extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<AKInlineDialog
|
||||
content = { content }
|
||||
isOpen = { this.state.showRemoteMenu }
|
||||
onClose = { this._onRemoteMenuClose }
|
||||
position = { interfaceConfig.VERTICAL_FILMSTRIP
|
||||
? 'left middle' : 'top center' }
|
||||
shouldFlip = { true }>
|
||||
<span
|
||||
className = 'popover-trigger remote-video-menu-trigger'
|
||||
onClick = { this._onRemoteMenuToggle }>
|
||||
<i
|
||||
className = 'icon-thumb-menu'
|
||||
title = 'Remote user controls' />
|
||||
</span>
|
||||
</AKInlineDialog>
|
||||
<div
|
||||
onMouseEnter = { this._onShowRemoteMenu }
|
||||
onMouseLeave = { this._onHideRemoteMenu }>
|
||||
<Popover
|
||||
content = { content }
|
||||
isOpen = { this.state.showRemoteMenu }
|
||||
position = { interfaceConfig.VERTICAL_FILMSTRIP
|
||||
? 'left middle' : 'top center' }>
|
||||
<span
|
||||
className = 'popover-trigger remote-video-menu-trigger'>
|
||||
<i
|
||||
className = 'icon-thumb-menu'
|
||||
title = 'Remote user controls' />
|
||||
</span>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -130,24 +131,20 @@ class RemoteVideoMenuTriggerButton extends Component {
|
|||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onRemoteMenuClose() {
|
||||
_onHideRemoteMenu() {
|
||||
this.setState({ showRemoteMenu: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens or closes the {@code RemoteVideoMenu}.
|
||||
* Opens the {@code RemoteVideoMenu}.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onRemoteMenuToggle() {
|
||||
const willShowRemoteMenu = !this.state.showRemoteMenu;
|
||||
_onShowRemoteMenu() {
|
||||
this.props.onMenuDisplay();
|
||||
|
||||
if (willShowRemoteMenu) {
|
||||
this.props.onMenuDisplay();
|
||||
}
|
||||
|
||||
this.setState({ showRemoteMenu: willShowRemoteMenu });
|
||||
this.setState({ showRemoteMenu: true });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,13 +172,13 @@ class RemoteVideoMenuTriggerButton extends Component {
|
|||
<MuteButton
|
||||
isAudioMuted = { isAudioMuted }
|
||||
key = 'mute'
|
||||
onClick = { this._onRemoteMenuClose }
|
||||
onClick = { this._onHideRemoteMenu }
|
||||
participantID = { participantID } />
|
||||
);
|
||||
buttons.push(
|
||||
<KickButton
|
||||
key = 'kick'
|
||||
onClick = { this._onRemoteMenuClose }
|
||||
onClick = { this._onHideRemoteMenu }
|
||||
participantID = { participantID } />
|
||||
);
|
||||
}
|
||||
|
@ -207,9 +204,15 @@ class RemoteVideoMenuTriggerButton extends Component {
|
|||
|
||||
if (buttons.length > 0) {
|
||||
return (
|
||||
<RemoteVideoMenu id = { participantID }>
|
||||
{ buttons }
|
||||
</RemoteVideoMenu>
|
||||
<div>
|
||||
<RemoteVideoMenu id = { participantID }>
|
||||
{ buttons }
|
||||
</RemoteVideoMenu>
|
||||
<div
|
||||
className = { interfaceConfig.VERTICAL_FILMSTRIP
|
||||
? 'popover-mousemove-padding-right'
|
||||
: 'popover-mousemove-padding-bottom' } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import AKInlineDialog from '@atlaskit/inline-dialog';
|
||||
import { default as Popover } from '@atlaskit/inline-dialog';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
@ -106,8 +106,8 @@ export class VideoQualityLabel extends Component {
|
|||
};
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onDialogClose = this._onDialogClose.bind(this);
|
||||
this._onDialogToggle = this._onDialogToggle.bind(this);
|
||||
this._onHideQualityDialog = this._onHideQualityDialog.bind(this);
|
||||
this._onShowQualityDialog = this._onShowQualityDialog.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,20 +163,20 @@ export class VideoQualityLabel extends Component {
|
|||
return (
|
||||
<div
|
||||
className = { classNames }
|
||||
id = 'videoResolutionLabel'>
|
||||
<AKInlineDialog
|
||||
content = { <VideoQualityDialog /> }
|
||||
id = 'videoResolutionLabel'
|
||||
onMouseEnter = { this._onShowQualityDialog }
|
||||
onMouseLeave = { this._onHideQualityDialog }>
|
||||
<Popover
|
||||
content = { this._renderQualityDialog() }
|
||||
isOpen = { this.state.showVideoQualityDialog }
|
||||
onClose = { this._onDialogClose }
|
||||
position = { 'left top' }>
|
||||
<div
|
||||
className = 'video-quality-label-status'
|
||||
onClick = { this._onDialogToggle }>
|
||||
className = 'video-quality-label-status'>
|
||||
{ _audioOnly
|
||||
? <i className = 'icon-visibility-off' />
|
||||
: this._mapResolutionToTranslation(_resolution) }
|
||||
</div>
|
||||
</AKInlineDialog>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -211,26 +211,39 @@ export class VideoQualityLabel extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Toggles the display of the {@code VideoQualityDialog}.
|
||||
* Shows the {@code VideoQualityDialog}.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDialogToggle() {
|
||||
this.setState({
|
||||
showVideoQualityDialog: !this.state.showVideoQualityDialog
|
||||
});
|
||||
_onShowQualityDialog() {
|
||||
this.setState({ showVideoQualityDialog: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the attached inline dialog.
|
||||
* Hides the {@code VideoQualityDialog}.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDialogClose() {
|
||||
_onHideQualityDialog() {
|
||||
this.setState({ showVideoQualityDialog: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a React Element for choosing a maximum receive video quality.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderQualityDialog() {
|
||||
return (
|
||||
<div>
|
||||
<VideoQualityDialog />
|
||||
<div className = 'popover-mousemove-padding-right' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue