{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/Portal/index.tsx"],"sourcesContent":["import { createContext, useCallback, useContext, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useIsMounted } from '../../hooks/useIsMounted';\nimport { useIsomorphicLayoutEffect } from '../../hooks/useIsomorphicLayoutEffect';\n\ninterface PortalProps {\n  children: React.ReactNode;\n  className?: string;\n  containerRef?: React.RefObject<HTMLElement | null>;\n}\n\nconst PortalContext = createContext<{\n  parentPortalElement: HTMLElement | null;\n}>({\n  parentPortalElement: null,\n});\n\nconst PORTAL_DEFAULT_CLASS = 'portal';\n\nfunction RenderPortal({\n  children,\n  className = PORTAL_DEFAULT_CLASS,\n  containerRef,\n}: PortalProps) {\n  const { parentPortalElement } = useContext(PortalContext);\n\n  const createPortalElement = useCallback(\n    (mountElement: HTMLElement) => {\n      const portalElement = mountElement.ownerDocument.createElement('div');\n      portalElement.classList.add(className);\n\n      return portalElement;\n    },\n    [className]\n  );\n\n  /**\n   * This is the mountElement to render portalElement.\n   * The mountElement has the value \"containerRef.current\" if it has a \"containerRef\", or the parent portalElement if it is a nested portal.\n   * By default, it has \"document.body\".\n   */\n  const mountElement = useMemo(() => {\n    return parentPortalElement || containerRef?.current || document.body;\n  }, [parentPortalElement, containerRef]);\n\n  const portalElement = useMemo(() => {\n    return createPortalElement(mountElement);\n  }, [createPortalElement, mountElement]);\n\n  useIsomorphicLayoutEffect(() => {\n    mountElement.appendChild(portalElement);\n\n    // \"portalElement\" is removed from \"mountElement\" on unmount.\n    return () => {\n      if (mountElement.contains(portalElement)) {\n        mountElement.removeChild(portalElement);\n      }\n    };\n  }, [portalElement, mountElement]);\n\n  return createPortal(\n    <PortalContext.Provider value={{ parentPortalElement: portalElement }}>\n      {children}\n    </PortalContext.Provider>,\n    portalElement\n  );\n}\n\nexport const Portal = ({ children, ...restProps }: PortalProps) => {\n  const isMounted = useIsMounted();\n\n  // With this code, it is possible to solve the \"window is not defined\" and \"Hydration Error\" that can occur in SSR.\n  if (!isMounted) {\n    return <></>;\n  }\n\n  return <RenderPortal {...restProps}>{children}</RenderPortal>;\n};\n"],"mappings":";;;;;;AAWA,MAAM,gBAAgB,cAEnB,EACD,qBAAqB,MACtB,CAAC;AAEF,MAAM,uBAAuB;AAE7B,SAAS,aAAa,EACpB,UACA,YAAY,sBACZ,gBACc;CACd,MAAM,EAAE,wBAAwB,WAAW,cAAc;CAEzD,MAAM,sBAAsB,aACzB,iBAA8B;EAC7B,MAAM,gBAAgB,aAAa,cAAc,cAAc,MAAM;EACrE,cAAc,UAAU,IAAI,UAAU;EAEtC,OAAO;IAET,CAAC,UAAU,CACZ;;;;;;CAOD,MAAM,eAAe,cAAc;EACjC,OAAO,uBAAuB,cAAc,WAAW,SAAS;IAC/D,CAAC,qBAAqB,aAAa,CAAC;CAEvC,MAAM,gBAAgB,cAAc;EAClC,OAAO,oBAAoB,aAAa;IACvC,CAAC,qBAAqB,aAAa,CAAC;CAEvC,gCAAgC;EAC9B,aAAa,YAAY,cAAc;EAGvC,aAAa;GACX,IAAI,aAAa,SAAS,cAAc,EACtC,aAAa,YAAY,cAAc;;IAG1C,CAAC,eAAe,aAAa,CAAC;CAEjC,OAAO,aACL,oBAAC,cAAc,UAAf;EAAwB,OAAO,EAAE,qBAAqB,eAAe;EAClE;EACsB,CAAA,EACzB,cACD;;AAGH,MAAa,UAAU,EAAE,UAAU,GAAG,gBAA6B;CAIjE,IAAI,CAHc,cAGJ,EACZ,OAAO,oBAAA,YAAA,EAAK,CAAA;CAGd,OAAO,oBAAC,cAAD;EAAc,GAAI;EAAY;EAAwB,CAAA"}