feat(tooltips): convert popup tooltips to InlineDialog
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
} from './actions.native';
|
||||
import { SET_DEFAULT_TOOLBOX_BUTTONS } from './actionTypes';
|
||||
import {
|
||||
getButton,
|
||||
getDefaultToolboxButtons,
|
||||
isButtonEnabled
|
||||
} from './functions';
|
||||
@@ -48,6 +49,23 @@ export function checkAutoEnableDesktopSharing(): Function {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to hide any popups displayed by the associated button.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button as specified in the
|
||||
* button configurations for the toolbar.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function clearButtonPopup(buttonName) {
|
||||
return (dispatch, getState) => {
|
||||
_clearPopupTimeout(buttonName, getState());
|
||||
|
||||
dispatch(setToolbarButton(buttonName, {
|
||||
popupDisplay: null
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Docks/undocks the Toolbox.
|
||||
*
|
||||
@@ -195,6 +213,34 @@ export function hideToolbox(force: boolean = false): Function {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to show the popup associated with a button. Sets a
|
||||
* timeout to be fired which will dismiss the popup.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button as specified in the
|
||||
* button configurations for the toolbar.
|
||||
* @param {string} popupName - The id of the popup to show as specified in
|
||||
* the button configurations for the toolbar.
|
||||
* @param {number} timeout - The time in milliseconds to show the popup.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setButtonPopupTimeout(buttonName, popupName, timeout) {
|
||||
return (dispatch, getState) => {
|
||||
_clearPopupTimeout(buttonName, getState());
|
||||
|
||||
const newTimeoutId = setTimeout(() => {
|
||||
dispatch(clearButtonPopup(buttonName));
|
||||
}, timeout);
|
||||
|
||||
dispatch(setToolbarButton(buttonName, {
|
||||
popupDisplay: {
|
||||
popupID: popupName,
|
||||
timeoutID: newTimeoutId
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default toolbar buttons of the Toolbox.
|
||||
*
|
||||
@@ -387,3 +433,20 @@ export function toggleSideToolbarContainer(containerId: string): Function {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the timeout set for hiding a button popup.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button as specified in the
|
||||
* button configurations for the toolbar.
|
||||
* @param {Object} state - The redux state in which the button is expected to
|
||||
* be defined.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _clearPopupTimeout(buttonName, state) {
|
||||
const { popupDisplay } = getButton(buttonName, state);
|
||||
const { timeoutID } = popupDisplay || {};
|
||||
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import AKInlineDialog from '@atlaskit/inline-dialog';
|
||||
import { Tooltip } from '@atlaskit/tooltip';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
@@ -11,6 +12,18 @@ import StatelessToolbarButton from './StatelessToolbarButton';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Mapping of tooltip positions to equivalent {@code AKInlineDialog} positions.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const TOOLTIP_TO_POPUP_POSITION = {
|
||||
bottom: 'bottom center',
|
||||
left: 'left middle',
|
||||
top: 'top center',
|
||||
right: 'right middle'
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a button in Toolbar on React.
|
||||
*
|
||||
@@ -127,26 +140,39 @@ class ToolbarButton extends Component {
|
||||
*/
|
||||
render(): ReactElement<*> {
|
||||
const { button, t, tooltipPosition } = this.props;
|
||||
const popups = button.popups || [];
|
||||
|
||||
const props = {
|
||||
...this.props,
|
||||
onClick: this._onClick,
|
||||
createRefToButton: this._createRefToButton
|
||||
};
|
||||
|
||||
return (
|
||||
const buttonComponent = ( // eslint-disable-line no-extra-parens
|
||||
<Tooltip
|
||||
description = { button.tooltipText || t(button.tooltipKey) }
|
||||
onMouseOut = { this._onMouseOut }
|
||||
onMouseOver = { this._onMouseOver }
|
||||
position = { tooltipPosition }
|
||||
visible = { this.state.showTooltip }>
|
||||
<StatelessToolbarButton { ...props }>
|
||||
{ this._renderPopups(popups) }
|
||||
</StatelessToolbarButton>
|
||||
<StatelessToolbarButton { ...props } />
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
const popupConfig = this._getPopupDisplayConfiguration();
|
||||
|
||||
if (popupConfig) {
|
||||
const { dataAttr, dataInterpolate, position } = popupConfig;
|
||||
|
||||
return (
|
||||
<AKInlineDialog
|
||||
content = { t(dataAttr, dataInterpolate) }
|
||||
isOpen = { Boolean(popupConfig) }
|
||||
position = { position }>
|
||||
{ buttonComponent }
|
||||
</AKInlineDialog>
|
||||
);
|
||||
}
|
||||
|
||||
return buttonComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,6 +199,32 @@ class ToolbarButton extends Component {
|
||||
this.button = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the props and state to find any popup that should be displayed
|
||||
* and returns an object describing how the popup should display.
|
||||
*
|
||||
* @private
|
||||
* @returns {Object|null}
|
||||
*/
|
||||
_getPopupDisplayConfiguration() {
|
||||
const { button, tooltipPosition } = this.props;
|
||||
const { popups, popupDisplay } = button;
|
||||
|
||||
if (!popups || !popupDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { popupID } = popupDisplay;
|
||||
const currentPopup = popups.find(popup => popup.id === popupID);
|
||||
|
||||
return Object.assign(
|
||||
{},
|
||||
currentPopup || {},
|
||||
{
|
||||
position: TOOLTIP_TO_POPUP_POSITION[tooltipPosition]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If toolbar button should contain children elements
|
||||
* renders them.
|
||||
@@ -188,34 +240,6 @@ class ToolbarButton extends Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders popup element for toolbar button.
|
||||
*
|
||||
* @param {Array} popups - Array of popup objects.
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
_renderPopups(popups: Array<*> = []): Array<*> {
|
||||
return popups.map(popup => {
|
||||
let gravity = 'n';
|
||||
|
||||
if (popup.dataAttrPosition) {
|
||||
gravity = popup.dataAttrPosition;
|
||||
}
|
||||
|
||||
const title = this.props.t(popup.dataAttr, popup.dataInterpolate);
|
||||
|
||||
return (
|
||||
<div
|
||||
className = { popup.className }
|
||||
data-popup = { gravity }
|
||||
id = { popup.id }
|
||||
key = { popup.id }
|
||||
title = { title } />
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides any displayed tooltip.
|
||||
*
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
|
||||
import {
|
||||
setDefaultToolboxButtons,
|
||||
setToolboxAlwaysVisible
|
||||
} from '../actions';
|
||||
import {
|
||||
abstractMapStateToProps,
|
||||
showCustomToolbarPopup
|
||||
abstractMapStateToProps
|
||||
} from '../functions';
|
||||
import Notice from './Notice';
|
||||
import PrimaryToolbar from './PrimaryToolbar';
|
||||
@@ -71,10 +68,6 @@ class Toolbox extends Component {
|
||||
componentDidMount(): void {
|
||||
this.props._setToolboxAlwaysVisible();
|
||||
|
||||
APP.UI.addListener(
|
||||
UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
|
||||
showCustomToolbarPopup);
|
||||
|
||||
// FIXME The redux action SET_DEFAULT_TOOLBOX_BUTTONS and related source
|
||||
// code such as the redux action creator setDefaultToolboxButtons and
|
||||
// _setDefaultToolboxButtons were introduced to solve the following bug
|
||||
@@ -89,17 +82,6 @@ class Toolbox extends Component {
|
||||
this.props._setDefaultToolboxButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters legacy UI listeners.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount(): void {
|
||||
APP.UI.removeListener(
|
||||
UIEvents.SHOW_CUSTOM_TOOLBAR_BUTTON_POPUP,
|
||||
showCustomToolbarPopup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
||||
@@ -51,7 +51,6 @@ const buttons: Object = {
|
||||
},
|
||||
popups: [
|
||||
{
|
||||
className: 'loginmenu',
|
||||
dataAttr: 'audioOnly.featureToggleDisabled',
|
||||
dataInterpolate: { feature: 'video mute' },
|
||||
id: 'unmuteWhileAudioOnly'
|
||||
@@ -143,7 +142,6 @@ const buttons: Object = {
|
||||
},
|
||||
popups: [
|
||||
{
|
||||
className: 'loginmenu',
|
||||
dataAttr: 'audioOnly.featureToggleDisabled',
|
||||
dataInterpolate: { feature: 'screen sharing' },
|
||||
id: 'screenshareWhileAudioOnly'
|
||||
@@ -313,17 +311,14 @@ const buttons: Object = {
|
||||
},
|
||||
popups: [
|
||||
{
|
||||
className: 'loginmenu',
|
||||
dataAttr: 'toolbar.micMutedPopup',
|
||||
id: 'micMutedPopup'
|
||||
},
|
||||
{
|
||||
className: 'loginmenu',
|
||||
dataAttr: 'toolbar.unableToUnmutePopup',
|
||||
id: 'unableToUnmutePopup'
|
||||
},
|
||||
{
|
||||
className: 'loginmenu',
|
||||
dataAttr: 'toolbar.talkWhileMutedPopup',
|
||||
id: 'talkWhileMutedPopup'
|
||||
}
|
||||
@@ -419,9 +414,7 @@ const buttons: Object = {
|
||||
},
|
||||
popups: [
|
||||
{
|
||||
className: 'loginmenu extendedToolbarPopup',
|
||||
dataAttr: 'toolbar.sharedVideoMutedPopup',
|
||||
dataAttrPosition: 'w',
|
||||
id: 'sharedVideoMutedPopup'
|
||||
}
|
||||
],
|
||||
|
||||
@@ -7,7 +7,7 @@ declare var $: Function;
|
||||
declare var AJS: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
export { abstractMapStateToProps } from './functions.native';
|
||||
export { abstractMapStateToProps, getButton } from './functions.native';
|
||||
|
||||
/**
|
||||
* Returns an object which contains the default buttons for the primary and
|
||||
|
||||
Reference in New Issue
Block a user