Fix tooltip bugs
This commit is contained in:
parent
6398a01852
commit
c6eafbb8d5
16 changed files with 339 additions and 235 deletions
|
@ -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
|
||||
|
|
|
@ -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} />;
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
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",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue