aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tooltip/tooltip.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Tooltip/tooltip.ts')
-rw-r--r--src/lib/Tooltip/tooltip.ts319
1 files changed, 161 insertions, 158 deletions
diff --git a/src/lib/Tooltip/tooltip.ts b/src/lib/Tooltip/tooltip.ts
index 024ca0fd..3235cb25 100644
--- a/src/lib/Tooltip/tooltip.ts
+++ b/src/lib/Tooltip/tooltip.ts
@@ -1,162 +1,165 @@
const tooltip = (element: HTMLElement) => {
- let tooltipDiv: HTMLDivElement | null = null;
- const offset = 10;
- const tooltipTransitionTime = 200;
- const tooltipHideDelay = 10;
- const debounceDelay = 100;
- let hideTimeout: number | null = null;
- let debounceTimer: number | null = null;
-
- if (element.dataset.tooltipDisable === 'true') return;
-
- const createTooltip = () => {
- if (!tooltipDiv) {
- tooltipDiv = document.createElement('div');
-
- tooltipDiv.style.position = 'absolute';
- tooltipDiv.style.zIndex = '1000';
- tooltipDiv.style.opacity = '0';
- tooltipDiv.style.transition = `opacity ${tooltipTransitionTime}ms ease-in-out, top 0.3s ease, left 0.3s ease`;
- tooltipDiv.style.pointerEvents = 'none';
- tooltipDiv.style.whiteSpace = 'nowrap';
- tooltipDiv.style.zIndex = '1000';
-
- tooltipDiv.classList.add('card');
- tooltipDiv.classList.add('card-small');
- document.body.appendChild(tooltipDiv);
- }
- };
-
- const updateTooltipPosition = (x: number, y: number) => {
- if (tooltipDiv) {
- const tooltipPin = element.dataset.tooltippin;
-
- if (tooltipPin) {
- const pinnedElement = document.getElementById(tooltipPin);
-
- if (pinnedElement) {
- const rect = pinnedElement.getBoundingClientRect();
- const tooltipWidth = tooltipDiv.offsetWidth;
- const tooltipHeight = tooltipDiv.offsetHeight;
- let top = rect.top - tooltipHeight - offset;
- let left = rect.left + rect.width / 2 - tooltipWidth / 2;
-
- if (left < 0) left = offset;
- if (left + tooltipWidth > window.innerWidth)
- left = window.innerWidth - tooltipWidth - offset;
- if (top < 0) top = rect.top + rect.height + offset;
-
- tooltipDiv.style.left = `${left}px`;
- tooltipDiv.style.top = `${top + window.scrollY}px`;
-
- return;
- }
- }
-
- const tooltipWidth = tooltipDiv.offsetWidth;
- const tooltipHeight = tooltipDiv.offsetHeight;
- let top = y - tooltipHeight - offset;
- let left = x - tooltipWidth / 2;
-
- if (left < 0) left = offset;
- if (left + tooltipWidth > window.innerWidth) left = window.innerWidth - tooltipWidth - offset;
- if (top < 0) top = y + offset;
-
- tooltipDiv.style.left = `${left}px`;
- tooltipDiv.style.top = `${top}px`;
- }
- };
-
- const showTooltip = (content: string, x: number, y: number) => {
- if (hideTimeout !== null) {
- clearTimeout(hideTimeout);
-
- hideTimeout = null;
- }
-
- createTooltip();
-
- if (tooltipDiv) {
- tooltipDiv.innerHTML = content.replace(/\n/g, '<br>');
-
- updateTooltipPosition(x, y);
- setTimeout(() => {
- if (tooltipDiv) {
- tooltipDiv.style.opacity = '1';
- }
- }, 10);
- }
- };
-
- const hideTooltip = () => {
- setTimeout(() => {
- if (tooltipDiv) {
- tooltipDiv.style.opacity = '0';
-
- hideTimeout = window.setTimeout(() => {
- if (tooltipDiv) {
- document.body.removeChild(tooltipDiv);
- tooltipDiv = null;
- }
- }, tooltipTransitionTime);
- }
- }, tooltipHideDelay);
- };
-
- const handleMouseEnter = (event: MouseEvent) => {
- const title = element.getAttribute('title');
-
- if (title) {
- element.removeAttribute('title');
-
- if (hideTimeout !== null) {
- clearTimeout(hideTimeout);
- hideTimeout = null;
- }
-
- if (!tooltipDiv) {
- showTooltip(title, event.pageX, event.pageY);
- }
- }
- };
-
- const handleMouseMove = (event: MouseEvent) => {
- if (debounceTimer !== null) clearTimeout(debounceTimer);
-
- debounceTimer = window.setTimeout(() => {
- if (tooltipDiv && tooltipDiv.style.opacity === '1')
- updateTooltipPosition(event.pageX, event.pageY);
- }, debounceDelay);
- };
-
- const handleMouseLeave = () => {
- element.setAttribute(
- 'title',
- tooltipDiv ? tooltipDiv.innerHTML?.replace(/<br>/g, '\n') || '' : ''
- );
- hideTooltip();
- };
-
- element.addEventListener('mouseenter', handleMouseEnter);
- element.addEventListener('mousemove', handleMouseMove);
- element.addEventListener('mouseleave', handleMouseLeave);
-
- return {
- destroy() {
- element.removeEventListener('mouseenter', handleMouseEnter);
- element.removeEventListener('mousemove', handleMouseMove);
- element.removeEventListener('mouseleave', handleMouseLeave);
-
- if (hideTimeout !== null) clearTimeout(hideTimeout);
- if (debounceTimer !== null) clearTimeout(debounceTimer);
-
- if (tooltipDiv && document.body.contains(tooltipDiv)) {
- document.body.removeChild(tooltipDiv);
-
- tooltipDiv = null;
- }
- }
- };
+ let tooltipDiv: HTMLDivElement | null = null;
+ const offset = 10;
+ const tooltipTransitionTime = 200;
+ const tooltipHideDelay = 10;
+ const debounceDelay = 100;
+ let hideTimeout: number | null = null;
+ let debounceTimer: number | null = null;
+
+ if (element.dataset.tooltipDisable === "true") return;
+
+ const createTooltip = () => {
+ if (!tooltipDiv) {
+ tooltipDiv = document.createElement("div");
+
+ tooltipDiv.style.position = "absolute";
+ tooltipDiv.style.top = "-9999px";
+ tooltipDiv.style.left = "-9999px";
+ tooltipDiv.style.zIndex = "1000";
+ tooltipDiv.style.opacity = "0";
+ tooltipDiv.style.transition = `opacity ${tooltipTransitionTime}ms ease-in-out`;
+ tooltipDiv.style.pointerEvents = "none";
+ tooltipDiv.style.whiteSpace = "nowrap";
+
+ tooltipDiv.classList.add("card");
+ tooltipDiv.classList.add("card-small");
+ document.body.appendChild(tooltipDiv);
+ }
+ };
+
+ const updateTooltipPosition = (x: number, y: number) => {
+ if (tooltipDiv) {
+ const tooltipPin = element.dataset.tooltippin;
+
+ if (tooltipPin) {
+ const pinnedElement = document.getElementById(tooltipPin);
+
+ if (pinnedElement) {
+ const rect = pinnedElement.getBoundingClientRect();
+ const tooltipWidth = tooltipDiv.offsetWidth;
+ const tooltipHeight = tooltipDiv.offsetHeight;
+ let top = rect.top - tooltipHeight - offset;
+ let left = rect.left + rect.width / 2 - tooltipWidth / 2;
+
+ if (left < 0) left = offset;
+ if (left + tooltipWidth > window.innerWidth)
+ left = window.innerWidth - tooltipWidth - offset;
+ if (top < 0) top = rect.top + rect.height + offset;
+
+ tooltipDiv.style.left = `${left}px`;
+ tooltipDiv.style.top = `${top + window.scrollY}px`;
+
+ return;
+ }
+ }
+
+ const tooltipWidth = tooltipDiv.offsetWidth;
+ const tooltipHeight = tooltipDiv.offsetHeight;
+ let top = y - tooltipHeight - offset;
+ let left = x - tooltipWidth / 2;
+
+ if (left < 0) left = offset;
+ if (left + tooltipWidth > window.innerWidth)
+ left = window.innerWidth - tooltipWidth - offset;
+ if (top < 0) top = y + offset;
+
+ tooltipDiv.style.left = `${left}px`;
+ tooltipDiv.style.top = `${top}px`;
+ }
+ };
+
+ const showTooltip = (content: string, x: number, y: number) => {
+ if (hideTimeout !== null) {
+ clearTimeout(hideTimeout);
+
+ hideTimeout = null;
+ }
+
+ createTooltip();
+
+ if (tooltipDiv) {
+ tooltipDiv.innerHTML = content.replace(/\n/g, "<br>");
+
+ updateTooltipPosition(x, y);
+ requestAnimationFrame(() => {
+ if (tooltipDiv) {
+ tooltipDiv.style.transition = `opacity ${tooltipTransitionTime}ms ease-in-out, top 0.3s ease, left 0.3s ease`;
+ tooltipDiv.style.opacity = "1";
+ }
+ });
+ }
+ };
+
+ const hideTooltip = () => {
+ setTimeout(() => {
+ if (tooltipDiv) {
+ tooltipDiv.style.opacity = "0";
+
+ hideTimeout = window.setTimeout(() => {
+ if (tooltipDiv) {
+ document.body.removeChild(tooltipDiv);
+ tooltipDiv = null;
+ }
+ }, tooltipTransitionTime);
+ }
+ }, tooltipHideDelay);
+ };
+
+ const handleMouseEnter = (event: MouseEvent) => {
+ const title = element.getAttribute("title");
+
+ if (title) {
+ element.removeAttribute("title");
+
+ if (hideTimeout !== null) {
+ clearTimeout(hideTimeout);
+ hideTimeout = null;
+ }
+
+ if (!tooltipDiv) {
+ showTooltip(title, event.pageX, event.pageY);
+ }
+ }
+ };
+
+ const handleMouseMove = (event: MouseEvent) => {
+ if (debounceTimer !== null) clearTimeout(debounceTimer);
+
+ debounceTimer = window.setTimeout(() => {
+ if (tooltipDiv && tooltipDiv.style.opacity === "1")
+ updateTooltipPosition(event.pageX, event.pageY);
+ }, debounceDelay);
+ };
+
+ const handleMouseLeave = () => {
+ element.setAttribute(
+ "title",
+ tooltipDiv ? tooltipDiv.innerHTML?.replace(/<br>/g, "\n") || "" : "",
+ );
+ hideTooltip();
+ };
+
+ element.addEventListener("mouseenter", handleMouseEnter);
+ element.addEventListener("mousemove", handleMouseMove);
+ element.addEventListener("mouseleave", handleMouseLeave);
+
+ return {
+ destroy() {
+ element.removeEventListener("mouseenter", handleMouseEnter);
+ element.removeEventListener("mousemove", handleMouseMove);
+ element.removeEventListener("mouseleave", handleMouseLeave);
+
+ if (hideTimeout !== null) clearTimeout(hideTimeout);
+ if (debounceTimer !== null) clearTimeout(debounceTimer);
+
+ if (tooltipDiv && document.body.contains(tooltipDiv)) {
+ document.body.removeChild(tooltipDiv);
+
+ tooltipDiv = null;
+ }
+ },
+ };
};
export default tooltip;