UNPKG

@modern-kit/react

Version:
1 lines 4 kB
{"version":3,"file":"index.mjs","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":["mountElement","portalElement"],"mappings":";;;;;;;AAWA,MAAM,gBAAgB,aAAA,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,GAAI,UAAA,CAAW,aAAa,CAAA;AAExD,EAAA,MAAM,mBAAA,GAAsB,WAAA;AAAA,IAC1B,CAACA,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,GAAe,QAAQ,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,GAAgB,QAAQ,MAAM;AAClC,IAAA,OAAO,oBAAoB,YAAY,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,mBAAA,EAAqB,YAAY,CAAC,CAAA;AAEtC,EAAA,yBAAA,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,OAAO,YAAA;AAAA,oBACL,GAAA,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,YAAY,YAAA,EAAa;AAG/B,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAE,CAAA;AAAA,EACX;AAEA,EAAA,uBAAO,GAAA,CAAC,YAAA,EAAA,EAAc,GAAG,SAAA,EAAY,QAAA,EAAS,CAAA;AAChD;;;;"}