UNPKG

@modern-kit/react

Version:
1 lines 4.15 kB
{"version":3,"file":"index.cjs","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>;\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"],"names":["createContext","useContext","useCallback","mountElement","portalElement","useMemo","useIsomorphicLayoutEffect","createPortal","jsx","useIsMounted","Fragment"],"mappings":";;;;;;;;;AAWA,MAAM,gBAAgBA,mBAAA,CAEnB;AAAA,EACD,mBAAA,EAAqB;AACvB,CAAC,CAAA;AAED,MAAM,oBAAA,GAAuB,QAAA;AAE7B,SAAS,YAAA,CAAa;AAAA,EACpB,QAAA;AAAA,EACA,SAAA,GAAY,oBAAA;AAAA,EACZ;AACF,CAAA,EAAgB;AACd,EAAA,MAAM,EAAE,mBAAA,EAAoB,GAAIC,gBAAA,CAAW,aAAa,CAAA;AAExD,EAAA,MAAM,mBAAA,GAAsBC,iBAAA;AAAA,IAC1B,CAACC,aAAAA,KAA8B;AAC7B,MAAA,MAAMC,cAAAA,GAAgBD,aAAAA,CAAa,aAAA,CAAc,aAAA,CAAc,KAAK,CAAA;AACpE,MAAAC,cAAAA,CAAc,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA;AAErC,MAAA,OAAOA,cAAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,SAAS;AAAA,GACZ;AAOA,EAAA,MAAM,YAAA,GAAeC,cAAQ,MAAM;AACjC,IAAA,OAAO,mBAAA,IAAuB,YAAA,EAAc,OAAA,IAAW,QAAA,CAAS,IAAA;AAAA,EAClE,CAAA,EAAG,CAAC,mBAAA,EAAqB,YAAY,CAAC,CAAA;AAEtC,EAAA,MAAM,aAAA,GAAgBA,cAAQ,MAAM;AAClC,IAAA,OAAO,oBAAoB,YAAY,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,mBAAA,EAAqB,YAAY,CAAC,CAAA;AAEtC,EAAAC,wDAAA,CAA0B,MAAM;AAC9B,IAAA,YAAA,CAAa,YAAY,aAAa,CAAA;AAGtC,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,YAAA,CAAa,QAAA,CAAS,aAAa,CAAA,EAAG;AACxC,QAAA,YAAA,CAAa,YAAY,aAAa,CAAA;AAAA,MACxC;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,aAAA,EAAe,YAAY,CAAC,CAAA;AAEhC,EAAA,OAAOC,qBAAA;AAAA,oBACLC,cAAA,CAAC,cAAc,QAAA,EAAd,EAAuB,OAAO,EAAE,mBAAA,EAAqB,aAAA,EAAc,EACjE,QAAA,EACH,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,MAAM,SAAS,CAAC,EAAE,QAAA,EAAU,GAAG,WAAU,KAAmB;AACjE,EAAA,MAAM,YAAYC,8BAAA,EAAa;AAG/B,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,uBAAOD,cAAA,CAAAE,mBAAA,EAAA,EAAE,CAAA;AAAA,EACX;AAEA,EAAA,uBAAOF,cAAA,CAAC,YAAA,EAAA,EAAc,GAAG,SAAA,EAAY,QAAA,EAAS,CAAA;AAChD;;;;"}