feat: further Tooltip improvements

This commit is contained in:
Jacob Fletcher
2022-12-08 17:01:00 -05:00
parent 17fac6e6a0
commit e101f925cc
11 changed files with 58 additions and 79 deletions

View File

@@ -22,22 +22,6 @@
&--has-tooltip {
position: relative;
}
.btn__tooltip {
opacity: 0;
visibility: hidden;
transform: translate(-50%, -10px);
}
.btn__content {
&:hover {
.btn__tooltip {
opacity: 1;
visibility: visible;
}
}
}
&--icon-style-without-border {

View File

@@ -1,4 +1,4 @@
import React, { isValidElement } from 'react';
import React, { Fragment, isValidElement } from 'react';
import { Link } from 'react-router-dom';
import { Props } from './types';
@@ -21,31 +21,31 @@ const icons = {
const baseClass = 'btn';
const ButtonContents = ({ children, icon, tooltip }) => {
const ButtonContents = ({ children, icon, tooltip, showTooltip }) => {
const BuiltInIcon = icons[icon];
return (
<span
className={`${baseClass}__content`}
>
<Fragment>
<Tooltip
className={`${baseClass}__tooltip`}
show={tooltip}
show={showTooltip}
>
{tooltip}
</Tooltip>
{children && (
<span className={`${baseClass}__label`}>
{children}
</span>
)}
{icon && (
<span className={`${baseClass}__icon`}>
{isValidElement(icon) && icon}
{BuiltInIcon && <BuiltInIcon />}
</span>
)}
</span>
<span className={`${baseClass}__content`}>
{children && (
<span className={`${baseClass}__label`}>
{children}
</span>
)}
{icon && (
<span className={`${baseClass}__icon`}>
{isValidElement(icon) && icon}
{BuiltInIcon && <BuiltInIcon />}
</span>
)}
</span>
</Fragment>
);
};
@@ -70,6 +70,8 @@ const Button: React.FC<Props> = (props) => {
tooltip,
} = props;
const [showTooltip, setShowTooltip] = React.useState(false);
const classes = [
baseClass,
className && className,
@@ -85,6 +87,7 @@ const Button: React.FC<Props> = (props) => {
].filter(Boolean).join(' ');
function handleClick(event) {
setShowTooltip(false);
if (type !== 'submit' && onClick) event.preventDefault();
if (onClick) onClick(event);
}
@@ -94,6 +97,8 @@ const Button: React.FC<Props> = (props) => {
type,
className: classes,
disabled,
onMouseEnter: tooltip ? () => setShowTooltip(true) : undefined,
onMouseLeave: tooltip ? () => setShowTooltip(false) : undefined,
onClick: !disabled ? handleClick : undefined,
rel: newTab ? 'noopener noreferrer' : undefined,
target: newTab ? '_blank' : undefined,
@@ -109,6 +114,7 @@ const Button: React.FC<Props> = (props) => {
<ButtonContents
icon={icon}
tooltip={tooltip}
showTooltip={showTooltip}
>
{children}
</ButtonContents>
@@ -124,6 +130,7 @@ const Button: React.FC<Props> = (props) => {
<ButtonContents
icon={icon}
tooltip={tooltip}
showTooltip={showTooltip}
>
{children}
</ButtonContents>
@@ -141,6 +148,7 @@ const Button: React.FC<Props> = (props) => {
<ButtonContents
icon={icon}
tooltip={tooltip}
showTooltip={showTooltip}
>
{children}
</ButtonContents>

View File

@@ -14,22 +14,8 @@
width: 0px;
}
.tooltip {
pointer-events: none;
opacity: 0;
visibility: hidden;
}
&:focus,
&:active {
outline: none;
}
&:hover {
.tooltip {
opacity: 1;
visibility: visible;
}
}
}

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef } from 'react';
import React, { useState, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import Copy from '../../icons/Copy';
import Tooltip from '../Tooltip';
@@ -18,14 +18,6 @@ const CopyToClipboard: React.FC<Props> = ({
const [hovered, setHovered] = useState(false);
const { t } = useTranslation('general');
useEffect(() => {
if (copied && !hovered) {
setTimeout(() => {
setCopied(false);
}, 1500);
}
}, [copied, hovered]);
if (value) {
return (
<button
@@ -44,13 +36,15 @@ const CopyToClipboard: React.FC<Props> = ({
ref.current.select();
ref.current.setSelectionRange(0, value.length + 1);
document.execCommand('copy');
setCopied(true);
}
}}
>
<Copy />
<Tooltip>
<Tooltip
show={hovered || copied}
delay={copied ? 0 : undefined}
>
{copied && (successMessage ?? t('copied'))}
{!copied && (defaultMessage ?? t('copy'))}
</Tooltip>

View File

@@ -30,7 +30,6 @@ export const MultiValueRemove: React.FC<MultiValueRemoveProps<OptionType>> = (pr
<Tooltip
className={`${baseClass}__tooltip`}
show={showTooltip}
delay={350}
>
{t('remove')}
</Tooltip>

View File

@@ -1,5 +1,7 @@
@import '../../../scss/styles.scss';
$caretSize: 6;
.tooltip {
opacity: 0;
background-color: var(--theme-elevation-800);
@@ -7,27 +9,33 @@
z-index: 2;
bottom: 100%;
left: 50%;
transform: translate3d(-50%, -20%, 0);
transform: translate3d(-50%, calc(#{$caretSize}px * -1), 0);
padding: base(.2) base(.4);
color: var(--theme-elevation-0);
line-height: base(.75);
font-weight: normal;
white-space: nowrap;
border-radius: 2px;
transition: opacity .2s ease-in-out;
visibility: hidden;
span {
position: absolute;
transform: translateX(-50%);
top: calc(100% - #{base(.0625)});
left: 50%;
height: 0;
width: 0;
border: 10px solid transparent;
border-top-color: var(--theme-elevation-800);
}
&::after {
content: ' ';
display: block;
position: absolute;
bottom: 0;
left: 50%;
transform: translate3d(-50%, 100%, 0);
width: 0;
height: 0;
border-left: #{$caretSize}px solid transparent;
border-right: #{$caretSize}px solid transparent;
border-top: #{$caretSize}px solid var(--theme-elevation-800);
}
&--show {
visibility: visible;
opacity: 1;
transition: opacity .2s ease-in-out;
cursor: default;
}
}

View File

@@ -8,7 +8,7 @@ const Tooltip: React.FC<Props> = (props) => {
className,
children,
show: showFromProps = true,
delay,
delay = 350,
} = props;
const [show, setShow] = React.useState(showFromProps);
@@ -16,7 +16,7 @@ const Tooltip: React.FC<Props> = (props) => {
useEffect(() => {
let timerId: NodeJS.Timeout;
// do not use the delay on out
// do not use the delay on transition-out
if (delay && showFromProps) {
timerId = setTimeout(() => {
setShow(showFromProps);
@@ -39,7 +39,6 @@ const Tooltip: React.FC<Props> = (props) => {
].filter(Boolean).join(' ')}
>
{children}
<span />
</aside>
);
};

View File

@@ -14,7 +14,10 @@ const Error: React.FC<Props> = (props) => {
if (showError) {
return (
<Tooltip className={baseClass}>
<Tooltip
className={baseClass}
delay={0}
>
{message}
</Tooltip>
);

View File

@@ -105,11 +105,11 @@ export const AddNewRelation: React.FC<Props> = ({ path, hasMany, relationTo, val
className={`${baseClass}__add-button`}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
onClick={() => setShowTooltip(false)}
>
<Tooltip
className={`${baseClass}__tooltip`}
show={showTooltip}
delay={350}
>
{t('addNewLabel', { label: relatedCollections[0].labels.singular })}
</Tooltip>

View File

@@ -60,7 +60,6 @@ export const MultiValueLabel: React.FC<MultiValueProps<Option>> = (props) => {
<Tooltip
className={`${baseClass}__tooltip`}
show={showTooltip}
delay={350}
>
{t('editLabel', { label: '' })}
</Tooltip>

View File

@@ -57,7 +57,6 @@ export const SingleValue: React.FC<SingleValueProps<Option>> = (props) => {
<Tooltip
className={`${baseClass}__tooltip`}
show={showTooltip}
delay={350}
>
{t('editLabel', { label: '' })}
</Tooltip>