import * as React from 'react';
import { useMemo, useRef, useEffect, useLayoutEffect, useCallback } from 'react';
import { getResizeObserverObject } from './getResizeObserverObject';
export const setupResizeObserver = (node, callback) => {
    const RO = getResizeObserverObject();
    if (!RO) {
        return () => { };
    }
    const observer = new RO((entries) => {
        const entry = entries[0];
        let { width, height } = entry.contentRect;
        if (entry.borderBoxSize?.[0]) {
            height = entry.borderBoxSize[0].blockSize;
            width = entry.borderBoxSize[0].inlineSize;
        }
        else {
            // this is needed for Safari and other browsers that don't have borderBoxSize on the entry object
            const rect = node.getBoundingClientRect();
            height = rect.height;
            width = rect.width;
        }
        callback({ width, height });
    });
    observer.observe(node);
    return () => {
        observer.disconnect();
    };
};
/**
 * A hook that notifies you when a certain DOM element has changed it's size
 *
 * @param ref A React ref to a DOM element
 * @param callback The function to be called when the element is resized.
 */
export const useResizeObserver = (ref, callback, config = { earlyAttach: false }) => {
    const sizeRef = useRef({
        width: 0,
        height: 0,
    });
    const effectFn = (callback) => {
        let disconnect;
        if (ref.current) {
            disconnect = setupResizeObserver(ref.current, (size) => {
                size = {
                    width: Math.round(size.width),
                    height: Math.round(size.height),
                };
                const prevSize = sizeRef.current;
                if (prevSize.width !== size.width || prevSize.height !== size.height) {
                    sizeRef.current = size;
                    callback(size);
                }
            });
        }
        return () => {
            if (disconnect) {
                disconnect();
            }
        };
    };
    useEffect(() => {
        if (!config.earlyAttach) {
            return effectFn(callback);
        }
        return () => { };
    }, [ref.current, callback, config.earlyAttach]);
    useLayoutEffect(() => {
        if (config.earlyAttach) {
            return effectFn(callback);
        }
        return () => { };
    }, [ref.current, callback, config.earlyAttach]);
};
export const ReactResizeObserver = ({ notifyOnMount = true, earlyAttach = false, ...props }) => {
    const style = useMemo(() => ({
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        boxSizing: 'border-box',
    }), []);
    const firstTime = useRef(true);
    const ref = useRef(null);
    const onResize = useCallback((size) => {
        if (firstTime.current && !notifyOnMount) {
            firstTime.current = false;
            return;
        }
        props.onResize(size);
    }, [props.onResize]);
    useResizeObserver(ref, onResize, { earlyAttach: earlyAttach || false });
    return React.createElement("div", { ref: ref, style: style });
};
