# All files PortalContainerProvider.tsx

100% Statements 94/94
100% Branches 17/17
100% Functions 3/3
100% Lines 94/94

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    951x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1122x
    1122x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x
    312x
    312x
    312x
    312x
    312x
    169x
    1x
    1x
    1x
    168x
    169x
    1x
    1x
    167x
    167x
    31x
    31x
    31x
    167x
    167x
    167x
    167x
    167x
    167x
    167x
    167x
    167x
    167x
    167x
    312x
    312x
    312x
    312x
    312x
    312x
     "use client";
    import {
      createContext,
      useContext,
      useEffect,
      useState,
      type ReactElement,
      type ReactNode,
      type RefObject,
    } from "react";

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    export type PortalContainer = Element | DocumentFragment | null;

    export const PORTAL_CONTAINER_ID = "rmd-portal-container";

    let portalContainer: PortalContainer = null;

    const getPortalContainer = (): PortalContainer =>
      typeof window === "undefined" ? null : document.body;

    const context = createContext<PortalContainer>(getPortalContainer());
    context.displayName = "PortalContainer";
    const { Provider } = context;

    /**
     * @internal
     * @remarks \@since 6.0.0
     */
    export function usePortalContainer(): PortalContainer {
      return useContext(context);
    }

    /** @remarks \@since 6.0.0 */
    export interface PortalContainerProviderProps {
      /**
       * An optional container element to use. When this is `undefined`, a
       * `<div id="rmd-portal-container"></div>` will be added as the last child to
       * the `document.body` and be used as the container element.
       */
      container?: PortalContainer | RefObject<PortalContainer>;
      children: ReactNode;
    }

    /**
     * **Client Component**
     *
     * This component allows for all child `Portal` components to render within the
     * same container element. If a custom `container` element is not provided, a
     * `<div id="rmd-portal-container"></div>` will be added as the last child to
     * the `document.body` and be used as the container element.
     *
     * @see {@link Portal}
     * @remarks \@since 6.0.0
     */
    export function PortalContainerProvider(
      props: PortalContainerProviderProps
    ): ReactElement {
      const { container, children } = props;
      const [value, setValue] = useState<PortalContainer>(portalContainer);
      useEffect(() => {
        if (container && "current" in container) {
          setValue(container.current);
          return;
        }

        if (typeof container !== "undefined") {
          return;
        }

        if (!portalContainer) {
          portalContainer = document.createElement("div");
          portalContainer.id = PORTAL_CONTAINER_ID;
        }
        if (!document.body.contains(portalContainer)) {
          document.body.appendChild(portalContainer);
        }

        setValue(portalContainer);

        return () => {
          if (portalContainer && document.body.contains(portalContainer)) {
            document.body.removeChild(portalContainer);
          }
        };
      }, [container]);

      const containerValue =
        (container && "current" in container) || !container ? value : container;
      return <Provider value={containerValue}>{children}</Provider>;
    }