import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { autoUpdate, flip, limitShift, offset, shift, useFloating, } from '@floating-ui/react';
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
import { createPortal } from 'react-dom';
import { seamComponentsClassName } from '../../../lib/seam/SeamProvider.js';
export function Popover(props) {
    const { children, content, instanceRef, preventCloseOnClickOutside } = props;
    const [open, setOpen] = useState(false);
    const { refs, floatingStyles } = useFloating({
        whileElementsMounted: autoUpdate,
        transform: false,
        open,
        onOpenChange: setOpen,
        placement: 'bottom',
        middleware: [
            shift({
                crossAxis: true,
                limiter: limitShift(),
            }),
            flip(),
            offset(5),
        ],
    });
    const referenceEl = useRef();
    const floatingEl = useRef();
    const setFLoating = useCallback((ref) => {
        refs.setFloating(ref);
        floatingEl.current = ref;
    }, [refs, floatingEl]);
    const toggle = useCallback(() => {
        setOpen((value) => !value);
    }, []);
    const instance = useMemo(() => ({
        show: () => {
            setOpen(true);
        },
        hide: () => {
            setOpen(false);
        },
        toggle,
    }), [toggle]);
    const setReference = useCallback((ref) => {
        if (!(ref instanceof HTMLElement) || referenceEl.current === ref)
            return;
        if (referenceEl.current != null) {
            referenceEl.current.removeEventListener('click', toggle);
        }
        refs.setReference(ref);
        ref.addEventListener('click', toggle);
        referenceEl.current = ref;
    }, [toggle, refs]);
    useImperativeHandle(instanceRef, () => instance);
    /**
     * Closes the popover when the user clicks outside of it.
     */
    const windowClickHandler = useCallback((e) => {
        const target = e.target;
        // If the target is the reference element, do nothing.
        if (referenceEl.current === target ||
            referenceEl.current?.contains(target) === true) {
            return;
        }
        const closest = target.closest('[data-seam-popover]');
        // Prevents closing if target is floating element, also adds support for nested popovers somehow :)
        if (closest != null &&
            referenceEl.current != null &&
            !closest.contains(referenceEl.current)) {
            return;
        }
        setOpen(false);
    }, []);
    useEffect(() => {
        setTimeout(() => {
            if (preventCloseOnClickOutside === false)
                return;
            globalThis.addEventListener('click', windowClickHandler);
        }, 0);
        return () => {
            globalThis.removeEventListener('click', windowClickHandler);
        };
    }, [windowClickHandler, preventCloseOnClickOutside]);
    return (_jsxs(_Fragment, { children: [children({ setRef: setReference, ...instance }), open &&
                createPortal(_jsx("div", { className: seamComponentsClassName, "data-seam-popover": '', ref: setFLoating, style: floatingStyles, children: _jsx("div", { className: 'seam-popover', children: typeof content === 'function' ? content(instance) : content }) }), globalThis.document.body)] }));
}
//# sourceMappingURL=Popover.js.map