feat: auto-position tooltip and suport overflowing container (#3631)

This commit is contained in:
David Luzar 2021-05-25 13:52:04 +02:00 committed by GitHub
parent 0bbb4535cf
commit 357266e9ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 76 deletions

View File

@ -67,11 +67,7 @@ export const actionChangeExportEmbedScene = register({
onChange={(event) => updateData(event.target.checked)}
/>{" "}
{t("labels.exportEmbedScene")}
<Tooltip
label={t("labels.exportEmbedScene_details")}
position="above"
long={true}
>
<Tooltip label={t("labels.exportEmbedScene_details")} long={true}>
<div className="TooltipIcon">{questionCircle}</div>
</Tooltip>
</label>

View File

@ -1,58 +1,25 @@
@import "../css/variables.module";
.excalidraw {
.Tooltip {
position: relative;
}
.excalidraw-tooltip {
position: absolute;
z-index: 1000;
.Tooltip__label {
--arrow-size: 4px;
visibility: hidden;
background: $oc-black;
color: $oc-white;
text-align: center;
border-radius: 6px;
padding: 8px;
position: absolute;
z-index: 10;
font-size: 13px;
line-height: 1.5;
font-weight: 500;
// extra pixel offset for unknown reasons
left: calc(50% + var(--arrow-size) / 2 - 1px);
transform: translateX(-50%);
word-wrap: break-word;
padding: 8px;
border-radius: 6px;
box-sizing: border-box;
pointer-events: none;
word-wrap: break-word;
&::after {
content: "";
border: var(--arrow-size) solid transparent;
position: absolute;
left: calc(50% - var(--arrow-size));
}
background: $oc-black;
&--above {
bottom: calc(100% + var(--arrow-size) + 3px);
line-height: 1.5;
text-align: center;
font-size: 13px;
font-weight: 500;
color: $oc-white;
&::after {
border-top-color: $oc-black;
top: 100%;
}
}
display: none;
&--below {
top: calc(100% + var(--arrow-size) + 3px);
&::after {
border-bottom-color: $oc-black;
bottom: 100%;
}
}
}
.Tooltip:hover .Tooltip__label {
visibility: visible;
}
.Tooltip__label:hover {
visibility: visible;
&.excalidraw-tooltip--visible {
display: block;
}
}

View File

@ -1,31 +1,92 @@
import "./Tooltip.scss";
import React from "react";
import React, { useEffect } from "react";
const getTooltipDiv = () => {
const existingDiv = document.querySelector<HTMLDivElement>(
".excalidraw-tooltip",
);
if (existingDiv) {
return existingDiv;
}
const div = document.createElement("div");
document.body.appendChild(div);
div.classList.add("excalidraw-tooltip");
return div;
};
const updateTooltip = (
item: HTMLDivElement,
tooltip: HTMLDivElement,
label: string,
long: boolean,
) => {
tooltip.classList.add("excalidraw-tooltip--visible");
tooltip.style.minWidth = long ? "50ch" : "10ch";
tooltip.style.maxWidth = long ? "50ch" : "15ch";
tooltip.textContent = label;
const {
x: itemX,
bottom: itemBottom,
top: itemTop,
width: itemWidth,
} = item.getBoundingClientRect();
const {
width: labelWidth,
height: labelHeight,
} = tooltip.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const margin = 5;
const left = itemX + itemWidth / 2 - labelWidth / 2;
const offsetLeft =
left + labelWidth >= viewportWidth ? left + labelWidth - viewportWidth : 0;
const top = itemBottom + margin;
const offsetTop =
top + labelHeight >= viewportHeight
? itemBottom - itemTop + labelHeight + margin * 2
: 0;
Object.assign(tooltip.style, {
top: `${top - offsetTop}px`,
left: `${left - offsetLeft}px`,
});
};
type TooltipProps = {
children: React.ReactNode;
label: string;
position?: "above" | "below";
long?: boolean;
};
export const Tooltip = ({
children,
label,
position = "below",
long = false,
}: TooltipProps) => (
<div className="Tooltip">
<span
className={
position === "above"
? "Tooltip__label Tooltip__label--above"
: "Tooltip__label Tooltip__label--below"
export const Tooltip = ({ children, label, long = false }: TooltipProps) => {
useEffect(() => {
return () =>
getTooltipDiv().classList.remove("excalidraw-tooltip--visible");
}, []);
return (
<div
onPointerEnter={(event) =>
updateTooltip(
event.currentTarget as HTMLDivElement,
getTooltipDiv(),
label,
long,
)
}
onPointerLeave={() =>
getTooltipDiv().classList.remove("excalidraw-tooltip--visible")
}
style={{ width: long ? "50ch" : "10ch" }}
>
{label}
</span>
{children}
</div>
);
{children}
</div>
);
};

View File

@ -340,7 +340,7 @@ const ExcalidrawWrapper = () => {
rel="noopener noreferrer"
aria-label={t("encrypted.link")}
>
<Tooltip label={t("encrypted.tooltip")} position="above" long={true}>
<Tooltip label={t("encrypted.tooltip")} long={true}>
{shield}
</Tooltip>
</a>