Fix tooltip bugs
This commit is contained in:
parent
6398a01852
commit
c6eafbb8d5
16 changed files with 339 additions and 235 deletions
|
@ -2223,30 +2223,6 @@ Signal Desktop makes use of the following open source projects.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
## react-tooltip-lite
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Benny Sidelinger
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
## react-virtualized
|
## react-virtualized
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
|
@ -126,7 +126,6 @@
|
||||||
"react-redux": "7.1.0",
|
"react-redux": "7.1.0",
|
||||||
"react-router-dom": "5.0.1",
|
"react-router-dom": "5.0.1",
|
||||||
"react-sortable-hoc": "1.9.1",
|
"react-sortable-hoc": "1.9.1",
|
||||||
"react-tooltip-lite": "1.12.0",
|
|
||||||
"react-virtualized": "9.21.0",
|
"react-virtualized": "9.21.0",
|
||||||
"read-last-lines": "1.3.0",
|
"read-last-lines": "1.3.0",
|
||||||
"redux": "4.0.1",
|
"redux": "4.0.1",
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
diff --git a/node_modules/react-tooltip-lite/dist/index.js b/node_modules/react-tooltip-lite/dist/index.js
|
|
||||||
index 32ce07d..6461913 100644
|
|
||||||
--- a/node_modules/react-tooltip-lite/dist/index.js
|
|
||||||
+++ b/node_modules/react-tooltip-lite/dist/index.js
|
|
||||||
@@ -80,7 +80,7 @@ function (_React$Component) {
|
|
||||||
|
|
||||||
_this.state = {
|
|
||||||
showTip: false,
|
|
||||||
- hasHover: false,
|
|
||||||
+ hasHover: 0,
|
|
||||||
ignoreShow: false,
|
|
||||||
hasBeenShown: false
|
|
||||||
};
|
|
||||||
@@ -232,7 +232,7 @@ function (_React$Component) {
|
|
||||||
var _this3 = this;
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
- hasHover: false
|
|
||||||
+ hasHover: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.state.showTip) {
|
|
||||||
@@ -250,7 +250,7 @@ function (_React$Component) {
|
|
||||||
value: function startHover() {
|
|
||||||
if (!this.state.ignoreShow) {
|
|
||||||
this.setState({
|
|
||||||
- hasHover: true
|
|
||||||
+ hasHover: (this.state.hasHover || 0) + 1,
|
|
||||||
});
|
|
||||||
clearTimeout(this.hoverTimeout);
|
|
||||||
this.hoverTimeout = setTimeout(this.checkHover, this.props.hoverDelay);
|
|
||||||
@@ -260,7 +260,7 @@ function (_React$Component) {
|
|
||||||
key: "endHover",
|
|
||||||
value: function endHover() {
|
|
||||||
this.setState({
|
|
||||||
- hasHover: false
|
|
||||||
+ hasHover: Math.max((this.state.hasHover || 0) - 1, 0),
|
|
||||||
});
|
|
||||||
clearTimeout(this.hoverTimeout);
|
|
||||||
this.hoverTimeout = setTimeout(this.checkHover, this.props.mouseOutDelay || this.props.hoverDelay);
|
|
||||||
@@ -268,7 +268,7 @@ function (_React$Component) {
|
|
||||||
}, {
|
|
||||||
key: "checkHover",
|
|
||||||
value: function checkHover() {
|
|
||||||
- this.state.hasHover ? this.showTip() : this.hideTip();
|
|
||||||
+ this.state.hasHover > 0 ? this.showTip() : this.hideTip();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
key: "render",
|
|
||||||
@@ -330,7 +330,9 @@ function (_React$Component) {
|
|
||||||
props[eventToggle] = this.toggleTip; // only use hover if they don't have a toggle event
|
|
||||||
} else if (useHover && !isControlledByProps) {
|
|
||||||
props.onMouseEnter = this.startHover;
|
|
||||||
- props.onMouseLeave = tipContentHover || mouseOutDelay ? this.endHover : this.hideTip;
|
|
||||||
+ props.onMouseLeave = this.endHover;
|
|
||||||
+ props.onFocus = this.startHover;
|
|
||||||
+ props.onBlur = this.endHover;
|
|
||||||
props.onTouchStart = this.targetTouchStart;
|
|
||||||
props.onTouchEnd = this.targetTouchEnd;
|
|
||||||
|
|
|
@ -2782,24 +2782,34 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-in-contacts-icon__tooltip {
|
span.module-in-contacts-icon__tooltip {
|
||||||
.react-tooltip-lite {
|
/* Written in this way to add more specificity and avoid !important */
|
||||||
|
.module-tooltip {
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
background-color: $ultramarine-ui-light;
|
background-color: $ultramarine-ui-light;
|
||||||
|
|
||||||
|
&[data-placement='top'] {
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
border-top-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-tooltip-lite-arrow {
|
&[data-placement='right'] {
|
||||||
border-color: $ultramarine-ui-light;
|
.module-tooltip-arrow::after {
|
||||||
|
border-right-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include dark-theme {
|
&[data-placement='bottom'] {
|
||||||
.react-tooltip-lite {
|
.module-tooltip-arrow::after {
|
||||||
color: $color-white;
|
border-bottom-color: $ultramarine-ui-light;
|
||||||
background-color: $ultramarine-ui-light;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-tooltip-lite-arrow {
|
&[data-placement='left'] {
|
||||||
border-color: $ultramarine-ui-light;
|
.module-tooltip-arrow::after {
|
||||||
|
border-left-color: $ultramarine-ui-light;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6522,8 +6532,8 @@ button.module-image__border-overlay:focus {
|
||||||
margin-top: 54px;
|
margin-top: 54px;
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
padding-bottom: 0;
|
|
||||||
width: 280px;
|
width: 280px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
&__overlay {
|
&__overlay {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -10183,10 +10193,13 @@ $contact-modal-padding: 18px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third-party module: react-tooltip-lite */
|
.module-tooltip {
|
||||||
|
|
||||||
.react-tooltip-lite {
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px 21px;
|
||||||
|
position: fixed;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
@include light-theme {
|
@include light-theme {
|
||||||
background-color: $color-gray-02;
|
background-color: $color-gray-02;
|
||||||
|
@ -10196,14 +10209,96 @@ $contact-modal-padding: 18px;
|
||||||
background-color: $color-gray-65;
|
background-color: $color-gray-65;
|
||||||
color: $color-gray-05;
|
color: $color-gray-05;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.react-tooltip-lite-arrow {
|
.module-tooltip-arrow {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
border: solid 6px transparent;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
margin-left: -6px;
|
||||||
|
margin-top: -6px;
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-placement='top'] {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.module-tooltip-arrow {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
bottom: -12px;
|
||||||
|
|
||||||
@include light-theme {
|
@include light-theme {
|
||||||
border-color: $color-gray-02;
|
border-top-color: $color-gray-02;
|
||||||
}
|
}
|
||||||
@include dark-theme {
|
@include dark-theme {
|
||||||
border-color: $color-gray-65;
|
border-top-color: $color-gray-65;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-placement='right'] {
|
||||||
|
margin-left: 12px;
|
||||||
|
|
||||||
|
.module-tooltip-arrow {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
left: -6px;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
border-right-color: $color-gray-02;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
border-right-color: $color-gray-65;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-placement='bottom'] {
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
.module-tooltip-arrow {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
top: -6px;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
border-bottom-color: $color-gray-02;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
border-bottom-color: $color-gray-65;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-placement='left'] {
|
||||||
|
margin-right: 12px;
|
||||||
|
|
||||||
|
.module-tooltip-arrow {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-tooltip-arrow::after {
|
||||||
|
right: -12px;
|
||||||
|
|
||||||
|
@include light-theme {
|
||||||
|
border-left-color: $color-gray-02;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
border-left-color: $color-gray-65;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,13 +253,11 @@ export const CallScreen: React.FC<PropsType> = ({
|
||||||
buttonType={videoButtonType}
|
buttonType={videoButtonType}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={toggleVideo}
|
onClick={toggleVideo}
|
||||||
tooltipDistance={24}
|
|
||||||
/>
|
/>
|
||||||
<CallingButton
|
<CallingButton
|
||||||
buttonType={audioButtonType}
|
buttonType={audioButtonType}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={toggleAudio}
|
onClick={toggleAudio}
|
||||||
tooltipDistance={24}
|
|
||||||
/>
|
/>
|
||||||
<CallingButton
|
<CallingButton
|
||||||
buttonType={CallingButtonType.HANG_UP}
|
buttonType={CallingButtonType.HANG_UP}
|
||||||
|
@ -267,7 +265,6 @@ export const CallScreen: React.FC<PropsType> = ({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
hangUp({ conversationId: conversation.id });
|
hangUp({ conversationId: conversation.id });
|
||||||
}}
|
}}
|
||||||
tooltipDistance={24}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -3,15 +3,11 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { storiesOf } from '@storybook/react';
|
import { storiesOf } from '@storybook/react';
|
||||||
import { number, select } from '@storybook/addon-knobs';
|
import { select } from '@storybook/addon-knobs';
|
||||||
import { action } from '@storybook/addon-actions';
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
import {
|
import { CallingButton, CallingButtonType, PropsType } from './CallingButton';
|
||||||
CallingButton,
|
import { TooltipPlacement } from './Tooltip';
|
||||||
CallingButtonType,
|
|
||||||
PropsType,
|
|
||||||
TooltipDirection,
|
|
||||||
} from './CallingButton';
|
|
||||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
import enMessages from '../../_locales/en/messages.json';
|
||||||
|
|
||||||
|
@ -27,12 +23,8 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
onClick: action('on-click'),
|
onClick: action('on-click'),
|
||||||
tooltipDirection: select(
|
tooltipDirection: select(
|
||||||
'tooltipDirection',
|
'tooltipDirection',
|
||||||
TooltipDirection,
|
TooltipPlacement,
|
||||||
overrideProps.tooltipDirection || TooltipDirection.DOWN
|
overrideProps.tooltipDirection || TooltipPlacement.Bottom
|
||||||
),
|
|
||||||
tooltipDistance: number(
|
|
||||||
'tooltipDistance',
|
|
||||||
overrideProps.tooltipDistance || 16
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,7 +79,7 @@ story.add('Video Disabled', () => {
|
||||||
|
|
||||||
story.add('Tooltip right', () => {
|
story.add('Tooltip right', () => {
|
||||||
const props = createProps({
|
const props = createProps({
|
||||||
tooltipDirection: TooltipDirection.RIGHT,
|
tooltipDirection: TooltipPlacement.Right,
|
||||||
});
|
});
|
||||||
return <CallingButton {...props} />;
|
return <CallingButton {...props} />;
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,16 +3,9 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Tooltip from 'react-tooltip-lite';
|
import { Tooltip, TooltipPlacement } from './Tooltip';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
export enum TooltipDirection {
|
|
||||||
UP = 'up',
|
|
||||||
RIGHT = 'right',
|
|
||||||
DOWN = 'down',
|
|
||||||
LEFT = 'left',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum CallingButtonType {
|
export enum CallingButtonType {
|
||||||
AUDIO_DISABLED = 'AUDIO_DISABLED',
|
AUDIO_DISABLED = 'AUDIO_DISABLED',
|
||||||
AUDIO_OFF = 'AUDIO_OFF',
|
AUDIO_OFF = 'AUDIO_OFF',
|
||||||
|
@ -27,16 +20,14 @@ export type PropsType = {
|
||||||
buttonType: CallingButtonType;
|
buttonType: CallingButtonType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
tooltipDirection?: TooltipDirection;
|
tooltipDirection?: TooltipPlacement;
|
||||||
tooltipDistance?: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CallingButton = ({
|
export const CallingButton = ({
|
||||||
buttonType,
|
buttonType,
|
||||||
i18n,
|
i18n,
|
||||||
onClick,
|
onClick,
|
||||||
tooltipDirection = TooltipDirection.DOWN,
|
tooltipDirection,
|
||||||
tooltipDistance = 16,
|
|
||||||
}: PropsType): JSX.Element => {
|
}: PropsType): JSX.Element => {
|
||||||
let classNameSuffix = '';
|
let classNameSuffix = '';
|
||||||
let tooltipContent = '';
|
let tooltipContent = '';
|
||||||
|
@ -69,21 +60,15 @@ export const CallingButton = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Tooltip content={tooltipContent} direction={tooltipDirection}>
|
||||||
<button
|
<button
|
||||||
aria-label={tooltipContent}
|
aria-label={tooltipContent}
|
||||||
type="button"
|
type="button"
|
||||||
className={className}
|
className={className}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
arrowSize={6}
|
|
||||||
content={tooltipContent}
|
|
||||||
direction={tooltipDirection}
|
|
||||||
distance={tooltipDistance}
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
</Tooltip>
|
|
||||||
</button>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Tooltip from 'react-tooltip-lite';
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
import { Tooltip } from './Tooltip';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
canPip?: boolean;
|
canPip?: boolean;
|
||||||
|
@ -34,52 +34,39 @@ export const CallingHeader = ({
|
||||||
{isGroupCall ? (
|
{isGroupCall ? (
|
||||||
<div className="module-calling-tools__button">
|
<div className="module-calling-tools__button">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
arrowSize={6}
|
|
||||||
content={i18n('calling__participants', [
|
content={i18n('calling__participants', [
|
||||||
String(remoteParticipants),
|
String(remoteParticipants),
|
||||||
])}
|
])}
|
||||||
direction="down"
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
aria-label={i18n('calling__participants', [
|
aria-label={i18n('calling__participants', [
|
||||||
String(remoteParticipants),
|
String(remoteParticipants),
|
||||||
])}
|
])}
|
||||||
className="module-calling-button__participants"
|
className="module-calling-button__participants"
|
||||||
onClick={toggleParticipants}
|
onClick={toggleParticipants}
|
||||||
|
type="button"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="module-calling-tools__button">
|
<div className="module-calling-tools__button">
|
||||||
<Tooltip
|
<Tooltip content={i18n('callingDeviceSelection__settings')}>
|
||||||
arrowSize={6}
|
|
||||||
content={i18n('callingDeviceSelection__settings')}
|
|
||||||
direction="down"
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
aria-label={i18n('callingDeviceSelection__settings')}
|
aria-label={i18n('callingDeviceSelection__settings')}
|
||||||
className="module-calling-button__settings"
|
className="module-calling-button__settings"
|
||||||
onClick={toggleSettings}
|
onClick={toggleSettings}
|
||||||
|
type="button"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
{canPip && (
|
{canPip && (
|
||||||
<div className="module-calling-tools__button">
|
<div className="module-calling-tools__button">
|
||||||
<Tooltip
|
<Tooltip content={i18n('calling__pip--on')}>
|
||||||
arrowSize={6}
|
|
||||||
content={i18n('calling__pip--on')}
|
|
||||||
direction="down"
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
aria-label={i18n('calling__pip--on')}
|
aria-label={i18n('calling__pip--on')}
|
||||||
className="module-calling-button__pip"
|
className="module-calling-button__pip"
|
||||||
onClick={togglePip}
|
onClick={togglePip}
|
||||||
|
type="button"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,11 +7,8 @@ import {
|
||||||
SetLocalPreviewType,
|
SetLocalPreviewType,
|
||||||
SetLocalVideoType,
|
SetLocalVideoType,
|
||||||
} from '../state/ducks/calling';
|
} from '../state/ducks/calling';
|
||||||
import {
|
import { CallingButton, CallingButtonType } from './CallingButton';
|
||||||
CallingButton,
|
import { TooltipPlacement } from './Tooltip';
|
||||||
CallingButtonType,
|
|
||||||
TooltipDirection,
|
|
||||||
} from './CallingButton';
|
|
||||||
import { CallBackgroundBlur } from './CallBackgroundBlur';
|
import { CallBackgroundBlur } from './CallBackgroundBlur';
|
||||||
import { CallingHeader } from './CallingHeader';
|
import { CallingHeader } from './CallingHeader';
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
|
@ -145,15 +142,13 @@ export const CallingLobby = ({
|
||||||
buttonType={videoButtonType}
|
buttonType={videoButtonType}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={toggleVideo}
|
onClick={toggleVideo}
|
||||||
tooltipDirection={TooltipDirection.UP}
|
tooltipDirection={TooltipPlacement.Top}
|
||||||
tooltipDistance={24}
|
|
||||||
/>
|
/>
|
||||||
<CallingButton
|
<CallingButton
|
||||||
buttonType={audioButtonType}
|
buttonType={audioButtonType}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
onClick={toggleAudio}
|
onClick={toggleAudio}
|
||||||
tooltipDirection={TooltipDirection.UP}
|
tooltipDirection={TooltipPlacement.Top}
|
||||||
tooltipDistance={24}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Tooltip from 'react-tooltip-lite';
|
import { Tooltip } from './Tooltip';
|
||||||
import { CallingPipRemoteVideo } from './CallingPipRemoteVideo';
|
import { CallingPipRemoteVideo } from './CallingPipRemoteVideo';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { ConversationType } from '../state/ducks/conversations';
|
import { ConversationType } from '../state/ducks/conversations';
|
||||||
|
@ -182,27 +182,23 @@ export const CallingPip = ({
|
||||||
) : null}
|
) : null}
|
||||||
<div className="module-calling-pip__actions">
|
<div className="module-calling-pip__actions">
|
||||||
<button
|
<button
|
||||||
type="button"
|
|
||||||
aria-label={i18n('calling__hangup')}
|
aria-label={i18n('calling__hangup')}
|
||||||
className="module-calling-pip__button--hangup"
|
className="module-calling-pip__button--hangup"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
hangUp({ conversationId: conversation.id });
|
hangUp({ conversationId: conversation.id });
|
||||||
}}
|
}}
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
type="button"
|
||||||
|
/>
|
||||||
|
<Tooltip content={i18n('calling__pip--off')}>
|
||||||
|
<button
|
||||||
aria-label={i18n('calling__pip--off')}
|
aria-label={i18n('calling__pip--off')}
|
||||||
className="module-calling-pip__button--pip"
|
className="module-calling-pip__button--pip"
|
||||||
onClick={togglePip}
|
onClick={togglePip}
|
||||||
>
|
type="button"
|
||||||
<Tooltip
|
|
||||||
arrowSize={6}
|
|
||||||
content={i18n('calling__pip--off')}
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
</Tooltip>
|
|
||||||
</button>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Tooltip from 'react-tooltip-lite';
|
|
||||||
|
|
||||||
|
import { Tooltip } from './Tooltip';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
|
@ -15,15 +15,8 @@ export const InContactsIcon = (props: PropsType): JSX.Element => {
|
||||||
|
|
||||||
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
|
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<span className="module-in-contacts-icon__tooltip">
|
||||||
tagName="span"
|
<Tooltip content={i18n('contactInAddressBook')}>
|
||||||
direction="bottom"
|
|
||||||
className="module-in-contacts-icon__tooltip"
|
|
||||||
arrowSize={8}
|
|
||||||
content={i18n('contactInAddressBook')}
|
|
||||||
distance={13}
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
|
||||||
<span
|
<span
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="img"
|
role="img"
|
||||||
|
@ -31,6 +24,7 @@ export const InContactsIcon = (props: PropsType): JSX.Element => {
|
||||||
className="module-in-contacts-icon__icon"
|
className="module-in-contacts-icon__icon"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
/* eslint-enable jsx-a11y/no-noninteractive-tabindex */
|
/* eslint-enable jsx-a11y/no-noninteractive-tabindex */
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Tooltip from 'react-tooltip-lite';
|
|
||||||
import { Avatar } from './Avatar';
|
import { Avatar } from './Avatar';
|
||||||
|
import { Tooltip } from './Tooltip';
|
||||||
import { ContactName } from './conversation/ContactName';
|
import { ContactName } from './conversation/ContactName';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { ColorType } from '../types/Colors';
|
import { ColorType } from '../types/Colors';
|
||||||
|
@ -41,22 +41,16 @@ const CallButton = ({
|
||||||
tooltipContent,
|
tooltipContent,
|
||||||
}: CallButtonProps): JSX.Element => {
|
}: CallButtonProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
|
<Tooltip content={tooltipContent}>
|
||||||
<button
|
<button
|
||||||
className={`module-incoming-call__button module-incoming-call__button--${classSuffix}`}
|
className={`module-incoming-call__button module-incoming-call__button--${classSuffix}`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
arrowSize={6}
|
|
||||||
content={tooltipContent}
|
|
||||||
direction="bottom"
|
|
||||||
distance={16}
|
|
||||||
hoverDelay={0}
|
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
</Tooltip>
|
|
||||||
</button>
|
</button>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
80
ts/components/Tooltip.stories.tsx
Normal file
80
ts/components/Tooltip.stories.tsx
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2020 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
import { select } from '@storybook/addon-knobs';
|
||||||
|
|
||||||
|
import { Tooltip, TooltipPlacement, PropsType } from './Tooltip';
|
||||||
|
|
||||||
|
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
|
content: overrideProps.content || 'Hello World',
|
||||||
|
direction: select('direction', TooltipPlacement, overrideProps.direction),
|
||||||
|
sticky: overrideProps.sticky,
|
||||||
|
});
|
||||||
|
|
||||||
|
const story = storiesOf('Components/Tooltip', module);
|
||||||
|
|
||||||
|
const Trigger = (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
marginTop: 200,
|
||||||
|
marginBottom: 200,
|
||||||
|
marginLeft: 200,
|
||||||
|
marginRight: 200,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Trigger
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
story.add('Top', () => (
|
||||||
|
<Tooltip
|
||||||
|
{...createProps({
|
||||||
|
direction: TooltipPlacement.Top,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Trigger}
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
story.add('Right', () => (
|
||||||
|
<Tooltip
|
||||||
|
{...createProps({
|
||||||
|
direction: TooltipPlacement.Right,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Trigger}
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
story.add('Bottom', () => (
|
||||||
|
<Tooltip
|
||||||
|
{...createProps({
|
||||||
|
direction: TooltipPlacement.Bottom,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Trigger}
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
story.add('Left', () => (
|
||||||
|
<Tooltip
|
||||||
|
{...createProps({
|
||||||
|
direction: TooltipPlacement.Left,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Trigger}
|
||||||
|
</Tooltip>
|
||||||
|
));
|
||||||
|
|
||||||
|
story.add('Sticky', () => (
|
||||||
|
<Tooltip
|
||||||
|
{...createProps({
|
||||||
|
sticky: true,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{Trigger}
|
||||||
|
</Tooltip>
|
||||||
|
));
|
81
ts/components/Tooltip.tsx
Normal file
81
ts/components/Tooltip.tsx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2020 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Manager, Reference, Popper } from 'react-popper';
|
||||||
|
|
||||||
|
export enum TooltipPlacement {
|
||||||
|
Top = 'top',
|
||||||
|
Right = 'right',
|
||||||
|
Bottom = 'bottom',
|
||||||
|
Left = 'left',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PropsType = {
|
||||||
|
content: string | JSX.Element;
|
||||||
|
direction?: TooltipPlacement;
|
||||||
|
sticky?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Tooltip: React.FC<PropsType> = ({
|
||||||
|
children,
|
||||||
|
content,
|
||||||
|
direction,
|
||||||
|
sticky,
|
||||||
|
}) => {
|
||||||
|
const isSticky = Boolean(sticky);
|
||||||
|
const [showTooltip, setShowTooltip] = React.useState(isSticky);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Manager>
|
||||||
|
<Reference>
|
||||||
|
{({ ref }) => (
|
||||||
|
<span
|
||||||
|
onBlur={() => {
|
||||||
|
if (!isSticky) {
|
||||||
|
setShowTooltip(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onFocus={() => {
|
||||||
|
if (!isSticky) {
|
||||||
|
setShowTooltip(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
if (!isSticky) {
|
||||||
|
setShowTooltip(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
if (!isSticky) {
|
||||||
|
setShowTooltip(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Reference>
|
||||||
|
<Popper placement={direction}>
|
||||||
|
{({ arrowProps, placement, ref, style }) =>
|
||||||
|
showTooltip && (
|
||||||
|
<div
|
||||||
|
className="module-tooltip"
|
||||||
|
ref={ref}
|
||||||
|
style={style}
|
||||||
|
data-placement={placement}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
<div
|
||||||
|
className="module-tooltip-arrow"
|
||||||
|
ref={arrowProps.ref}
|
||||||
|
style={arrowProps.style}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Popper>
|
||||||
|
</Manager>
|
||||||
|
);
|
||||||
|
};
|
|
@ -14391,7 +14391,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/CallingLobby.js",
|
"path": "ts/components/CallingLobby.js",
|
||||||
"line": " const localVideoRef = react_1.default.useRef(null);",
|
"line": " const localVideoRef = react_1.default.useRef(null);",
|
||||||
"lineNumber": 14,
|
"lineNumber": 15,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-10-26T19:12:24.410Z",
|
"updated": "2020-10-26T19:12:24.410Z",
|
||||||
"reasonDetail": "Used to get the local video element for rendering."
|
"reasonDetail": "Used to get the local video element for rendering."
|
||||||
|
@ -14400,7 +14400,7 @@
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/CallingLobby.tsx",
|
"path": "ts/components/CallingLobby.tsx",
|
||||||
"line": " const localVideoRef = React.useRef(null);",
|
"line": " const localVideoRef = React.useRef(null);",
|
||||||
"lineNumber": 61,
|
"lineNumber": 58,
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2020-10-26T19:12:24.410Z",
|
"updated": "2020-10-26T19:12:24.410Z",
|
||||||
"reasonDetail": "Used to get the local video element for rendering."
|
"reasonDetail": "Used to get the local video element for rendering."
|
||||||
|
|
|
@ -13508,13 +13508,6 @@ react-textarea-autosize@^7.1.0:
|
||||||
"@babel/runtime" "^7.1.2"
|
"@babel/runtime" "^7.1.2"
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
|
|
||||||
react-tooltip-lite@1.12.0:
|
|
||||||
version "1.12.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-tooltip-lite/-/react-tooltip-lite-1.12.0.tgz#f6cd1323cdd9f5f80dd0e71a30ef59f401dee9ba"
|
|
||||||
integrity sha512-QjDnmDmjtLNKvLY6bzUOG8W6ZDBTiE4UXugGzClOQEGvMvbkJn2GvZvLwRaxsN/GCx7589RgbGaESMiJAm+zWg==
|
|
||||||
dependencies:
|
|
||||||
prop-types "^15.5.8"
|
|
||||||
|
|
||||||
react-transition-group@^2.2.1:
|
react-transition-group@^2.2.1:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||||
|
|
Loading…
Reference in a new issue