feat(overflow): Add responsive drawer at small screen width.
* Implement opening toolbar and participant overflows as drawers when below certain width. * Fix dial-in copy button displaying incorrectly.
This commit is contained in:
parent
5ef60c3a7d
commit
c752ea13f1
|
@ -48,3 +48,19 @@
|
|||
.toolbox-button-wth-dialog .eYJELv {
|
||||
max-height: initial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override @atlaskit/InlineDialog styling for the overflowmenu so it displays
|
||||
* a scrollable list of elements at small screen widths.
|
||||
*/
|
||||
.sc-eNQAEJ {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep overflow menu within screen vertical bounds and make it scrollable.
|
||||
*/
|
||||
.toolbox-button-wth-dialog .sc-ckVGcZ.fdAqDG > :first-child {
|
||||
max-height: calc(100vh - #{$newToolbarSizeWithPadding} - 16px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
.drawer-portal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: $drawerZ;
|
||||
}
|
||||
|
||||
.drawer-menu {
|
||||
padding: 12px 16px;
|
||||
max-height: 50vh;
|
||||
background: #242528;
|
||||
border-radius: 16px 16px 0 0;
|
||||
overflow-y: auto;
|
||||
|
||||
&.expanded {
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.drawer-toggle {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: $overflowMenuItemHoverBG;
|
||||
}
|
||||
|
||||
svg, path {
|
||||
fill: #b8c7e0;
|
||||
}
|
||||
}
|
||||
|
||||
.popupmenu {
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.popupmenu__item {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
&#{&} .overflow-menu {
|
||||
margin: auto;
|
||||
font-size: 1.2em;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
|
||||
.overflow-menu-item {
|
||||
box-sizing: border-box;
|
||||
height: 48px;
|
||||
padding: 12px 16px;
|
||||
|
||||
align-items: center;
|
||||
color: $overflowMenuItemColor;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $overflowMenuItemHoverBG;
|
||||
color: $overflowMenuItemHoverColor;
|
||||
}
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
}
|
||||
&.unclickable:hover {
|
||||
background: inherit;
|
||||
}
|
||||
&.disabled {
|
||||
cursor: initial;
|
||||
color: #3b475c;
|
||||
}
|
||||
}
|
||||
|
||||
.beta-tag {
|
||||
background: $overflowMenuItemColor;
|
||||
border-radius: 2px;
|
||||
color: $overflowMenuBG;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.overflow-menu-item-icon {
|
||||
margin-right: 10px;
|
||||
|
||||
i {
|
||||
display: inline;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 24px;
|
||||
max-height: 24px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #B8C7E0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-text {
|
||||
max-width: 150px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,6 +121,7 @@ $poweredByZ: 100;
|
|||
$ringingZ: 300;
|
||||
$sideToolbarContainerZ: 300;
|
||||
$toolbarZ: 350;
|
||||
$drawerZ: 351;
|
||||
$tooltipsZ: 401;
|
||||
$dropdownMaskZ: 900;
|
||||
$dropdownZ: 901;
|
||||
|
|
|
@ -103,5 +103,6 @@ $flagsImagePath: "../images/";
|
|||
@import 'e2ee';
|
||||
@import 'responsive';
|
||||
@import 'connection-status';
|
||||
@import 'drawer';
|
||||
|
||||
/* Modules END */
|
||||
|
|
|
@ -50,6 +50,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.dial-in-number {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.dial-in-numbers-list {
|
||||
margin-top: 20px;
|
||||
font-size: 12px;
|
||||
|
|
|
@ -135,7 +135,6 @@
|
|||
.dial-in-copy {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 21px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
import InlineDialog from '@atlaskit/inline-dialog';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Drawer, DrawerPortal } from '../../../toolbox/components/web';
|
||||
|
||||
/**
|
||||
* A map of dialog positions, relative to trigger, to css classes used to
|
||||
* manipulate elements for handling mouse events.
|
||||
|
@ -66,6 +68,11 @@ type Props = {
|
|||
*/
|
||||
onPopoverOpen: Function,
|
||||
|
||||
/**
|
||||
* Whether to display the Popover as a drawer.
|
||||
*/
|
||||
overflowDrawer: boolean,
|
||||
|
||||
/**
|
||||
* From which side of the dialog trigger the dialog should display. The
|
||||
* value will be passed to {@code InlineDialog}.
|
||||
|
@ -101,6 +108,11 @@ class Popover extends Component<Props, State> {
|
|||
id: ''
|
||||
};
|
||||
|
||||
/**
|
||||
* Reference to the Popover that is meant to open as a drawer.
|
||||
*/
|
||||
_drawerContainerRef: Object;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code Popover} instance.
|
||||
*
|
||||
|
@ -117,6 +129,51 @@ class Popover extends Component<Props, State> {
|
|||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onHideDialog = this._onHideDialog.bind(this);
|
||||
this._onShowDialog = this._onShowDialog.bind(this);
|
||||
this._drawerContainerRef = React.createRef();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up an event listener to open a drawer when clicking, rather than entering the
|
||||
* overflow area.
|
||||
*
|
||||
* TODO: This should be done by setting an {@code onClick} handler on the div, but for some
|
||||
* reason that doesn't seem to work whatsoever.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
if (this._drawerContainerRef && this._drawerContainerRef.current) {
|
||||
this._drawerContainerRef.current.addEventListener('click', this._onShowDialog);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listener set up in the {@code componentDidMount} method.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
if (this._drawerContainerRef && this._drawerContainerRef.current) {
|
||||
this._drawerContainerRef.current.removeEventListener('click', this._onShowDialog);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React Component's componentDidUpdate.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.overflowDrawer !== this.props.overflowDrawer) {
|
||||
// Make sure the listeners are set up when resizing the screen past the drawer threshold.
|
||||
if (this.props.overflowDrawer) {
|
||||
this.componentDidMount();
|
||||
} else {
|
||||
this.componentWillUnmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,17 +183,37 @@ class Popover extends Component<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { children, className, content, id, overflowDrawer, position } = this.props;
|
||||
|
||||
if (overflowDrawer) {
|
||||
return (
|
||||
<div
|
||||
className = { className }
|
||||
id = { id }
|
||||
ref = { this._drawerContainerRef }>
|
||||
{ children }
|
||||
<DrawerPortal>
|
||||
<Drawer
|
||||
isOpen = { this.state.showDialog }
|
||||
onClose = { this._onHideDialog }>
|
||||
{ content }
|
||||
</Drawer>
|
||||
</DrawerPortal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className = { this.props.className }
|
||||
id = { this.props.id }
|
||||
className = { className }
|
||||
id = { id }
|
||||
onMouseEnter = { this._onShowDialog }
|
||||
onMouseLeave = { this._onHideDialog }>
|
||||
<InlineDialog
|
||||
content = { this._renderContent() }
|
||||
isOpen = { this.state.showDialog }
|
||||
position = { this.props.position }>
|
||||
{ this.props.children }
|
||||
position = { position }>
|
||||
{ children }
|
||||
</InlineDialog>
|
||||
</div>
|
||||
);
|
||||
|
@ -160,10 +237,12 @@ class Popover extends Component<Props, State> {
|
|||
* Displays the {@code InlineDialog} and calls any registered onPopoverOpen
|
||||
* callbacks.
|
||||
*
|
||||
* @param {MouseEvent} event - The mouse event to intercept.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onShowDialog() {
|
||||
_onShowDialog(event) {
|
||||
event.stopPropagation();
|
||||
if (!this.props.disablePopover) {
|
||||
this.setState({ showDialog: true });
|
||||
|
||||
|
|
|
@ -9,3 +9,8 @@ export const FILMSTRIP_SIZE = 90;
|
|||
* The aspect ratio of a tile in tile view.
|
||||
*/
|
||||
export const TILE_ASPECT_RATIO = 16 / 9;
|
||||
|
||||
/**
|
||||
* Width below which the overflow menu(s) will be displayed as drawer(s).
|
||||
*/
|
||||
export const DISPLAY_DRAWER_THRESHOLD = 512;
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
import Filmstrip from '../../../modules/UI/videolayout/Filmstrip';
|
||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||
import { StateListenerRegistry, equals } from '../base/redux';
|
||||
import { setOverflowDrawer } from '../toolbox/actions.web';
|
||||
import { getCurrentLayout, getTileViewGridDimensions, shouldDisplayTileView, LAYOUTS } from '../video-layout';
|
||||
|
||||
import { setHorizontalViewDimensions, setTileViewDimensions } from './actions.web';
|
||||
import { DISPLAY_DRAWER_THRESHOLD } from './constants';
|
||||
|
||||
/**
|
||||
* Listens for changes in the number of participants to calculate the dimensions of the tile view grid and the tiles.
|
||||
|
@ -123,3 +125,12 @@ StateListenerRegistry.register(
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Listens for changes in the client width to determine whether the overflow menu(s) should be displayed as drawers.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/base/responsive-ui'].clientWidth < DISPLAY_DRAWER_THRESHOLD,
|
||||
/* listener */ (widthBelowThreshold, store) => {
|
||||
store.dispatch(setOverflowDrawer(widthBelowThreshold));
|
||||
});
|
||||
|
|
|
@ -79,25 +79,27 @@ class DialInNumber extends Component<Props> {
|
|||
|
||||
return (
|
||||
<div className = 'dial-in-number'>
|
||||
<span className = 'phone-number'>
|
||||
<span className = 'info-label'>
|
||||
{ t('info.dialInNumber') }
|
||||
<div>
|
||||
<span className = 'phone-number'>
|
||||
<span className = 'info-label'>
|
||||
{ t('info.dialInNumber') }
|
||||
</span>
|
||||
<span className = 'spacer'> </span>
|
||||
<span className = 'info-value'>
|
||||
{ phoneNumber }
|
||||
</span>
|
||||
</span>
|
||||
<span className = 'spacer'> </span>
|
||||
<span className = 'info-value'>
|
||||
{ phoneNumber }
|
||||
<span className = 'conference-id'>
|
||||
<span className = 'info-label'>
|
||||
{ t('info.dialInConferenceID') }
|
||||
</span>
|
||||
<span className = 'spacer'> </span>
|
||||
<span className = 'info-value'>
|
||||
{ `${_formatConferenceIDPin(conferenceID)}#` }
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span className = 'spacer'> </span>
|
||||
<span className = 'conference-id'>
|
||||
<span className = 'info-label'>
|
||||
{ t('info.dialInConferenceID') }
|
||||
</span>
|
||||
<span className = 'spacer'> </span>
|
||||
<span className = 'info-value'>
|
||||
{ `${_formatConferenceIDPin(conferenceID)}#` }
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<a
|
||||
className = 'dial-in-copy'
|
||||
onClick = { this._onCopyText }>
|
||||
|
|
|
@ -60,6 +60,11 @@ type Props = {
|
|||
*/
|
||||
_menuPosition: string,
|
||||
|
||||
/**
|
||||
* Whether to display the Popover as a drawer.
|
||||
*/
|
||||
_overflowDrawer: boolean,
|
||||
|
||||
/**
|
||||
* The current state of the participant's remote control session.
|
||||
*/
|
||||
|
@ -122,6 +127,7 @@ class RemoteVideoMenuTriggerButton extends Component<Props> {
|
|||
return (
|
||||
<Popover
|
||||
content = { content }
|
||||
overflowDrawer = { this.props._overflowDrawer }
|
||||
position = { this.props._menuPosition }>
|
||||
<span
|
||||
className = 'popover-trigger remote-video-menu-trigger'>
|
||||
|
@ -237,14 +243,7 @@ class RemoteVideoMenuTriggerButton extends Component<Props> {
|
|||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The own props of the component.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _isAudioMuted: boolean,
|
||||
* _isModerator: boolean,
|
||||
* _disableKick: boolean,
|
||||
* _disableRemoteMute: boolean,
|
||||
* _menuPosition: string,
|
||||
* _remoteControlState: number
|
||||
* }}
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
const { participantID } = ownProps;
|
||||
|
@ -259,6 +258,7 @@ function _mapStateToProps(state, ownProps) {
|
|||
const { active, controller } = state['features/remote-control'];
|
||||
const { requestedParticipant, controlled } = controller;
|
||||
const activeParticipant = requestedParticipant || controlled;
|
||||
const { overflowDrawer } = state['features/toolbox'];
|
||||
|
||||
if (_supportsRemoteControl
|
||||
&& ((!active && !_isRemoteControlSessionActive) || activeParticipant === participantID)) {
|
||||
|
@ -291,7 +291,8 @@ function _mapStateToProps(state, ownProps) {
|
|||
_disableKick: Boolean(disableKick),
|
||||
_disableRemoteMute: Boolean(disableRemoteMute),
|
||||
_remoteControlState,
|
||||
_menuPosition
|
||||
_menuPosition,
|
||||
_overflowDrawer: overflowDrawer
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,11 @@ export const FULL_SCREEN_CHANGED = 'FULL_SCREEN_CHANGED';
|
|||
*/
|
||||
export const SET_FULL_SCREEN = 'SET_FULL_SCREEN';
|
||||
|
||||
/**
|
||||
* The type of the redux action that toggles whether the overflow menu(s) should be shown as drawers.
|
||||
*/
|
||||
export const SET_OVERFLOW_DRAWER = 'SET_OVERFLOW_DRAWER';
|
||||
|
||||
/**
|
||||
* The type of the (redux) action which shows/hides the OverflowMenu.
|
||||
*
|
||||
|
|
|
@ -4,7 +4,8 @@ import type { Dispatch } from 'redux';
|
|||
|
||||
import {
|
||||
FULL_SCREEN_CHANGED,
|
||||
SET_FULL_SCREEN
|
||||
SET_FULL_SCREEN,
|
||||
SET_OVERFLOW_DRAWER
|
||||
} from './actionTypes';
|
||||
import {
|
||||
clearToolboxTimeout,
|
||||
|
@ -143,3 +144,19 @@ export function showToolbox(timeout: number = 0): Object {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals a request to display overflow as drawer.
|
||||
*
|
||||
* @param {boolean} displayAsDrawer - True to display overflow as drawer, false to preserve original behaviour.
|
||||
* @returns {{
|
||||
* type: SET_OVERFLOW_DRAWER,
|
||||
* displayAsDrawer: boolean
|
||||
* }}
|
||||
*/
|
||||
export function setOverflowDrawer(displayAsDrawer: boolean) {
|
||||
return {
|
||||
type: SET_OVERFLOW_DRAWER,
|
||||
displayAsDrawer
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// @flow
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { Icon, IconArrowUp, IconArrowDown } from '../../../base/icons';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Whether the drawer should have a button that expands its size or not.
|
||||
*/
|
||||
canExpand: ?boolean,
|
||||
|
||||
/**
|
||||
* The component(s) to be displayed within the drawer menu.
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
Whether the drawer should be shown or not.
|
||||
*/
|
||||
isOpen: boolean,
|
||||
|
||||
/**
|
||||
Function that hides the drawer.
|
||||
*/
|
||||
onClose: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that displays the mobile friendly drawer on web.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function Drawer({
|
||||
canExpand,
|
||||
children,
|
||||
isOpen,
|
||||
onClose }: Props) {
|
||||
const [ expanded, setExpanded ] = useState(false);
|
||||
const drawerRef: Object = useRef(null);
|
||||
|
||||
/**
|
||||
* Closes the drawer when clicking outside of it.
|
||||
*
|
||||
* @param {Event} event - Mouse down event object.
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleOutsideClick(event: MouseEvent) {
|
||||
if (drawerRef.current && !drawerRef.current.contains(event.target)) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('mousedown', handleOutsideClick);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousedown', handleOutsideClick);
|
||||
};
|
||||
}, [ drawerRef ]);
|
||||
|
||||
/**
|
||||
* Toggles the menu state between expanded/collapsed.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function toggleExpanded() {
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
|
||||
return (
|
||||
isOpen ? (
|
||||
<div
|
||||
className = { `drawer-menu${expanded ? ' expanded' : ''}` }
|
||||
ref = { drawerRef }>
|
||||
{canExpand && (
|
||||
<div
|
||||
className = 'drawer-toggle'
|
||||
onClick = { toggleExpanded }>
|
||||
<Icon src = { expanded ? IconArrowDown : IconArrowUp } />
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
) : null
|
||||
);
|
||||
}
|
||||
|
||||
export default Drawer;
|
|
@ -0,0 +1,47 @@
|
|||
// @flow
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The component(s) to be displayed within the drawer portal.
|
||||
*/
|
||||
children: React$Node
|
||||
};
|
||||
|
||||
/**
|
||||
* Component meant to render a drawer at the bottom of the screen,
|
||||
* by creating a portal containing the component's children.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function DrawerPortal({ children }: Props) {
|
||||
const [ portalTarget ] = useState(() => {
|
||||
const portalDiv = document.createElement('div');
|
||||
|
||||
portalDiv.className = 'drawer-portal';
|
||||
|
||||
return portalDiv;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (document.body) {
|
||||
document.body.appendChild(portalTarget);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (document.body) {
|
||||
document.body.removeChild(portalTarget);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
children,
|
||||
portalTarget
|
||||
);
|
||||
}
|
||||
|
||||
export default DrawerPortal;
|
|
@ -6,7 +6,10 @@ import React, { Component } from 'react';
|
|||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { IconMenuThumb } from '../../../base/icons';
|
||||
import { connect } from '../../../base/redux';
|
||||
|
||||
import Drawer from './Drawer';
|
||||
import DrawerPortal from './DrawerPortal';
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
|
||||
/**
|
||||
|
@ -29,6 +32,11 @@ type Props = {
|
|||
*/
|
||||
onVisibilityChange: Function,
|
||||
|
||||
/**
|
||||
* Whether to display the OverflowMenu as a drawer.
|
||||
*/
|
||||
overflowDrawer: boolean,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
|
@ -63,27 +71,58 @@ class OverflowMenuButton extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { children, isOpen, t } = this.props;
|
||||
const { children, isOpen, overflowDrawer } = this.props;
|
||||
|
||||
return (
|
||||
<div className = 'toolbox-button-wth-dialog'>
|
||||
<InlineDialog
|
||||
content = { children }
|
||||
isOpen = { isOpen }
|
||||
onClose = { this._onCloseDialog }
|
||||
position = { 'top right' }>
|
||||
<ToolbarButton
|
||||
accessibilityLabel =
|
||||
{ t('toolbar.accessibilityLabel.moreActions') }
|
||||
icon = { IconMenuThumb }
|
||||
onClick = { this._onToggleDialogVisibility }
|
||||
toggled = { isOpen }
|
||||
tooltip = { t('toolbar.moreActions') } />
|
||||
</InlineDialog>
|
||||
{
|
||||
overflowDrawer ? (
|
||||
<>
|
||||
{this._renderToolbarButton()}
|
||||
<DrawerPortal>
|
||||
<Drawer
|
||||
canExpand = { true }
|
||||
isOpen = { isOpen }
|
||||
onClose = { this._onCloseDialog }>
|
||||
{children}
|
||||
</Drawer>
|
||||
</DrawerPortal>
|
||||
</>
|
||||
) : (
|
||||
<InlineDialog
|
||||
content = { children }
|
||||
isOpen = { isOpen }
|
||||
onClose = { this._onCloseDialog }
|
||||
position = { 'top right' }>
|
||||
{this._renderToolbarButton()}
|
||||
</InlineDialog>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
_renderToolbarButton: () => React$Node;
|
||||
|
||||
/**
|
||||
* Renders the actual toolbar overflow menu button.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderToolbarButton() {
|
||||
const { isOpen, t } = this.props;
|
||||
|
||||
return (
|
||||
<ToolbarButton
|
||||
accessibilityLabel =
|
||||
{ t('toolbar.accessibilityLabel.moreActions') }
|
||||
icon = { IconMenuThumb }
|
||||
onClick = { this._onToggleDialogVisibility }
|
||||
toggled = { isOpen }
|
||||
tooltip = { t('toolbar.moreActions') } />
|
||||
);
|
||||
}
|
||||
|
||||
_onCloseDialog: () => void;
|
||||
|
||||
/**
|
||||
|
@ -113,4 +152,19 @@ class OverflowMenuButton extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default translate(OverflowMenuButton);
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated props for the
|
||||
* {@code OverflowMenuButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
const { overflowDrawer } = state['features/toolbox'];
|
||||
|
||||
return {
|
||||
overflowDrawer
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(mapStateToProps)(OverflowMenuButton));
|
||||
|
|
|
@ -2,3 +2,5 @@ export { default as AudioSettingsButton } from './AudioSettingsButton';
|
|||
export { default as VideoSettingsButton } from './VideoSettingsButton';
|
||||
export { default as ToolbarButton } from './ToolbarButton';
|
||||
export { default as Toolbox } from './Toolbox';
|
||||
export { default as Drawer } from './Drawer';
|
||||
export { default as DrawerPortal } from './DrawerPortal';
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ReducerRegistry, set } from '../base/redux';
|
|||
import {
|
||||
CLEAR_TOOLBOX_TIMEOUT,
|
||||
FULL_SCREEN_CHANGED,
|
||||
SET_OVERFLOW_DRAWER,
|
||||
SET_OVERFLOW_MENU_VISIBLE,
|
||||
SET_TOOLBAR_HOVERED,
|
||||
SET_TOOLBOX_ALWAYS_VISIBLE,
|
||||
|
@ -25,6 +26,7 @@ declare var interfaceConfig: Object;
|
|||
* alwaysVisible: boolean,
|
||||
* enabled: boolean,
|
||||
* hovered: boolean,
|
||||
* overflowDrawer: boolean,
|
||||
* overflowMenuVisible: boolean,
|
||||
* timeoutID: number,
|
||||
* timeoutMS: number,
|
||||
|
@ -79,6 +81,13 @@ function _getInitialState() {
|
|||
*/
|
||||
hovered: false,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the overflow menu(s) are to be displayed as drawers.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
overflowDrawer: false,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the OverflowMenu is visible.
|
||||
*
|
||||
|
@ -103,7 +112,7 @@ function _getInitialState() {
|
|||
timeoutMS,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the Toolbox is visible.
|
||||
* The indicator that determines whether the Toolbox is visible.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
@ -127,6 +136,12 @@ ReducerRegistry.register(
|
|||
fullScreen: action.fullScreen
|
||||
};
|
||||
|
||||
case SET_OVERFLOW_DRAWER:
|
||||
return {
|
||||
...state,
|
||||
overflowDrawer: action.displayAsDrawer
|
||||
};
|
||||
|
||||
case SET_OVERFLOW_MENU_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
|
|
Loading…
Reference in New Issue