[Chrome Workspace] Push flyout breakpoint relative to main container (#216137)

## Summary

This fixes push flyout to switch to overlay relative to main container
instead of body



https://github.com/user-attachments/assets/c07f1a8b-5eed-4aee-aa4c-a392f9b1eb04

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Anton Dosov 2025-03-28 17:13:46 +01:00 committed by GitHub
parent 2f71971983
commit cf7930d438
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 120 additions and 9 deletions

View file

@ -10,7 +10,7 @@
/* eslint-disable max-classes-per-file */
import { css } from '@emotion/react';
import { EuiFlyout, EuiFlyoutResizable } from '@elastic/eui';
import { WorkspaceFlyout, WorkspaceFlyoutResizable } from '@kbn/core-workspace-components';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Subject } from 'rxjs';
@ -115,18 +115,18 @@ export class FlyoutService {
const getWrapper = (children: JSX.Element) => {
return isResizable ? (
<EuiFlyoutResizable
<WorkspaceFlyoutResizable
{...restOptions}
onClose={onCloseFlyout}
ref={React.createRef()}
maxWidth={Number(options?.maxWidth)}
>
{children}
</EuiFlyoutResizable>
</WorkspaceFlyoutResizable>
) : (
<EuiFlyout {...restOptions} onClose={onCloseFlyout}>
<WorkspaceFlyout {...restOptions} onClose={onCloseFlyout}>
{children}
</EuiFlyout>
</WorkspaceFlyout>
);
};

View file

@ -30,7 +30,8 @@
"@kbn/core-analytics-browser-mocks",
"@kbn/core-analytics-browser",
"@kbn/core-user-profile-browser-mocks",
"@kbn/core-user-profile-browser"
"@kbn/core-user-profile-browser",
"@kbn/core-workspace-components"
],
"exclude": [
"target/**/*"

View file

@ -0,0 +1,102 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { forwardRef, useEffect, useLayoutEffect, useState } from 'react';
import {
EuiFlyoutResizable,
EuiFlyoutResizableProps,
useEuiTheme,
EuiFlyoutProps,
EuiFlyout,
} from '@elastic/eui';
export type WorkspaceFlyoutResizableProps = EuiFlyoutResizableProps;
/**
* A wrapper around EuiFlyoutResizable that controls pushMinBreakpoint relative to main workspace container width
*/
export const WorkspaceFlyoutResizable = forwardRef<HTMLDivElement, WorkspaceFlyoutResizableProps>(
(props, ref) => {
const theme = useEuiTheme();
const mainContainerWidth = useMainContainerWidth();
if (mainContainerWidth) {
const { type, pushMinBreakpoint, ...rest } = props;
const pushMinBreakpointWidth = theme.euiTheme.breakpoint[pushMinBreakpoint ?? 'xl'];
const typeRelativeToMainContainer =
mainContainerWidth > pushMinBreakpointWidth ? type : 'overlay';
return (
<EuiFlyoutResizable
ref={ref}
{...rest}
type={typeRelativeToMainContainer}
pushMinBreakpoint={'xs' /* take control of the breakpoint with finalType */}
/>
);
} else {
return <EuiFlyoutResizable ref={ref} {...props} />;
}
}
);
export type WorkspaceFlyoutProps = EuiFlyoutProps;
/**
* A wrapper around EuiFlyout that controls pushMinBreakpoint relative to main workspace container width
*/
export const WorkspaceFlyout = forwardRef<HTMLDivElement, WorkspaceFlyoutProps>((props, ref) => {
const theme = useEuiTheme();
const mainContainerWidth = useMainContainerWidth();
if (mainContainerWidth) {
const { type, pushMinBreakpoint, ...rest } = props;
const pushMinBreakpointWidth = theme.euiTheme.breakpoint[pushMinBreakpoint ?? 'xl'];
const typeRelativeToMainContainer =
mainContainerWidth > pushMinBreakpointWidth ? type : 'overlay';
return (
<EuiFlyout
ref={ref}
{...rest}
type={typeRelativeToMainContainer}
pushMinBreakpoint={'xs' /* take control of the breakpoint with finalType */}
/>
);
} else {
return <EuiFlyout ref={ref} {...props} />;
}
});
const mainContainerSelector = 'main';
const useMainContainerWidth = () => {
const [width, setWidth] = useState<number | null>(null);
useLayoutEffect(() => {
const mainContainer = document.querySelector(mainContainerSelector);
if (!mainContainer) return;
setWidth(mainContainer.clientWidth);
}, []);
useEffect(() => {
const mainContainer = document.querySelector(mainContainerSelector);
if (!mainContainer) return;
const observer = new ResizeObserver(() => {
setWidth(mainContainer.clientWidth);
});
observer.observe(mainContainer);
return () => {
observer.disconnect();
};
}, []);
return width;
};

View file

@ -11,3 +11,9 @@ export { Workspace, type WorkspaceProps } from './workspace';
export { KibanaWorkspace, type KibanaWorkspaceProps } from './kibana';
export type { WorkspaceToolProps, WorkspaceToolboxButtonProps } from './toolbox';
export { RecentlyAccessedTool, type RecentlyAccessedToolProps, FeedbackTool } from './tools';
export {
type WorkspaceFlyoutResizableProps,
WorkspaceFlyoutResizable,
type WorkspaceFlyoutProps,
WorkspaceFlyout,
} from './flyouts/flyouts';

View file

@ -28,6 +28,7 @@ import {
useIsWithinMinBreakpoint,
EuiFlyoutProps,
} from '@elastic/eui';
import { WorkspaceFlyoutResizable } from '@kbn/core-workspace-components';
import type { DataTableRecord, DataTableColumnsMeta } from '@kbn/discover-utils/types';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import type { ToastsStart } from '@kbn/core-notifications-browser';
@ -241,7 +242,7 @@ export function UnifiedDocViewerFlyout({
return (
<EuiPortal>
<EuiFlyoutResizable
<WorkspaceFlyoutResizable
className="DiscoverFlyout" // used to override the z-index of the flyout from SecuritySolution
onClose={onClose}
type={flyoutType ?? 'push'}
@ -314,7 +315,7 @@ export function UnifiedDocViewerFlyout({
})}
</EuiButtonEmpty>
</EuiFlyoutFooter>
</EuiFlyoutResizable>
</WorkspaceFlyoutResizable>
</EuiPortal>
);
}

View file

@ -40,7 +40,8 @@
"@kbn/apm-types",
"@kbn/event-stacktrace",
"@kbn/elastic-agent-utils",
"@kbn/data-view-utils"
"@kbn/data-view-utils",
"@kbn/core-workspace-components"
],
"exclude": ["target/**/*"]
}