LCOV - code coverage report
Current view: top level - dashql-app/src/ui/foundations - portal.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 92.3 % 52 48
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : /// This file is copied almost as-is from the Portal of @primer/react
       2              : 
       3              : import * as React from 'react'
       4              : import { createPortal } from 'react-dom'
       5              : 
       6            1 : const DASHQL_PORTAL_ROOT_ID = '__dashqlPortalRoot__'
       7            1 : const DEFAULT_PORTAL_CONTAINER_NAME = '__default__'
       8              : 
       9            1 : const portalRootRegistry: Partial<Record<string, Element>> = {}
      10              : 
      11              : /// Register a container to serve as a portal root.
      12              : /// If name is not specified, registers the default portal root.
      13            1 : export function registerPortalRoot(root: Element, name = DEFAULT_PORTAL_CONTAINER_NAME): void {
      14            1 :     portalRootRegistry[name] = root
      15            1 : }
      16              : 
      17              : /// Ensures that a default portal root exists and is registered. If a DOM element exists
      18              : /// with id __dashqlPortalRoot__, allow that element to serve as the default portal root.
      19              : /// Otherwise, create that element and attach it to the end of document.body.
      20            1 : function ensureDefaultPortal() {
      21            1 :     const existingDefaultContainer = portalRootRegistry[DEFAULT_PORTAL_CONTAINER_NAME]
      22            1 :     if (!existingDefaultContainer || !document.body.contains(existingDefaultContainer)) {
      23            1 :         let defaultContainer = document.getElementById(DASHQL_PORTAL_ROOT_ID)
      24            1 :         if (!(defaultContainer instanceof Element)) {
      25            1 :             defaultContainer = document.createElement('div')
      26            1 :             defaultContainer.setAttribute('id', DASHQL_PORTAL_ROOT_ID)
      27            1 :             defaultContainer.style.position = 'absolute'
      28            1 :             defaultContainer.style.top = '0'
      29            1 :             defaultContainer.style.left = '0'
      30            1 :             const suitablePortalRoot = document.querySelector('[data-portal-root]')
      31            1 :             if (suitablePortalRoot) {
      32            0 :                 suitablePortalRoot.appendChild(defaultContainer)
      33              :             } else {
      34            1 :                 document.body.appendChild(defaultContainer)
      35              :             }
      36            1 :         }
      37            1 :         registerPortalRoot(defaultContainer)
      38            1 :     }
      39            1 : }
      40              : 
      41              : export interface PortalProps {
      42              :     /// Called when this portal is added to the DOM
      43              :     onMount?: () => void
      44              :     /// Optional. Mount this portal at the container specified
      45              :     /// by this name. The container must be previously registered
      46              :     /// with `registerPortal`.
      47              :     containerName?: string
      48              :     /// The children elements
      49              :     children?: React.ReactElement;
      50              : }
      51              : 
      52              : /// Creates a React Portal, placing all children in a separate physical DOM root node.
      53            1 : export function Portal(props: PortalProps) {
      54            1 :     const elementRef = React.useRef<HTMLDivElement | null>(null)
      55            1 :     if (!elementRef.current) {
      56            1 :         const div = document.createElement('div')
      57            1 :         div.style.position = 'relative';
      58            1 :         div.style.zIndex = '1000';
      59            1 :         elementRef.current = div
      60            1 :     }
      61            1 :     const element = elementRef.current;
      62              : 
      63            1 :     React.useLayoutEffect(() => {
      64            1 :         let containerName = props.containerName
      65            1 :         if (containerName === undefined) {
      66            1 :             containerName = DEFAULT_PORTAL_CONTAINER_NAME
      67            1 :             ensureDefaultPortal();
      68            1 :         }
      69            1 :         const parentElement = portalRootRegistry[containerName];
      70            1 :         if (!parentElement) {
      71            0 :             throw new Error(
      72            0 :                 `Portal container '${props.containerName}' is not yet registered. Container must be registered with registerPortal before use.`,
      73            0 :             )
      74              :         }
      75            1 :         parentElement.appendChild(element);
      76            1 :         props.onMount?.();
      77              : 
      78            1 :         return () => {
      79            1 :             parentElement.removeChild(element)
      80            1 :         }
      81            1 :     }, [element]);
      82              : 
      83            1 :     return createPortal(props.children, element);
      84            1 : }
        

Generated by: LCOV version 2.0-1