UNPKG

@svelte-plugins/tooltips

Version:

A simple tooltip action and component designed for Svelte.

168 lines (140 loc) 5.16 kB
export const formatVariableKey = (str) => { return str .replace(/-_$/g, '') .replace(/([a-z0-9])([A-Z])/g, '$1-$2') .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1-$2') .toLowerCase(); }; export const getMinWidth = (element, maxWidth) => { const extraCharPadding = 2; const elementWidth = element.getBoundingClientRect().width + extraCharPadding; const elementStyle = window.getComputedStyle(element); const elementPaddingLeft = parseInt( elementStyle.getPropertyValue('padding-left'), 10 ); const elementPaddingRight = parseInt( elementStyle.getPropertyValue('padding-right'), 10 ); const elementPadding = elementPaddingLeft + elementPaddingRight; const contentWidth = elementWidth - elementPadding; return Math.round(Math.min(maxWidth, contentWidth || maxWidth)); }; export const isElementInViewport = (element, container = null, position) => { const rect = element.getBoundingClientRect(); const viewportWidth = window.innerWidth || document.documentElement.clientWidth; const viewportHeight = window.innerHeight || document.documentElement.clientHeight; let isInsideViewport = rect.bottom > 0 && rect.top < viewportHeight && rect.right > 0 && rect.left < viewportWidth; if (container) { const containerRect = container.getBoundingClientRect(); if (position === 'top' || position === 'bottom') { isInsideViewport = containerRect.bottom + containerRect.height < viewportHeight && containerRect.top < viewportHeight; } else { isInsideViewport = containerRect.right + containerRect.width < viewportWidth && containerRect.left < viewportWidth; } return isInsideViewport; } return isInsideViewport; }; export const computeTooltipPosition = ( containerRef, tooltipRef, position, coords ) => { if (!containerRef || !tooltipRef) { return coords; } const tooltipRect = tooltipRef.getBoundingClientRect(); const containerRect = containerRef.getBoundingClientRect(); const containerPosition = window.getComputedStyle(containerRef).position; const containerStyle = window.getComputedStyle(containerRef); let cumulativeOffsetTop = 0; let cumulativeOffsetLeft = 0; let fixedOffsetTop = 0; let stickyOffsetTop = 0; let fixedOffsetLeft = 0; let currentElement = containerRef; while (currentElement && currentElement !== document.body) { const computedStyle = window.getComputedStyle(currentElement); const elementPosition = computedStyle.position; const currentRect = currentElement.getBoundingClientRect(); if (elementPosition === 'fixed') { fixedOffsetTop += currentRect.top + window.scrollY; fixedOffsetLeft += currentRect.left + window.scrollX; } else if (elementPosition === 'sticky') { stickyOffsetTop += currentRect.top; fixedOffsetLeft += currentRect.left + window.scrollX; } else if (elementPosition === 'absolute' || elementPosition === 'relative') { if (elementPosition === 'absolute') { cumulativeOffsetTop -= parseFloat(computedStyle.top) || 0; cumulativeOffsetLeft -= parseFloat(computedStyle.left) || 0; } if (elementPosition === 'relative') { cumulativeOffsetTop -= currentElement.offsetTop; cumulativeOffsetLeft -= currentElement.offsetLeft; if (position === 'bottom') { cumulativeOffsetTop += containerRect.height; } if (position === 'right') { cumulativeOffsetLeft -= containerRect.width; } if (containerPosition === 'absolute') { if (position === 'right') { cumulativeOffsetLeft += containerRect.width; } } } } const transform = computedStyle.transform; if (transform && transform !== 'none') { const transformMatrix = new DOMMatrix(transform); if (elementPosition === 'relative' || elementPosition === 'absolute') { cumulativeOffsetTop -= transformMatrix.m42; cumulativeOffsetLeft -= transformMatrix.m41; } else { cumulativeOffsetTop -= currentElement.offsetTop + transformMatrix.m42; cumulativeOffsetLeft -= currentElement.offsetLeft + transformMatrix.m41; } } currentElement = currentElement.parentElement; } let finalTop = containerRect.top + cumulativeOffsetTop + stickyOffsetTop - fixedOffsetTop; let finalLeft = containerRect.left + cumulativeOffsetLeft - fixedOffsetLeft; switch (position) { case 'top': coords.top = finalTop; coords.left = finalLeft + containerRect.width / 2; break; case 'bottom': coords.top = finalTop - tooltipRect.height; coords.left = finalLeft + containerRect.width / 2; break; case 'left': coords.left = finalLeft; coords.top = finalTop + containerRect.height / 2; break; case 'right': coords.left = finalLeft + containerRect.width - tooltipRect.width; coords.top = finalTop + containerRect.height / 2; break; } coords.top += window.scrollY; coords.left += window.scrollX; return coords; };