{"version":3,"file":"Portal.mjs","sources":["../../../../src/components/Portal/Portal.tsx"],"sourcesContent":["import { css } from '@emotion/css';\nimport { createContext, type PropsWithChildren, useContext, useRef } from 'react';\nimport ReactDOM from 'react-dom';\n\nimport { type GrafanaTheme2 } from '@grafana/data';\nimport { selectors } from '@grafana/e2e-selectors';\n\nimport { useStyles2, useTheme2 } from '../../themes/ThemeContext';\n\n// Tracks whether we're in a nested Portal.\n// A nested portal will render inside it's parent portal instead of the default portal container.\n// This prevents nested portals from being rendered in reverse order due to React's bottom-up commit phase.\nconst PortalContext = createContext<HTMLDivElement | null>(null);\n\ninterface Props {\n  className?: string;\n  root?: HTMLElement;\n  // the zIndex of the node; defaults to theme.zIndex.portal\n  zIndex?: number;\n}\n\nexport function Portal(props: PropsWithChildren<Props>) {\n  const { children, className, root, zIndex } = props;\n  const theme = useTheme2();\n  const parentPortal = useContext(PortalContext);\n  const portalRef = useRef<HTMLDivElement | null>(null);\n\n  const portalRoot = root ?? parentPortal ?? getPortalContainer();\n\n  return ReactDOM.createPortal(\n    <PortalContext.Provider value={portalRef.current}>\n      <div\n        className={className}\n        ref={portalRef}\n        style={{ position: 'relative', zIndex: zIndex ?? theme.zIndex.portal }}\n      >\n        {children}\n      </div>\n    </PortalContext.Provider>,\n    portalRoot\n  );\n}\n\n/**\n * Returns the container element Grafana renders overlays into (tooltips, menus, modals).\n * Content rendered into this container coexists with an open Modal: it is treated as\n * inside the modal for focus management and pressing it does not dismiss the modal.\n */\nexport function getPortalContainer() {\n  return window.document.getElementById('grafana-portal-container') ?? document.body;\n}\n\n/** @internal */\nexport function PortalContainer() {\n  const styles = useStyles2(getStyles);\n  return (\n    <div\n      id=\"grafana-portal-container\"\n      data-testid={selectors.components.Portal.container}\n      className={styles.grafanaPortalContainer}\n    />\n  );\n}\n\nconst getStyles = (theme: GrafanaTheme2) => {\n  return {\n    grafanaPortalContainer: css({\n      position: 'fixed',\n      top: 0,\n      width: '100%',\n      zIndex: theme.zIndex.portal,\n    }),\n  };\n};\n"],"names":[],"mappings":";;;;;;;;AAYA,MAAM,aAAA,GAAgB,cAAqC,IAAI,CAAA;AASxD,SAAS,OAAO,KAAA,EAAiC;AArBxD,EAAA,IAAA,EAAA;AAsBE,EAAA,MAAM,EAAE,QAAA,EAAU,SAAA,EAAW,IAAA,EAAM,QAAO,GAAI,KAAA;AAC9C,EAAA,MAAM,QAAQ,SAAA,EAAU;AACxB,EAAA,MAAM,YAAA,GAAe,WAAW,aAAa,CAAA;AAC7C,EAAA,MAAM,SAAA,GAAY,OAA8B,IAAI,CAAA;AAEpD,EAAA,MAAM,UAAA,GAAA,CAAa,EAAA,GAAA,IAAA,IAAA,IAAA,GAAA,IAAA,GAAQ,YAAA,KAAR,IAAA,GAAA,EAAA,GAAwB,kBAAA,EAAmB;AAE9D,EAAA,OAAO,QAAA,CAAS,YAAA;AAAA,wBACb,aAAA,CAAc,QAAA,EAAd,EAAuB,KAAA,EAAO,UAAU,OAAA,EACvC,QAAA,kBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA;AAAA,QACA,GAAA,EAAK,SAAA;AAAA,QACL,KAAA,EAAO,EAAE,QAAA,EAAU,UAAA,EAAY,QAAQ,MAAA,IAAA,IAAA,GAAA,MAAA,GAAU,KAAA,CAAM,OAAO,MAAA,EAAO;AAAA,QAEpE;AAAA;AAAA,KACH,EACF,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAOO,SAAS,kBAAA,GAAqB;AAhDrC,EAAA,IAAA,EAAA;AAiDE,EAAA,OAAA,CAAO,YAAO,QAAA,CAAS,cAAA,CAAe,0BAA0B,CAAA,KAAzD,YAA8D,QAAA,CAAS,IAAA;AAChF;AAGO,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,MAAA,GAAS,WAAW,SAAS,CAAA;AACnC,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAG,0BAAA;AAAA,MACH,aAAA,EAAa,SAAA,CAAU,UAAA,CAAW,MAAA,CAAO,SAAA;AAAA,MACzC,WAAW,MAAA,CAAO;AAAA;AAAA,GACpB;AAEJ;AAEA,MAAM,SAAA,GAAY,CAAC,KAAA,KAAyB;AAC1C,EAAA,OAAO;AAAA,IACL,wBAAwB,GAAA,CAAI;AAAA,MAC1B,QAAA,EAAU,OAAA;AAAA,MACV,GAAA,EAAK,CAAA;AAAA,MACL,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ,MAAM,MAAA,CAAO;AAAA,KACtB;AAAA,GACH;AACF,CAAA;;;;"}