mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Performance: Create separate div for portal root to limit reflow -> recalc style (#47633)
* Performance: Create separate div for portal root to limit reflow -> recalc style * refactoring
This commit is contained in:
parent
a4381ebc91
commit
6042beab43
@ -9,9 +9,11 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Portal(props: PropsWithChildren<Props>) {
|
export function Portal(props: PropsWithChildren<Props>) {
|
||||||
const { children, className, root: portalRoot = document.body, forwardedRef } = props;
|
const { children, className, root, forwardedRef } = props;
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const node = useRef<HTMLDivElement | null>(null);
|
const node = useRef<HTMLDivElement | null>(null);
|
||||||
|
const portalRoot = root ?? getPortalContainer();
|
||||||
|
|
||||||
if (!node.current) {
|
if (!node.current) {
|
||||||
node.current = document.createElement('div');
|
node.current = document.createElement('div');
|
||||||
if (className) {
|
if (className) {
|
||||||
@ -25,6 +27,7 @@ export function Portal(props: PropsWithChildren<Props>) {
|
|||||||
if (node.current) {
|
if (node.current) {
|
||||||
portalRoot.appendChild(node.current);
|
portalRoot.appendChild(node.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (node.current) {
|
if (node.current) {
|
||||||
portalRoot.removeChild(node.current);
|
portalRoot.removeChild(node.current);
|
||||||
@ -35,7 +38,18 @@ export function Portal(props: PropsWithChildren<Props>) {
|
|||||||
return ReactDOM.createPortal(<div ref={forwardedRef}>{children}</div>, node.current);
|
return ReactDOM.createPortal(<div ref={forwardedRef}>{children}</div>, node.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function getPortalContainer() {
|
||||||
|
return window.document.getElementById('grafana-portal-container') ?? document.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
export function PortalContainer() {
|
||||||
|
return <div id="grafana-portal-container" />;
|
||||||
|
}
|
||||||
|
|
||||||
export const RefForwardingPortal = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
|
export const RefForwardingPortal = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
|
||||||
return <Portal {...props} forwardedRef={ref} />;
|
return <Portal {...props} forwardedRef={ref} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
RefForwardingPortal.displayName = 'RefForwardingPortal';
|
RefForwardingPortal.displayName = 'RefForwardingPortal';
|
||||||
|
@ -6,7 +6,7 @@ export { Tooltip } from './Tooltip/Tooltip';
|
|||||||
export { PopoverContent } from './Tooltip/types';
|
export { PopoverContent } from './Tooltip/types';
|
||||||
export { PopoverController } from './Tooltip/PopoverController';
|
export { PopoverController } from './Tooltip/PopoverController';
|
||||||
export { Popover } from './Tooltip/Popover';
|
export { Popover } from './Tooltip/Popover';
|
||||||
export { Portal } from './Portal/Portal';
|
export { Portal, getPortalContainer, PortalContainer } from './Portal/Portal';
|
||||||
export { CustomScrollbar, ScrollbarPosition } from './CustomScrollbar/CustomScrollbar';
|
export { CustomScrollbar, ScrollbarPosition } from './CustomScrollbar/CustomScrollbar';
|
||||||
export { TabbedContainer, TabConfig } from './TabbedContainer/TabbedContainer';
|
export { TabbedContainer, TabConfig } from './TabbedContainer/TabbedContainer';
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { Router, Route, Redirect, Switch } from 'react-router-dom';
|
|||||||
import { config, locationService, navigationLogger } from '@grafana/runtime';
|
import { config, locationService, navigationLogger } from '@grafana/runtime';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { store } from 'app/store/store';
|
import { store } from 'app/store/store';
|
||||||
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider } from '@grafana/ui';
|
import { ErrorBoundaryAlert, GlobalStyles, ModalRoot, ModalsProvider, PortalContainer } from '@grafana/ui';
|
||||||
import { GrafanaApp } from './app';
|
import { GrafanaApp } from './app';
|
||||||
import { getAppRoutes } from 'app/routes/routes';
|
import { getAppRoutes } from 'app/routes/routes';
|
||||||
import { ConfigContext, ThemeProvider } from './core/utils/ConfigProvider';
|
import { ConfigContext, ThemeProvider } from './core/utils/ConfigProvider';
|
||||||
@ -113,6 +113,7 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
|
|||||||
</div>
|
</div>
|
||||||
<LiveConnectionWarning />
|
<LiveConnectionWarning />
|
||||||
<ModalRoot />
|
<ModalRoot />
|
||||||
|
<PortalContainer />
|
||||||
</ModalsProvider>
|
</ModalsProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</ConfigContext.Provider>
|
</ConfigContext.Provider>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react';
|
import React, { ReactElement, useEffect, useState } from 'react';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { Icon, IconName, Link, useTheme2 } from '@grafana/ui';
|
import { getPortalContainer, Icon, IconName, Link, useTheme2 } from '@grafana/ui';
|
||||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||||
import { MenuTriggerProps } from '@react-types/menu';
|
import { MenuTriggerProps } from '@react-types/menu';
|
||||||
import { useMenuTriggerState } from '@react-stately/menu';
|
import { useMenuTriggerState } from '@react-stately/menu';
|
||||||
@ -182,7 +182,7 @@ export function NavBarItemMenuTrigger(props: NavBarItemMenuTriggerProps): ReactE
|
|||||||
<div className={cx(styles.element, 'dropdown')} {...focusWithinProps} {...hoverProps}>
|
<div className={cx(styles.element, 'dropdown')} {...focusWithinProps} {...hoverProps}>
|
||||||
{element}
|
{element}
|
||||||
{state.isOpen && (
|
{state.isOpen && (
|
||||||
<OverlayContainer>
|
<OverlayContainer portalContainer={getPortalContainer()}>
|
||||||
<NavBarItemMenuContext.Provider
|
<NavBarItemMenuContext.Provider
|
||||||
value={{
|
value={{
|
||||||
menuProps,
|
menuProps,
|
||||||
|
Loading…
Reference in New Issue
Block a user