mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 03:12:29 +00:00
feat(tooltip) Create and move to our component (#13061)
Create Tooltip component Fix Popover positioning calculations Add margins to popover Remove @atlaskit/tooltip Update all components to use the new Tooltip component Added tooltip actions and reducers for the following functionality: when a user hovers over an element is sees the tooltip for that element and then hovers another element that has a tooltip, instead of using the delay and animations we just unmount the current tooltip and mount the next one immediately
This commit is contained in:
@@ -1,49 +1,27 @@
|
||||
/**
|
||||
* Mousemove padding styles are used to add invisible elements to the popover
|
||||
* to allow mouse movement from the popover trigger to the popover itself
|
||||
* without triggering a mouseleave event.
|
||||
*/
|
||||
%vertical-popover-padding {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 20px;
|
||||
padding: 20px 0;
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
%horizontal-popover-padding {
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
padding: 0 35px;
|
||||
left: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-left {
|
||||
@extend %vertical-popover-padding;
|
||||
left: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-right {
|
||||
@extend %vertical-popover-padding;
|
||||
right: -35px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-bottom {
|
||||
@extend %horizontal-popover-padding;
|
||||
bottom: -40px;
|
||||
}
|
||||
|
||||
.popover-mousemove-padding-top {
|
||||
@extend %horizontal-popover-padding;
|
||||
top: -40px;
|
||||
}
|
||||
|
||||
.popover {
|
||||
margin: -16px -24px;
|
||||
z-index: $popoverZ;
|
||||
|
||||
.popover-content {
|
||||
margin: 16px 24px;
|
||||
position: relative;
|
||||
|
||||
&.top {
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
&.left {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
&.right {
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.excalidraw .popover {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
width: 280px;
|
||||
background: $menuBG;
|
||||
box-shadow: 0px 3px 16px rgba(0, 0, 0, 0.6), 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 3px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
|
||||
&.with-gif {
|
||||
@@ -104,10 +104,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.reactions-menu-container {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.reactions-animations-container {
|
||||
position: absolute;
|
||||
width: 20%;
|
||||
|
||||
@@ -34,20 +34,20 @@
|
||||
background: #F2F3F4;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
|
||||
|
||||
& > svg {
|
||||
& svg {
|
||||
fill: #040404;
|
||||
}
|
||||
|
||||
&.settings-button-small-icon--disabled {
|
||||
background: #36383C;
|
||||
|
||||
&> svg {
|
||||
& svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > svg {
|
||||
& svg {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
background-color: #36383c;
|
||||
cursor: default;
|
||||
|
||||
&> svg {
|
||||
& svg {
|
||||
fill: #929292;
|
||||
}
|
||||
}
|
||||
|
||||
56
package-lock.json
generated
56
package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"@atlaskit/inline-message": "11.0.8",
|
||||
"@atlaskit/multi-select": "15.0.5",
|
||||
"@atlaskit/theme": "11.0.2",
|
||||
"@atlaskit/tooltip": "17.1.2",
|
||||
"@emotion/react": "11.10.0",
|
||||
"@emotion/styled": "11.10.0",
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
@@ -599,18 +598,6 @@
|
||||
"styled-components": "^3.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/motion": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/motion/-/motion-0.4.8.tgz",
|
||||
"integrity": "sha512-+5hABjUNUgl66zNya+EmNXLrbJQ7EgXA+fNQih7qzu7MkIuzJjT5vEtpXrzckLKBu1v1HsbMQW90Wnd8MJugdw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/multi-select": {
|
||||
"version": "15.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/multi-select/-/multi-select-15.0.5.tgz",
|
||||
@@ -789,25 +776,6 @@
|
||||
"@babel/types": "^7.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/tooltip": {
|
||||
"version": "17.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-17.1.2.tgz",
|
||||
"integrity": "sha512-0N63l18ZuyL2pjNXwY3pwnNos3HjOsFhSmnj2TLASC+RLz/6/Nk1k9gXuydfMjU2ntsr7xrVY5U7ING0mxAzQQ==",
|
||||
"dependencies": {
|
||||
"@atlaskit/analytics-next": "^8.1.0",
|
||||
"@atlaskit/motion": "^0.4.0",
|
||||
"@atlaskit/popper": "^5.0.0",
|
||||
"@atlaskit/portal": "^4.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9",
|
||||
"bind-event-listener": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0",
|
||||
"react-dom": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
@@ -20705,15 +20673,6 @@
|
||||
"react-scrolllock": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"@atlaskit/motion": {
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/motion/-/motion-0.4.8.tgz",
|
||||
"integrity": "sha512-+5hABjUNUgl66zNya+EmNXLrbJQ7EgXA+fNQih7qzu7MkIuzJjT5vEtpXrzckLKBu1v1HsbMQW90Wnd8MJugdw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9"
|
||||
}
|
||||
},
|
||||
"@atlaskit/multi-select": {
|
||||
"version": "15.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/multi-select/-/multi-select-15.0.5.tgz",
|
||||
@@ -20857,21 +20816,6 @@
|
||||
"@babel/types": "^7.15.0"
|
||||
}
|
||||
},
|
||||
"@atlaskit/tooltip": {
|
||||
"version": "17.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-17.1.2.tgz",
|
||||
"integrity": "sha512-0N63l18ZuyL2pjNXwY3pwnNos3HjOsFhSmnj2TLASC+RLz/6/Nk1k9gXuydfMjU2ntsr7xrVY5U7ING0mxAzQQ==",
|
||||
"requires": {
|
||||
"@atlaskit/analytics-next": "^8.1.0",
|
||||
"@atlaskit/motion": "^0.4.0",
|
||||
"@atlaskit/popper": "^5.0.0",
|
||||
"@atlaskit/portal": "^4.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"@emotion/core": "^10.0.9",
|
||||
"bind-event-listener": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"@atlaskit/inline-message": "11.0.8",
|
||||
"@atlaskit/multi-select": "15.0.5",
|
||||
"@atlaskit/theme": "11.0.2",
|
||||
"@atlaskit/tooltip": "17.1.2",
|
||||
"@emotion/react": "11.10.0",
|
||||
"@emotion/styled": "11.10.0",
|
||||
"@giphy/js-fetch-api": "4.7.1",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @flow
|
||||
|
||||
import '../base/devices/reducer';
|
||||
import '../base/tooltip/reducer';
|
||||
import '../e2ee/reducer';
|
||||
import '../face-landmarks/reducer';
|
||||
import '../feedback/reducer';
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IResponsiveUIState } from '../base/responsive-ui/reducer';
|
||||
import { ISettingsState } from '../base/settings/reducer';
|
||||
import { ISoundsState } from '../base/sounds/reducer';
|
||||
import { ITestingState } from '../base/testing/reducer';
|
||||
import { ITooltipState } from '../base/tooltip/reducer';
|
||||
import { INoSrcDataState, ITracksState } from '../base/tracks/reducer';
|
||||
import { IUserInteractionState } from '../base/user-interaction/reducer';
|
||||
import { IBreakoutRoomsState } from '../breakout-rooms/reducer';
|
||||
@@ -111,6 +112,7 @@ export interface IReduxState {
|
||||
'features/base/responsive-ui': IResponsiveUIState;
|
||||
'features/base/settings': ISettingsState;
|
||||
'features/base/sounds': ISoundsState;
|
||||
'features/base/tooltip': ITooltipState;
|
||||
'features/base/tracks': ITracksState;
|
||||
'features/base/user-interaction': IUserInteractionState;
|
||||
'features/breakout-rooms': IBreakoutRoomsState;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { IReduxState } from '../../../app/types';
|
||||
import DialogPortal from '../../../toolbox/components/web/DialogPortal';
|
||||
import Drawer from '../../../toolbox/components/web/Drawer';
|
||||
import JitsiPortal from '../../../toolbox/components/web/JitsiPortal';
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
import { connect } from '../../redux/functions';
|
||||
import { getContextMenuStyle } from '../functions.web';
|
||||
|
||||
@@ -14,6 +13,11 @@ import { getContextMenuStyle } from '../functions.web';
|
||||
*/
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Whether the child element can be clicked on.
|
||||
*/
|
||||
allowClick?: boolean;
|
||||
|
||||
/**
|
||||
* A child React Element to use as the trigger for showing the dialog.
|
||||
*/
|
||||
@@ -245,7 +249,8 @@ class Popover extends Component<IProps, IState> {
|
||||
<DialogPortal
|
||||
getRef = { this._setContextMenuRef }
|
||||
setSize = { this._setContextMenuStyle }
|
||||
style = { this.state.contextMenuStyle }>
|
||||
style = { this.state.contextMenuStyle }
|
||||
targetSelector = '.popover-content'>
|
||||
<ReactFocusLock
|
||||
lockProps = {{
|
||||
role: 'dialog',
|
||||
@@ -345,9 +350,11 @@ class Popover extends Component<IProps, IState> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick(event: React.MouseEvent) {
|
||||
const { trigger, visible } = this.props;
|
||||
const { allowClick, trigger, visible } = this.props;
|
||||
|
||||
event.stopPropagation();
|
||||
if (!allowClick) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
if (trigger === 'click') {
|
||||
if (visible) {
|
||||
this._onHideDialog();
|
||||
@@ -417,20 +424,15 @@ class Popover extends Component<IProps, IState> {
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderContent() {
|
||||
const { content } = this.props;
|
||||
const { content, position } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'popover'
|
||||
onKeyDown = { this._onEscKey }>
|
||||
{ content }
|
||||
{!isMobileBrowser() && (
|
||||
<>
|
||||
<div className = 'popover-mousemove-padding-top' />
|
||||
<div className = 'popover-mousemove-padding-right' />
|
||||
<div className = 'popover-mousemove-padding-left' />
|
||||
<div className = 'popover-mousemove-padding-bottom' />
|
||||
</>)}
|
||||
<div className = { `popover-content ${position.split('-')[0]}` }>
|
||||
{ content }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,43 +1,40 @@
|
||||
const LEFT_RIGHT_OFFSET = 25;
|
||||
const TOP_BOTTOM_OFFSET = 20;
|
||||
|
||||
const getLeftAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
right: `${window.innerWidth - bounds.x + LEFT_RIGHT_OFFSET}px`
|
||||
right: `${window.innerWidth - bounds.x}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getRightAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
left: `${bounds.x + bounds.width + LEFT_RIGHT_OFFSET}px`
|
||||
left: `${bounds.x + bounds.width}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
bottom: `${window.innerHeight - bounds.y + TOP_BOTTOM_OFFSET}px`
|
||||
bottom: `${window.innerHeight - bounds.y}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getBottomAlignedStyle = (bounds: DOMRect) => {
|
||||
return {
|
||||
position: 'fixed',
|
||||
top: `${bounds.y + bounds.height + TOP_BOTTOM_OFFSET}px`
|
||||
top: `${bounds.y + bounds.height}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getLeftRightStartAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
top: `${Math.min(bounds.y + 15, window.innerHeight - size.height - 20)}px`
|
||||
top: `${Math.min(bounds.y, window.innerHeight - size.height - 20)}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getLeftRightMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
bottom: `${window.innerHeight - bounds.y - bounds.height - (size.height / 2)}px`
|
||||
bottom: `${window.innerHeight - bounds.y - (bounds.height / 2) - (size.height / 2)}px`
|
||||
};
|
||||
};
|
||||
|
||||
@@ -49,19 +46,19 @@ const getLeftRightEndAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
|
||||
const getTopBotStartAlign = (bounds: DOMRect) => {
|
||||
return {
|
||||
right: `${window.innerWidth - bounds.x + 10}px`
|
||||
right: `${window.innerWidth - bounds.x - 6}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopBotMidAlign = (bounds: DOMRect, size: DOMRectReadOnly) => {
|
||||
return {
|
||||
right: `${window.innerWidth - bounds.x - (size.width / 2)}px`
|
||||
right: `${window.innerWidth - bounds.x - (bounds.width / 2) - (size.width / 2)}px`
|
||||
};
|
||||
};
|
||||
|
||||
const getTopBotEndAlign = (bounds: DOMRect) => {
|
||||
return {
|
||||
left: `${bounds.x + bounds.width + 10}px`
|
||||
left: `${bounds.x + bounds.width - 6}px`
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { translate } from '../../../i18n/functions';
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import Tooltip from '../../../tooltip/components/Tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link BaseIndicator}.
|
||||
@@ -58,7 +56,7 @@ interface IProps extends WithTranslation {
|
||||
* From which side of the indicator the tooltip should appear from,
|
||||
* defaulting to "top".
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { Icon } from '../../icons';
|
||||
import { Tooltip } from '../../tooltip';
|
||||
import Tooltip from '../../tooltip/components/Tooltip';
|
||||
import ContextMenuItem from '../../ui/components/web/ContextMenuItem';
|
||||
|
||||
import AbstractToolboxItem from './AbstractToolboxItem';
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link OverflowMenuItem}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* A succinct description of what the item does. Used by accessibility tools
|
||||
* and torture tests.
|
||||
*/
|
||||
accessibilityLabel: string,
|
||||
|
||||
/**
|
||||
* Whether menu item is disabled or not.
|
||||
*/
|
||||
disabled: boolean,
|
||||
|
||||
/**
|
||||
* A React Element to display at the end of {@code OverflowMenuItem}.
|
||||
*/
|
||||
elementAfter?: React$Node,
|
||||
|
||||
/**
|
||||
* The icon class to use for displaying an icon before the link text.
|
||||
*/
|
||||
icon: Object,
|
||||
|
||||
/**
|
||||
* Id of the icon to be rendered.
|
||||
*/
|
||||
iconId?: string,
|
||||
|
||||
/**
|
||||
* The callback to invoke when {@code OverflowMenuItem} is clicked.
|
||||
*/
|
||||
onClick: Function,
|
||||
|
||||
/**
|
||||
* The text to display in the {@code OverflowMenuItem}.
|
||||
*/
|
||||
text: string,
|
||||
|
||||
/**
|
||||
* The text to display in the tooltip.
|
||||
*/
|
||||
tooltip?: string,
|
||||
|
||||
/**
|
||||
* From which direction the tooltip should appear, relative to the button.
|
||||
*/
|
||||
tooltipPosition: string
|
||||
};
|
||||
|
||||
/**
|
||||
* A React {@code Component} for displaying a link to interact with other
|
||||
* features of the application.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class OverflowMenuItem extends Component<Props> {
|
||||
/**
|
||||
* Default values for {@code OverflowMenuItem} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
tooltipPosition: 'left',
|
||||
disabled: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code OverflowMenuItem} instance.
|
||||
*
|
||||
* @param {*} props - The read-only properties with which the new instance
|
||||
* is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handler so it is only bound once for every instance.
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
}
|
||||
|
||||
_onKeyPress: (Object) => void;
|
||||
|
||||
/**
|
||||
* KeyPress handler for accessibility.
|
||||
*
|
||||
* @param {Object} e - The key event to handle.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(e) {
|
||||
if (!this.props.disabled && this.props.onClick && (e.key === ' ' || e.key === 'Enter')) {
|
||||
e.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { accessibilityLabel, disabled, elementAfter, icon, iconId, onClick } = this.props;
|
||||
|
||||
let className = 'overflow-menu-item';
|
||||
|
||||
className += this.props.disabled ? ' disabled' : '';
|
||||
|
||||
return (
|
||||
<li
|
||||
aria-disabled = { disabled }
|
||||
aria-label = { accessibilityLabel }
|
||||
className = { className }
|
||||
onClick = { disabled ? null : onClick }
|
||||
onKeyPress = { this._onKeyPress }
|
||||
role = 'button'
|
||||
tabIndex = { 0 }>
|
||||
<span className = 'overflow-menu-item-icon'>
|
||||
<Icon
|
||||
id = { iconId }
|
||||
src = { icon } />
|
||||
</span>
|
||||
{ this._renderText() }
|
||||
{
|
||||
elementAfter || null
|
||||
}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the text label to display in the {@code OverflowMenuItem}.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderText() {
|
||||
const textElement = (
|
||||
<span className = 'overflow-menu-item-text'>
|
||||
{ this.props.text }
|
||||
</span>
|
||||
);
|
||||
|
||||
if (this.props.tooltip) {
|
||||
return (
|
||||
<Tooltip
|
||||
content = { this.props.tooltip }
|
||||
position = { this.props.tooltipPosition }>
|
||||
{ textElement }
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return textElement;
|
||||
}
|
||||
}
|
||||
|
||||
export default OverflowMenuItem;
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
|
||||
import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import Tooltip from '../../../tooltip/components/Tooltip';
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -107,12 +107,13 @@ export default function ToolboxButtonWithIcon(props: Props) {
|
||||
} = props;
|
||||
|
||||
const iconProps = {};
|
||||
let className = '';
|
||||
|
||||
if (iconDisabled) {
|
||||
iconProps.className
|
||||
className
|
||||
= 'settings-button-small-icon settings-button-small-icon--disabled';
|
||||
} else {
|
||||
iconProps.className = 'settings-button-small-icon';
|
||||
className = 'settings-button-small-icon';
|
||||
iconProps.onClick = () => {
|
||||
if (typeof APP !== 'undefined' && notifyMode) {
|
||||
APP.API.notifyToolbarButtonClicked(
|
||||
@@ -141,6 +142,7 @@ export default function ToolboxButtonWithIcon(props: Props) {
|
||||
|
||||
<div>
|
||||
<Tooltip
|
||||
containerClassName = { className }
|
||||
content = { iconTooltip }
|
||||
position = 'top'>
|
||||
<Icon
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { Icon } from '../../../icons';
|
||||
import { Tooltip } from '../../../tooltip';
|
||||
import AbstractToolboxItem from '../AbstractToolboxItem';
|
||||
import type { Props } from '../AbstractToolboxItem';
|
||||
|
||||
/**
|
||||
* Web implementation of {@code AbstractToolboxItem}.
|
||||
*/
|
||||
export default class ToolboxItem extends AbstractToolboxItem<Props> {
|
||||
/**
|
||||
* Initializes a new {@code ToolboxItem} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
}
|
||||
|
||||
_onKeyPress: (Object) => void;
|
||||
|
||||
/**
|
||||
* Handles 'Enter' and Space key on the button to trigger onClick for accessibility.
|
||||
*
|
||||
* @param {Object} event - The key event.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(event) {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles rendering of the actual item. If the label is being shown, which
|
||||
* is controlled with the `showLabel` prop, the item is rendered for its
|
||||
* display in an overflow menu, otherwise it will only have an icon, which
|
||||
* can be displayed on any toolbar.
|
||||
*
|
||||
* @protected
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderItem() {
|
||||
const {
|
||||
disabled,
|
||||
elementAfter,
|
||||
onClick,
|
||||
showLabel,
|
||||
tooltipPosition,
|
||||
toggled
|
||||
} = this.props;
|
||||
const className = showLabel ? 'overflow-menu-item' : 'toolbox-button';
|
||||
const props = {
|
||||
'aria-pressed': toggled,
|
||||
'aria-disabled': disabled,
|
||||
'aria-label': this.accessibilityLabel,
|
||||
className: className + (disabled ? ' disabled' : ''),
|
||||
onClick: disabled ? undefined : onClick,
|
||||
onKeyPress: this._onKeyPress,
|
||||
tabIndex: 0,
|
||||
role: 'button'
|
||||
};
|
||||
|
||||
const elementType = showLabel ? 'li' : 'div';
|
||||
const useTooltip = this.tooltip && this.tooltip.length > 0;
|
||||
let children = (
|
||||
<Fragment>
|
||||
{ this._renderIcon() }
|
||||
{ showLabel && <span>
|
||||
{ this.label }
|
||||
</span> }
|
||||
{ elementAfter }
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
if (useTooltip) {
|
||||
children = (
|
||||
<Tooltip
|
||||
content = { this.tooltip }
|
||||
position = { tooltipPosition }>
|
||||
{ children }
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return React.createElement(elementType, props, children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to render the item's icon.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderIcon() {
|
||||
const { customClass, disabled, icon, showLabel, toggled } = this.props;
|
||||
const iconComponent = <Icon src = { icon } />;
|
||||
const elementType = showLabel ? 'span' : 'div';
|
||||
const className = `${showLabel ? 'overflow-menu-item-icon' : 'toolbox-icon'} ${
|
||||
toggled ? 'toggled' : ''} ${disabled ? 'disabled' : ''} ${customClass ?? ''}`;
|
||||
|
||||
return React.createElement(elementType, { className }, iconComponent);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// @flow
|
||||
|
||||
export { default as OverflowMenuItem } from './OverflowMenuItem';
|
||||
export { default as ToolboxButtonWithIcon } from './ToolboxButtonWithIcon';
|
||||
|
||||
19
react/features/base/tooltip/actionTypes.tsx
Normal file
19
react/features/base/tooltip/actionTypes.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* The type of the action which signals a tooltip is being displayed.
|
||||
*
|
||||
* {
|
||||
* type: SHOW_TOOLTIP,
|
||||
* content: string
|
||||
* }.
|
||||
*/
|
||||
export const SHOW_TOOLTIP = 'SHOW_TOOLTIP';
|
||||
|
||||
/**
|
||||
* The type of the action which signals a tooltip should be hidden.
|
||||
*
|
||||
* {
|
||||
* type: SHOW_TOOLTIP,
|
||||
* content: string
|
||||
* }.
|
||||
*/
|
||||
export const HIDE_TOOLTIP = 'HIDE_TOOLTIP';
|
||||
29
react/features/base/tooltip/actions.tsx
Normal file
29
react/features/base/tooltip/actions.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { HIDE_TOOLTIP, SHOW_TOOLTIP } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Set tooltip state to visible.
|
||||
*
|
||||
* @param {string} content - The content of the tooltip.
|
||||
* Used as unique identifier for tooltip.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function showTooltip(content: string) {
|
||||
return {
|
||||
type: SHOW_TOOLTIP,
|
||||
content
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tooltip state to hidden.
|
||||
*
|
||||
* @param {string} content - The content of the tooltip.
|
||||
* Used as unique identifier for tooltip.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function hideTooltip(content: string) {
|
||||
return {
|
||||
type: HIDE_TOOLTIP,
|
||||
content
|
||||
};
|
||||
}
|
||||
150
react/features/base/tooltip/components/Tooltip.tsx
Normal file
150
react/features/base/tooltip/components/Tooltip.tsx
Normal file
@@ -0,0 +1,150 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { keyframes } from 'tss-react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
import Popover from '../../popover/components/Popover.web';
|
||||
import { withPixelLineHeight } from '../../styles/functions.web';
|
||||
import { hideTooltip, showTooltip } from '../actions';
|
||||
|
||||
const TOOLTIP_DELAY = 300;
|
||||
const ANIMATION_DURATION = 0.2;
|
||||
|
||||
interface IProps {
|
||||
children: ReactElement;
|
||||
containerClassName?: string;
|
||||
content: string;
|
||||
position?: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
backgroundColor: theme.palette.uiBackground,
|
||||
borderRadius: '3px',
|
||||
padding: theme.spacing(2),
|
||||
...withPixelLineHeight(theme.typography.labelRegular),
|
||||
color: theme.palette.text01,
|
||||
position: 'relative',
|
||||
|
||||
'&.mounting-animation': {
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
`} ${ANIMATION_DURATION}s forwards ease-in`
|
||||
},
|
||||
|
||||
'&.unmounting': {
|
||||
animation: `${keyframes`
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
`} ${ANIMATION_DURATION}s forwards ease-out`
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const Tooltip = ({ containerClassName, content, children, position = 'top' }: IProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
const [ isUnmounting, setIsUnmounting ] = useState(false);
|
||||
const { classes, cx } = useStyles();
|
||||
const timeoutID = useRef({
|
||||
open: 0,
|
||||
close: 0
|
||||
});
|
||||
const {
|
||||
content: storeContent,
|
||||
previousContent,
|
||||
visible: isVisible
|
||||
} = useSelector((state: IReduxState) => state['features/base/tooltip']);
|
||||
|
||||
if (isMobileBrowser()) {
|
||||
return children;
|
||||
}
|
||||
|
||||
const contentComponent = (
|
||||
<div
|
||||
className = { cx(classes.container, previousContent === '' && 'mounting-animation',
|
||||
isUnmounting && 'unmounting') }>
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
|
||||
const openPopover = () => {
|
||||
setVisible(true);
|
||||
dispatch(showTooltip(content));
|
||||
};
|
||||
|
||||
const closePopover = () => {
|
||||
setVisible(false);
|
||||
dispatch(hideTooltip(content));
|
||||
setIsUnmounting(false);
|
||||
};
|
||||
|
||||
const onPopoverOpen = useCallback(() => {
|
||||
clearTimeout(timeoutID.current.close);
|
||||
timeoutID.current.close = 0;
|
||||
if (!visible) {
|
||||
if (isVisible) {
|
||||
openPopover();
|
||||
} else {
|
||||
timeoutID.current.open = window.setTimeout(() => {
|
||||
openPopover();
|
||||
}, TOOLTIP_DELAY);
|
||||
}
|
||||
}
|
||||
}, [ visible, isVisible ]);
|
||||
|
||||
const onPopoverClose = useCallback(() => {
|
||||
clearTimeout(timeoutID.current.open);
|
||||
if (visible) {
|
||||
timeoutID.current.close = window.setTimeout(() => {
|
||||
setIsUnmounting(true);
|
||||
}, TOOLTIP_DELAY);
|
||||
}
|
||||
}, [ visible ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isUnmounting) {
|
||||
setTimeout(() => {
|
||||
if (timeoutID.current.close !== 0) {
|
||||
closePopover();
|
||||
}
|
||||
}, (ANIMATION_DURATION * 1000) + 10);
|
||||
}
|
||||
}, [ isUnmounting ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (storeContent !== content) {
|
||||
closePopover();
|
||||
clearTimeout(timeoutID.current.close);
|
||||
timeoutID.current.close = 0;
|
||||
}
|
||||
}, [ storeContent ]);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
allowClick = { true }
|
||||
className = { containerClassName }
|
||||
content = { contentComponent }
|
||||
onPopoverClose = { onPopoverClose }
|
||||
onPopoverOpen = { onPopoverOpen }
|
||||
position = { position }
|
||||
visible = { visible }>
|
||||
{children}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tooltip;
|
||||
@@ -1,50 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import Tooltip from '@atlaskit/tooltip';
|
||||
import React from 'react';
|
||||
|
||||
import { isMobileBrowser } from '../../environment/utils';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Children of the component.
|
||||
*/
|
||||
children: React$Node,
|
||||
|
||||
/**
|
||||
* The text to be displayed in the tooltip.
|
||||
*/
|
||||
content?: string | null,
|
||||
|
||||
/**
|
||||
* The position of the tooltip relative to the element it contains.
|
||||
*/
|
||||
position?: string
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper of AtlasKit Tooltip that doesn't render the actual tooltip in mobile browsers.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function TooltipWrapper({
|
||||
children,
|
||||
content,
|
||||
position
|
||||
}: Props) {
|
||||
if (isMobileBrowser()) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content = { content }
|
||||
position = { position }>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export default TooltipWrapper;
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export { default as Tooltip } from './TooltipWrapper';
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export * from './components';
|
||||
50
react/features/base/tooltip/reducer.ts
Normal file
50
react/features/base/tooltip/reducer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import ReducerRegistry from '../redux/ReducerRegistry';
|
||||
|
||||
import { HIDE_TOOLTIP, SHOW_TOOLTIP } from './actionTypes';
|
||||
|
||||
export interface ITooltipState {
|
||||
content: string;
|
||||
previousContent: string;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
content: '',
|
||||
previousContent: '',
|
||||
visible: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces redux actions which mark the tooltip as displayed or hidden.
|
||||
*
|
||||
* @param {IDialogState} state - The current redux state.
|
||||
* @param {Action} action - The redux action to reduce.
|
||||
* @param {string} action.type - The type of the redux action to reduce..
|
||||
* @returns {State} The next redux state that is the result of reducing the
|
||||
* specified action.
|
||||
*/
|
||||
ReducerRegistry.register<ITooltipState>('features/base/tooltip', (state = DEFAULT_STATE, action): ITooltipState => {
|
||||
switch (action.type) {
|
||||
case SHOW_TOOLTIP:
|
||||
return {
|
||||
content: action.content,
|
||||
previousContent: state.content,
|
||||
visible: true
|
||||
};
|
||||
case HIDE_TOOLTIP: {
|
||||
// The tooltip can be marked as hidden only if the hide action
|
||||
// is dispatched by the tooltip that is displayed.
|
||||
if (action.content === state.content) {
|
||||
return {
|
||||
content: '',
|
||||
previousContent: '',
|
||||
visible: false
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconPlus } from '../../base/icons';
|
||||
import { connect } from '../../base/redux';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import { updateCalendarEvent } from '../actions';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Icon, IconPlus } from '../../base/icons';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link JoinButton}.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Tooltip from '@atlaskit/tooltip';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -6,6 +5,7 @@ import { translate } from '../../../base/i18n/functions';
|
||||
import { IconExclamationTriangle } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
import { COLORS } from '../../../base/label/constants';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,9 +6,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconRaiseHand } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { open as openParticipantsPane } from '../../../participants-pane/actions.web';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -5,9 +5,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { getConferenceName } from '../../../base/conference/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
@@ -44,13 +42,13 @@ const SubjectText = () => {
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
<Tooltip
|
||||
content = { subject }
|
||||
position = 'bottom'>
|
||||
<Tooltip
|
||||
content = { subject }
|
||||
position = 'bottom'>
|
||||
<div className = { classes.container }>
|
||||
<div className = { clsx('subject-text--content', classes.content) }>{subject}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconArrowDown } from '../../../base/icons/svg/index';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { setTopPanelVisible } from '../../../filmstrip/actions.web';
|
||||
|
||||
const ToggleTopPanelLabel = () => {
|
||||
|
||||
@@ -230,12 +230,9 @@ const styles = (theme: Theme) => {
|
||||
},
|
||||
contextMenu: {
|
||||
position: 'relative' as const,
|
||||
marginTop: 0,
|
||||
margin: 0,
|
||||
right: 'auto',
|
||||
padding: `${theme.spacing(2)} ${theme.spacing(1)}`,
|
||||
marginLeft: theme.spacing(1),
|
||||
marginRight: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1)
|
||||
padding: `${theme.spacing(2)} ${theme.spacing(1)}`
|
||||
},
|
||||
download: {},
|
||||
mobile: {
|
||||
|
||||
@@ -10,9 +10,7 @@ import {
|
||||
} from '../../../base/participants/functions';
|
||||
import { updateSettings } from '../../../base/settings/actions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { getIndicatorsTooltipPosition } from '../../../filmstrip/functions.web';
|
||||
import { appendSuffix } from '../../functions';
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { translate } from '../../base/i18n/functions';
|
||||
import { IconE2EE } from '../../base/icons/svg';
|
||||
import Label from '../../base/label/components/web/Label';
|
||||
import { COLORS } from '../../base/label/constants';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
import { IProps, _mapStateToProps } from './AbstractE2EELabel';
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ interface IProps {
|
||||
/**
|
||||
* From which side of the indicator the tooltip should appear from.
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(() => {
|
||||
|
||||
@@ -27,7 +27,7 @@ interface IProps {
|
||||
/**
|
||||
* From which side of the indicator the tooltip should appear from.
|
||||
*/
|
||||
tooltipPosition: string;
|
||||
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -30,8 +30,7 @@ import {
|
||||
} from '../../../base/participants/functions';
|
||||
import { IParticipant } from '../../../base/participants/types';
|
||||
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { trackStreamingStatusChanged } from '../../../base/tracks/actions';
|
||||
import {
|
||||
getLocalAudioTrack,
|
||||
|
||||
@@ -222,7 +222,9 @@ export const STATS_POPOVER_POSITION = {
|
||||
/**
|
||||
* The tooltip position for the indicators on the thumbnail.
|
||||
*/
|
||||
export const INDICATORS_TOOLTIP_POSITION = {
|
||||
export const INDICATORS_TOOLTIP_POSITION: {
|
||||
[x: string]: 'right' | 'left' | 'top';
|
||||
} = {
|
||||
[THUMBNAIL_TYPE.TILE]: 'right',
|
||||
[THUMBNAIL_TYPE.VERTICAL]: 'left',
|
||||
[THUMBNAIL_TYPE.HORIZONTAL]: 'top'
|
||||
|
||||
@@ -11,9 +11,7 @@ import {
|
||||
IconOffice365,
|
||||
IconYahoo
|
||||
} from '../../../../base/icons/svg';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../../base/tooltip';
|
||||
import Tooltip from '../../../../base/tooltip/components/Tooltip';
|
||||
import { copyText } from '../../../../base/util/copyText.web';
|
||||
|
||||
interface IProps {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractToolbarButton from '../../../toolbox/components/AbstractToolbarButton';
|
||||
import type { Props as AbstractToolbarButtonProps } from '../../../toolbox/components/AbstractToolbarButton';
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@ import { IconHighlight } from '../../../../base/icons/svg';
|
||||
import { MEET_FEATURES } from '../../../../base/jwt/constants';
|
||||
import Label from '../../../../base/label/components/web/Label';
|
||||
import { connect } from '../../../../base/redux/functions';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../../base/tooltip';
|
||||
import Tooltip from '../../../../base/tooltip/components/Tooltip';
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
|
||||
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
|
||||
import AbstractHighlightButton, {
|
||||
|
||||
@@ -7,9 +7,7 @@ import { IconRecord, IconSites } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import AbstractRecordingLabel, {
|
||||
_mapStateToProps
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ import {
|
||||
IconEmotionsSad,
|
||||
IconEmotionsSurprised
|
||||
} from '../../../base/icons/svg';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import Dialog from '../../../base/ui/components/web/Dialog';
|
||||
import { escapeRegexp } from '../../../base/util/helpers';
|
||||
import { initSearch, resetSearchCriteria, toggleFaceExpressions } from '../../actions.any';
|
||||
|
||||
@@ -31,6 +31,12 @@ type Props = {
|
||||
* Custom style to apply to the container div.
|
||||
*/
|
||||
style?: any;
|
||||
|
||||
/**
|
||||
* The selector for the element we consider the content container.
|
||||
* This is used to determine the correct size of the portal content.
|
||||
*/
|
||||
targetSelector?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,7 +45,7 @@ type Props = {
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function DialogPortal({ children, className, style, getRef, setSize }: Props) {
|
||||
function DialogPortal({ children, className, style, getRef, setSize, targetSelector }: Props) {
|
||||
const clientWidth = useSelector((state: IReduxState) => state['features/base/responsive-ui'].clientWidth);
|
||||
const [ portalTarget ] = useState(() => {
|
||||
const portalDiv = document.createElement('div');
|
||||
@@ -87,13 +93,15 @@ function DialogPortal({ children, className, style, getRef, setSize }: Props) {
|
||||
}
|
||||
});
|
||||
|
||||
const target = targetSelector ? portalTarget.querySelector(targetSelector) : portalTarget;
|
||||
|
||||
if (document.body) {
|
||||
document.body.appendChild(portalTarget);
|
||||
observer.observe(portalTarget);
|
||||
observer.observe(target ?? portalTarget);
|
||||
}
|
||||
|
||||
return () => {
|
||||
observer.unobserve(portalTarget);
|
||||
observer.unobserve(target ?? portalTarget);
|
||||
if (document.body) {
|
||||
document.body.removeChild(portalTarget);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Label from '../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
|
||||
import { Props, _mapStateToProps } from './AbstractTranscribingLabel';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IconPerformance } from '../../base/icons';
|
||||
import { Label } from '../../base/label';
|
||||
import { COLORS } from '../../base/label/constants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import { shouldDisplayTileView } from '../../video-layout';
|
||||
|
||||
import AbstractVideoQualityLabel, {
|
||||
|
||||
@@ -14,8 +14,7 @@ import { translate } from '../../base/i18n/functions';
|
||||
import Icon from '../../base/icons/components/Icon';
|
||||
import { IconCloseLarge } from '../../base/icons/svg';
|
||||
import { withPixelLineHeight } from '../../base/styles/functions.web';
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../base/tooltip';
|
||||
import Tooltip from '../../base/tooltip/components/Tooltip';
|
||||
import Spinner from '../../base/ui/components/web/Spinner';
|
||||
import { BACKGROUNDS_LIMIT, IMAGES, type Image, VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
||||
import { toDataURL } from '../functions';
|
||||
@@ -430,7 +429,7 @@ function VirtualBackgrounds({
|
||||
</Tooltip>
|
||||
{_images.map(image => (
|
||||
<Tooltip
|
||||
content = { image.tooltip && t(`virtualBackground.${image.tooltip}`) }
|
||||
content = { (image.tooltip && t(`virtualBackground.${image.tooltip}`)) ?? '' }
|
||||
key = { image.id }
|
||||
position = { 'top' }>
|
||||
<img
|
||||
|
||||
@@ -6,9 +6,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconUsers } from '../../../base/icons/svg';
|
||||
import Label from '../../../base/label/components/web/Label';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import Tooltip from '../../../base/tooltip/components/Tooltip';
|
||||
import { getVisitorsShortText, iAmVisitor } from '../../functions';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"node_modules",
|
||||
"react/features/analytics/handlers/GoogleAnalyticsHandler.ts",
|
||||
"react/features/base/components/participants-pane-list",
|
||||
"react/features/base/tooltip",
|
||||
"react/features/connection-stats",
|
||||
"react/features/desktop-picker",
|
||||
"react/features/e2ee",
|
||||
|
||||
Reference in New Issue
Block a user