UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

110 lines (109 loc) 4.26 kB
"use client"; import { getEnv } from "../../core/utils/get-env/get-env.mjs"; import { toInt } from "../ScrollArea/utils/to-int.mjs"; import { useEffect, useRef, useState } from "react"; import { useMutationObserverTarget, useTimeout } from "@mantine/hooks"; //#region packages/@mantine/core/src/components/FloatingIndicator/use-floating-indicator.ts function isParent(parentElement, childElement) { if (!childElement || !parentElement) return false; let parent = childElement.parentNode; while (parent != null) { if (parent === parentElement) return true; parent = parent.parentNode; } return false; } function useFloatingIndicator({ target, parent, ref, displayAfterTransitionEnd, onTransitionStart, onTransitionEnd }) { const transitionTimeout = useRef(-1); const previousTarget = useRef(target); const [initialized, setInitialized] = useState(false); const [hidden, setHidden] = useState(typeof displayAfterTransitionEnd === "boolean" ? displayAfterTransitionEnd : false); const updatePosition = () => { if (!target || !parent || !ref.current) return; const targetRect = target.getBoundingClientRect(); const parentRect = parent.getBoundingClientRect(); const targetComputedStyle = window.getComputedStyle(target); const parentComputedStyle = window.getComputedStyle(parent); const borderTopWidth = toInt(targetComputedStyle.borderTopWidth) + toInt(parentComputedStyle.borderTopWidth); const borderLeftWidth = toInt(targetComputedStyle.borderLeftWidth) + toInt(parentComputedStyle.borderLeftWidth); const position = { top: targetRect.top - parentRect.top - borderTopWidth, left: targetRect.left - parentRect.left - borderLeftWidth, width: targetRect.width, height: targetRect.height }; ref.current.style.transform = `translateY(${position.top}px) translateX(${position.left}px)`; ref.current.style.width = `${position.width}px`; ref.current.style.height = `${position.height}px`; }; const updatePositionWithoutAnimation = () => { window.clearTimeout(transitionTimeout.current); if (ref.current) ref.current.style.transitionDuration = "0ms"; updatePosition(); transitionTimeout.current = window.setTimeout(() => { if (ref.current) ref.current.style.transitionDuration = ""; }, 30); }; const targetResizeObserver = useRef(null); const parentResizeObserver = useRef(null); useEffect(() => { if (initialized && previousTarget.current !== target && onTransitionStart) onTransitionStart(); previousTarget.current = target; updatePosition(); if (target) { targetResizeObserver.current = new ResizeObserver(updatePositionWithoutAnimation); targetResizeObserver.current.observe(target); if (parent) { parentResizeObserver.current = new ResizeObserver(updatePositionWithoutAnimation); parentResizeObserver.current.observe(parent); } return () => { targetResizeObserver.current?.disconnect(); parentResizeObserver.current?.disconnect(); }; } }, [parent, target]); useEffect(() => { if (parent) { const handleTransitionEnd = (event) => { if (isParent(event.target, parent)) { updatePositionWithoutAnimation(); setHidden(false); } }; parent.addEventListener("transitionend", handleTransitionEnd); return () => { parent.removeEventListener("transitionend", handleTransitionEnd); }; } }, [parent]); useEffect(() => { if (ref.current && onTransitionEnd) { const handleIndicatorTransitionEnd = (event) => { if (event.propertyName === "transform") onTransitionEnd(); }; ref.current.addEventListener("transitionend", handleIndicatorTransitionEnd); return () => { ref.current?.removeEventListener("transitionend", handleIndicatorTransitionEnd); }; } }, [onTransitionEnd]); useTimeout(() => { if (getEnv() !== "test") setInitialized(true); }, 20, { autoInvoke: true }); useMutationObserverTarget((mutations) => { mutations.forEach((mutation) => { if (mutation.type === "attributes" && mutation.attributeName === "dir") updatePositionWithoutAnimation(); }); }, { attributes: true, attributeFilter: ["dir"] }, () => document.documentElement); return { initialized, hidden }; } //#endregion export { useFloatingIndicator }; //# sourceMappingURL=use-floating-indicator.mjs.map