Fix tooltip bugs

This commit is contained in:
Josh Perez 2020-11-19 13:11:35 -05:00 committed by Josh Perez
parent 6398a01852
commit c6eafbb8d5
16 changed files with 339 additions and 235 deletions

View file

@ -253,13 +253,11 @@ export const CallScreen: React.FC<PropsType> = ({
buttonType={videoButtonType}
i18n={i18n}
onClick={toggleVideo}
tooltipDistance={24}
/>
<CallingButton
buttonType={audioButtonType}
i18n={i18n}
onClick={toggleAudio}
tooltipDistance={24}
/>
<CallingButton
buttonType={CallingButtonType.HANG_UP}
@ -267,7 +265,6 @@ export const CallScreen: React.FC<PropsType> = ({
onClick={() => {
hangUp({ conversationId: conversation.id });
}}
tooltipDistance={24}
/>
</div>
<div

View file

@ -3,15 +3,11 @@
import * as React from '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 {
CallingButton,
CallingButtonType,
PropsType,
TooltipDirection,
} from './CallingButton';
import { CallingButton, CallingButtonType, PropsType } from './CallingButton';
import { TooltipPlacement } from './Tooltip';
import { setup as setupI18n } from '../../js/modules/i18n';
import enMessages from '../../_locales/en/messages.json';
@ -27,12 +23,8 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
onClick: action('on-click'),
tooltipDirection: select(
'tooltipDirection',
TooltipDirection,
overrideProps.tooltipDirection || TooltipDirection.DOWN
),
tooltipDistance: number(
'tooltipDistance',
overrideProps.tooltipDistance || 16
TooltipPlacement,
overrideProps.tooltipDirection || TooltipPlacement.Bottom
),
});
@ -87,7 +79,7 @@ story.add('Video Disabled', () => {
story.add('Tooltip right', () => {
const props = createProps({
tooltipDirection: TooltipDirection.RIGHT,
tooltipDirection: TooltipPlacement.Right,
});
return <CallingButton {...props} />;
});

View file

@ -3,16 +3,9 @@
import React from 'react';
import classNames from 'classnames';
import Tooltip from 'react-tooltip-lite';
import { Tooltip, TooltipPlacement } from './Tooltip';
import { LocalizerType } from '../types/Util';
export enum TooltipDirection {
UP = 'up',
RIGHT = 'right',
DOWN = 'down',
LEFT = 'left',
}
export enum CallingButtonType {
AUDIO_DISABLED = 'AUDIO_DISABLED',
AUDIO_OFF = 'AUDIO_OFF',
@ -27,16 +20,14 @@ export type PropsType = {
buttonType: CallingButtonType;
i18n: LocalizerType;
onClick: () => void;
tooltipDirection?: TooltipDirection;
tooltipDistance?: number;
tooltipDirection?: TooltipPlacement;
};
export const CallingButton = ({
buttonType,
i18n,
onClick,
tooltipDirection = TooltipDirection.DOWN,
tooltipDistance = 16,
tooltipDirection,
}: PropsType): JSX.Element => {
let classNameSuffix = '';
let tooltipContent = '';
@ -69,21 +60,15 @@ export const CallingButton = ({
);
return (
<button
aria-label={tooltipContent}
type="button"
className={className}
onClick={onClick}
>
<Tooltip
arrowSize={6}
content={tooltipContent}
direction={tooltipDirection}
distance={tooltipDistance}
hoverDelay={0}
<Tooltip content={tooltipContent} direction={tooltipDirection}>
<button
aria-label={tooltipContent}
type="button"
className={className}
onClick={onClick}
>
<div />
</Tooltip>
</button>
</button>
</Tooltip>
);
};

View file

@ -2,8 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import Tooltip from 'react-tooltip-lite';
import { LocalizerType } from '../types/Util';
import { Tooltip } from './Tooltip';
export type PropsType = {
canPip?: boolean;
@ -34,52 +34,39 @@ export const CallingHeader = ({
{isGroupCall ? (
<div className="module-calling-tools__button">
<Tooltip
arrowSize={6}
content={i18n('calling__participants', [
String(remoteParticipants),
])}
direction="down"
hoverDelay={0}
>
<button
type="button"
aria-label={i18n('calling__participants', [
String(remoteParticipants),
])}
className="module-calling-button__participants"
onClick={toggleParticipants}
type="button"
/>
</Tooltip>
</div>
) : null}
<div className="module-calling-tools__button">
<Tooltip
arrowSize={6}
content={i18n('callingDeviceSelection__settings')}
direction="down"
hoverDelay={0}
>
<Tooltip content={i18n('callingDeviceSelection__settings')}>
<button
type="button"
aria-label={i18n('callingDeviceSelection__settings')}
className="module-calling-button__settings"
onClick={toggleSettings}
type="button"
/>
</Tooltip>
</div>
{canPip && (
<div className="module-calling-tools__button">
<Tooltip
arrowSize={6}
content={i18n('calling__pip--on')}
direction="down"
hoverDelay={0}
>
<Tooltip content={i18n('calling__pip--on')}>
<button
type="button"
aria-label={i18n('calling__pip--on')}
className="module-calling-button__pip"
onClick={togglePip}
type="button"
/>
</Tooltip>
</div>

View file

@ -7,11 +7,8 @@ import {
SetLocalPreviewType,
SetLocalVideoType,
} from '../state/ducks/calling';
import {
CallingButton,
CallingButtonType,
TooltipDirection,
} from './CallingButton';
import { CallingButton, CallingButtonType } from './CallingButton';
import { TooltipPlacement } from './Tooltip';
import { CallBackgroundBlur } from './CallBackgroundBlur';
import { CallingHeader } from './CallingHeader';
import { Spinner } from './Spinner';
@ -145,15 +142,13 @@ export const CallingLobby = ({
buttonType={videoButtonType}
i18n={i18n}
onClick={toggleVideo}
tooltipDirection={TooltipDirection.UP}
tooltipDistance={24}
tooltipDirection={TooltipPlacement.Top}
/>
<CallingButton
buttonType={audioButtonType}
i18n={i18n}
onClick={toggleAudio}
tooltipDirection={TooltipDirection.UP}
tooltipDistance={24}
tooltipDirection={TooltipPlacement.Top}
/>
</div>
</div>

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import Tooltip from 'react-tooltip-lite';
import { Tooltip } from './Tooltip';
import { CallingPipRemoteVideo } from './CallingPipRemoteVideo';
import { LocalizerType } from '../types/Util';
import { ConversationType } from '../state/ducks/conversations';
@ -182,27 +182,23 @@ export const CallingPip = ({
) : null}
<div className="module-calling-pip__actions">
<button
type="button"
aria-label={i18n('calling__hangup')}
className="module-calling-pip__button--hangup"
onClick={() => {
hangUp({ conversationId: conversation.id });
}}
/>
<button
type="button"
aria-label={i18n('calling__pip--off')}
className="module-calling-pip__button--pip"
onClick={togglePip}
>
<Tooltip
arrowSize={6}
content={i18n('calling__pip--off')}
hoverDelay={0}
/>
<Tooltip content={i18n('calling__pip--off')}>
<button
aria-label={i18n('calling__pip--off')}
className="module-calling-pip__button--pip"
onClick={togglePip}
type="button"
>
<div />
</Tooltip>
</button>
</button>
</Tooltip>
</div>
</div>
);

View file

@ -2,8 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import Tooltip from 'react-tooltip-lite';
import { Tooltip } from './Tooltip';
import { LocalizerType } from '../types/Util';
type PropsType = {
@ -15,22 +15,16 @@ export const InContactsIcon = (props: PropsType): JSX.Element => {
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
return (
<Tooltip
tagName="span"
direction="bottom"
className="module-in-contacts-icon__tooltip"
arrowSize={8}
content={i18n('contactInAddressBook')}
distance={13}
hoverDelay={0}
>
<span
tabIndex={0}
role="img"
aria-label={i18n('contactInAddressBook')}
className="module-in-contacts-icon__icon"
/>
</Tooltip>
<span className="module-in-contacts-icon__tooltip">
<Tooltip content={i18n('contactInAddressBook')}>
<span
tabIndex={0}
role="img"
aria-label={i18n('contactInAddressBook')}
className="module-in-contacts-icon__icon"
/>
</Tooltip>
</span>
);
/* eslint-enable jsx-a11y/no-noninteractive-tabindex */
};

View file

@ -2,8 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import Tooltip from 'react-tooltip-lite';
import { Avatar } from './Avatar';
import { Tooltip } from './Tooltip';
import { ContactName } from './conversation/ContactName';
import { LocalizerType } from '../types/Util';
import { ColorType } from '../types/Colors';
@ -41,22 +41,16 @@ const CallButton = ({
tooltipContent,
}: CallButtonProps): JSX.Element => {
return (
<button
className={`module-incoming-call__button module-incoming-call__button--${classSuffix}`}
onClick={onClick}
tabIndex={tabIndex}
type="button"
>
<Tooltip
arrowSize={6}
content={tooltipContent}
direction="bottom"
distance={16}
hoverDelay={0}
<Tooltip content={tooltipContent}>
<button
className={`module-incoming-call__button module-incoming-call__button--${classSuffix}`}
onClick={onClick}
tabIndex={tabIndex}
type="button"
>
<div />
</Tooltip>
</button>
</button>
</Tooltip>
);
};

View 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
View 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>
);
};

View file

@ -14391,7 +14391,7 @@
"rule": "React-useRef",
"path": "ts/components/CallingLobby.js",
"line": " const localVideoRef = react_1.default.useRef(null);",
"lineNumber": 14,
"lineNumber": 15,
"reasonCategory": "usageTrusted",
"updated": "2020-10-26T19:12:24.410Z",
"reasonDetail": "Used to get the local video element for rendering."
@ -14400,7 +14400,7 @@
"rule": "React-useRef",
"path": "ts/components/CallingLobby.tsx",
"line": " const localVideoRef = React.useRef(null);",
"lineNumber": 61,
"lineNumber": 58,
"reasonCategory": "usageTrusted",
"updated": "2020-10-26T19:12:24.410Z",
"reasonDetail": "Used to get the local video element for rendering."
@ -15176,4 +15176,4 @@
"reasonCategory": "falseMatch",
"updated": "2020-09-08T23:07:22.682Z"
}
]
]