"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import { delegateEvent } from "../delegateEvent.js";
import { useEnsuredRef } from "../useEnsuredRef.js";
import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect.js";
import { BELOW_CENTER_ANCHOR } from "./constants.js";
import { getFixedPosition } from "./getFixedPosition.js";
import { isWithinViewport } from "./utils.js";
const noop = ()=>undefined;
/**
 * This hook is used to attach a temporary (fixed) element to another element
 * within the page. In other words, this is a way to have an element with
 * `position: fixed` as if it were `position: absolute` to a parent element that
 * had `position: relative`.
 *
 * @example
 * Simple Example
 * ```tsx
 * import { ReactElement, useRef, useState } from "react";
 * import { Button, useCSSTransition, useFixedPositioning } from "@react-md/core";
 *
 * function Example(): ReactElement {
 *   const fixedTo = useRef<HTMLButtonElement>(null);
 *   const [transitionIn, setTransitionIn] = useState(false);
 *   const { style, transitionOptions } = useFixedPositioning({
 *     fixedTo,
 *   });
 *   const { elementProps, rendered } = useCSSTransition({
 *     ...transitionOptions,
 *     transitionIn,
 *     temporary: true,
 *     timeout: {
 *       enter: 200,
 *       exit: 150,
 *     },
 *     classNames: {
 *       enter: "enter",
 *       enterActive: "enter--active",
 *       exit: "exit",
 *       exitActive: "exit--active",
 *     },
 *   });
 *
 *   return (
 *     <>
 *       <Button
 *         ref={fixedTo}
 *         onClick={() => setTransitionIn(!transitionIn)}
 *       >
 *         Toggle
 *       </Button>
 *       {rendered && (
 *         <div {...elementProps} style={style}>
 *           Fixed Temporary Element
 *         </div>
 *       )}
 *     </>
 *   );
 * }
 * ```
 *
 * @typeParam FixedToElement - An HTMLElement type for the static element.
 * @typeParam FixedElement - An HTMLElement type for the fixed element.
 * @remarks \@since 4.0.0
 */ export function useFixedPositioning(options) {
    const { style: propStyle, nodeRef, fixedTo, onEnter = noop, onEntering = noop, onEntered = noop, onExited = noop, anchor = BELOW_CENTER_ANCHOR, disableSwapping, disableVHBounds, initialX, initialY, preventOverlap, transformOrigin, vhMargin, vwMargin, width, xMargin, yMargin, getFixedPositionOptions = noop, onScroll, onResize = noop } = options;
    const [active, setActive] = useState(false);
    const [ref, refHandler] = useEnsuredRef(nodeRef);
    const optionsRef = useRef({
        ref,
        fixedTo,
        anchor,
        disableSwapping,
        disableVHBounds,
        preventOverlap,
        transformOrigin,
        vhMargin,
        vwMargin,
        width,
        xMargin,
        yMargin,
        getFixedPositionOptions
    });
    useIsomorphicLayoutEffect(()=>{
        optionsRef.current = {
            ref,
            fixedTo,
            anchor,
            disableSwapping,
            disableVHBounds,
            preventOverlap,
            transformOrigin,
            vhMargin,
            vwMargin,
            width,
            xMargin,
            yMargin,
            getFixedPositionOptions
        };
    }, [
        ref,
        fixedTo,
        anchor,
        disableSwapping,
        disableVHBounds,
        preventOverlap,
        transformOrigin,
        vhMargin,
        vwMargin,
        width,
        xMargin,
        yMargin,
        getFixedPositionOptions
    ]);
    const [style, setStyle] = useState(()=>getFixedPosition({
            container: ref.current,
            element: fixedTo.current,
            anchor,
            disableSwapping,
            disableVHBounds,
            initialX,
            initialY,
            preventOverlap,
            transformOrigin,
            vhMargin,
            vwMargin,
            width,
            xMargin,
            yMargin,
            ...getFixedPositionOptions()
        }).style);
    const updateStyle = useCallback(()=>{
        const { ref, fixedTo, anchor, disableSwapping, disableVHBounds, preventOverlap, transformOrigin, vhMargin, vwMargin, width, xMargin, yMargin, getFixedPositionOptions } = optionsRef.current;
        const element = ref.current;
        const container = fixedTo.current;
        const { style } = getFixedPosition({
            container,
            element,
            anchor,
            disableSwapping,
            disableVHBounds,
            initialX,
            initialY,
            preventOverlap,
            transformOrigin,
            vhMargin,
            vwMargin,
            width,
            xMargin,
            yMargin,
            ...getFixedPositionOptions()
        });
        setStyle(style);
        setActive(!!element && !element.hidden);
    // Only changing the initialX and initialY should cause the useEffect below
    // to trigger, which is why everything else is set in a ref.
    }, [
        initialX,
        initialY
    ]);
    useEffect(()=>{
        if (!active) {
            return;
        }
        const resizeCallback = (event)=>{
            onResize(event);
            updateStyle();
        };
        const scrollCallback = (event)=>{
            const fixedElement = ref.current;
            const fixedToElement = fixedTo.current;
            if (onScroll && fixedElement && fixedToElement) {
                onScroll(event, {
                    visible: isWithinViewport({
                        fixedElement,
                        fixedToElement
                    }),
                    fixedElement,
                    fixedToElement
                });
            }
            updateStyle();
        };
        const resizeHandler = delegateEvent("resize", window, true);
        const scrollHandler = delegateEvent("scroll", window, true, {
            passive: true
        });
        resizeHandler.add(resizeCallback);
        scrollHandler.add(scrollCallback);
        return ()=>{
            resizeHandler.remove(resizeCallback);
            scrollHandler.remove(scrollCallback);
        };
    }, [
        active,
        fixedTo,
        onResize,
        onScroll,
        ref,
        updateStyle
    ]);
    const callbacks = {
        onEnter (appearing) {
            onEnter(appearing);
            updateStyle();
        },
        onEntering (appearing) {
            onEntering(appearing);
            updateStyle();
        },
        onEntered (appearing) {
            onEntered(appearing);
            updateStyle();
        },
        onExited () {
            onExited();
            setActive(false);
        }
    };
    return {
        ref: refHandler,
        style: {
            ...style,
            ...propStyle
        },
        callbacks,
        updateStyle,
        transitionOptions: {
            ...callbacks,
            nodeRef: refHandler
        }
    };
}

//# sourceMappingURL=useFixedPositioning.js.map