import { Fragment, useEffect, useState } from "react";
import { createPortal } from "react-dom";

import type { FC, PropsWithChildren } from "react";

/**
 * Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
 *
 * Attention: If your Portal has lazy loaded React Components, put a `<Suspense` component into the rendered Portal content
 * so it does not trigger rerenders on the highest `<Suspense` component.
 *
 * @see https://reactjs.org/docs/portals.html
 */
const Portal: FC<
    PropsWithChildren<{ active?: boolean; className?: string; tag?: string; renderInContainer?: HTMLElement }>
> = ({ active = true, children, className, tag = "div", renderInContainer }) => {
    const [renderIn] = useState(() => {
        const el = document.createElement(tag);
        className && el.classList.add(...className.split(" "));
        return el;
    });

    // Append container to `body`
    useEffect(() => {
        document.body.appendChild(renderIn);
        return () => {
            document.body.removeChild(renderIn);
        };
    }, []);

    return active ? createPortal(children, renderInContainer || renderIn) : <Fragment>{children}</Fragment>;
};

export { Portal };
