UNPKG

@clayui/shared

Version:
102 lines (101 loc) 2.5 kB
import { useCallback, useEffect, useLayoutEffect } from "react"; import { doAlign } from "./doAlign"; import { observeRect } from "./observeRect"; const ALIGN_INVERSE = { 0: "TopCenter", 1: "TopRight", 2: "RightCenter", 3: "BottomRight", 4: "BottomCenter", 5: "BottomLeft", 6: "LeftCenter", 7: "TopLeft", 8: "RightTop", 9: "RightBottom", 10: "LeftTop", 11: "LeftBottom" }; const ALIGN_MAP = { BottomCenter: ["tc", "bc"], BottomLeft: ["tl", "bl"], BottomRight: ["tr", "br"], Center: ["cc", "cc"], LeftBottom: ["br", "bl"], LeftCenter: ["cr", "cl"], LeftTop: ["tr", "tl"], RightBottom: ["bl", "br"], RightCenter: ["cl", "cr"], RightTop: ["tl", "tr"], TopCenter: ["bc", "tc"], TopLeft: ["bl", "tl"], TopRight: ["br", "tr"] }; function getAlignPoints(val) { return ALIGN_MAP[ALIGN_INVERSE[val]]; } const BOTTOM_OFFSET = [0, 4]; const LEFT_OFFSET = [-4, 0]; const RIGHT_OFFSET = [4, 0]; const TOP_OFFSET = [0, -4]; const OFFSET_MAP = { bctc: TOP_OFFSET, blbr: RIGHT_OFFSET, bltl: TOP_OFFSET, brbl: LEFT_OFFSET, brtr: TOP_OFFSET, clcr: RIGHT_OFFSET, crcl: LEFT_OFFSET, tcbc: BOTTOM_OFFSET, tlbl: BOTTOM_OFFSET, tltr: RIGHT_OFFSET, trbr: BOTTOM_OFFSET, trtl: LEFT_OFFSET }; const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; function defaultOffset(points) { return OFFSET_MAP[points.join("")]; } function useOverlayPosition({ alignmentByViewport, alignmentPosition = 5, autoBestAlign = true, getOffset = defaultOffset, isOpen, ref, triggerRef }, deps = [isOpen]) { const alignElement = useCallback(() => { if (triggerRef.current && ref.current) { let points = alignmentPosition; if (typeof points === "number") { points = getAlignPoints(points); } doAlign({ offset: getOffset(points), overflow: { adjustX: autoBestAlign, adjustY: autoBestAlign, alwaysByViewport: alignmentByViewport }, points, sourceElement: ref.current, targetElement: triggerRef.current }); } }, []); useIsomorphicLayoutEffect(() => { if (isOpen && triggerRef.current) { alignElement(); return observeRect(triggerRef.current, alignElement); } }, deps); useIsomorphicLayoutEffect(() => { if (isOpen && ref.current) { alignElement(); return observeRect(ref.current, alignElement); } }, deps); } export { useOverlayPosition };