Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/eui/changelogs/upcoming/8851.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds a new `EuiFlyoutMenu` component that provides a standardized top menu bar for flyouts.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '../../global_styling';
import { UseEuiTheme } from '../../services';

import { FLYOUT_BREAKPOINT } from './flyout.styles';
import { FLYOUT_BREAKPOINT } from './flyout_shared.styles';

export const euiFlyoutCloseButtonStyles = (euiThemeContext: UseEuiTheme) => {
const euiTheme = euiThemeContext.euiTheme;
Expand Down
76 changes: 10 additions & 66 deletions packages/eui/src/components/flyout/flyout.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,10 @@
import { css, keyframes } from '@emotion/react';
import { euiShadowXLarge } from '@elastic/eui-theme-common';

import { _EuiFlyoutPaddingSize, EuiFlyoutSize } from './flyout';
import {
euiCanAnimate,
euiMaxBreakpoint,
euiMinBreakpoint,
logicalCSS,
mathWithUnits,
} from '../../global_styling';
import { _EuiFlyoutPaddingSize } from './flyout';
import { euiCanAnimate, logicalCSS, mathWithUnits } from '../../global_styling';
import { UseEuiTheme } from '../../services';
import { euiFormMaxWidth } from '../form/form.styles';

export const FLYOUT_BREAKPOINT = 'm' as const;
import { composeFlyoutSizing, maxedFlyoutWidth } from './flyout_shared.styles';

export const euiFlyoutSlideInRight = keyframes`
0% {
Expand Down Expand Up @@ -67,19 +59,20 @@ export const euiFlyoutStyles = (euiThemeContext: UseEuiTheme) => {
${maxedFlyoutWidth(euiThemeContext)}
`,

// Flyout sizes
// When a child flyout is stacked on top of the parent, the parent flyout size will match the child flyout size
/**
* Flyout sizes
*
* When a child flyout is stacked on top of the parent, the parent flyout size updates to fill the space required by the child.
* FIXME: make sure that effect does not cause a child flyout to "push" the page content. Child flyouts should always overlay.
*/
s: css`
${composeFlyoutSizing(euiThemeContext, 's')}

&.euiFlyout--hasChild--stacked.euiFlyout--hasChild--m {
${composeFlyoutSizing(euiThemeContext, 'm')}
}
`,
m: css`
${composeFlyoutSizing(euiThemeContext, 'm')}

&.euiFlyout--hasChild--stacked.euiFlyout--hasChild--s {
/* when a size "s" child flyout is stacked on top of a size "m" parent, the parent flyout size is lowered to match the child. */
${composeFlyoutSizing(euiThemeContext, 's')}
}
`,
Expand Down Expand Up @@ -175,55 +168,6 @@ export const euiFlyoutStyles = (euiThemeContext: UseEuiTheme) => {
};
};

export const maxedFlyoutWidth = (euiThemeContext: UseEuiTheme) => `
${euiMaxBreakpoint(euiThemeContext, FLYOUT_BREAKPOINT)} {
${logicalCSS('max-width', '90vw !important')}
}
`;

export const composeFlyoutSizing = (
euiThemeContext: UseEuiTheme,
size: EuiFlyoutSize
) => {
const euiTheme = euiThemeContext.euiTheme;
const formMaxWidth = euiFormMaxWidth(euiThemeContext);

// 1. Calculating the minimum width based on the screen takeover breakpoint
const flyoutSizes = {
s: {
min: `${Math.round(euiTheme.breakpoint.m * 0.5)}px`, // 1.
width: '25vw',
max: `${Math.round(euiTheme.breakpoint.s * 0.7)}px`,
},

m: {
// Calculated for forms plus padding
min: `${mathWithUnits(formMaxWidth, (x) => x + 24)}`,
width: '50vw',
max: `${euiTheme.breakpoint.m}px`,
},

l: {
min: `${Math.round(euiTheme.breakpoint.m * 0.9)}px`, // 1.
width: '75vw',
max: `${euiTheme.breakpoint.l}px`,
},
};

return `
${logicalCSS('max-width', flyoutSizes[size].max)}

${euiMaxBreakpoint(euiThemeContext, FLYOUT_BREAKPOINT)} {
${logicalCSS('min-width', 0)}
${logicalCSS('width', flyoutSizes[size].min)}
}
${euiMinBreakpoint(euiThemeContext, FLYOUT_BREAKPOINT)} {
${logicalCSS('min-width', flyoutSizes[size].min)}
${logicalCSS('width', flyoutSizes[size].width)}
}
`;
};

const composeFlyoutPadding = (
euiThemeContext: UseEuiTheme,
paddingSize: _EuiFlyoutPaddingSize
Expand Down
15 changes: 13 additions & 2 deletions packages/eui/src/components/flyout/flyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import { EuiScreenReaderOnly } from '../accessibility';
import { EuiFlyoutCloseButton } from './_flyout_close_button';
import { euiFlyoutStyles } from './flyout.styles';
import { EuiFlyoutChild } from './flyout_child';
import { EuiFlyoutMenuContext } from './flyout_menu_context';
import { EuiFlyoutMenu } from './flyout_menu';
import { EuiFlyoutChildProvider } from './flyout_child_manager';
import { usePropsWithComponentDefaults } from '../provider/component_defaults';

Expand Down Expand Up @@ -242,6 +244,13 @@ export const EuiFlyout = forwardRef(
const hasChildFlyout = !!childFlyoutElement;

// Validate props, determine close button position and set child flyout classes
const hasFlyoutMenu = React.Children.toArray(children).some(
(child) =>
React.isValidElement(child) &&
(child.type === EuiFlyoutMenu ||
(child.type as any).displayName === 'EuiFlyoutMenu')
);

let closeButtonPosition: 'inside' | 'outside';
let childFlyoutClasses: string[] = [];
if (hasChildFlyout) {
Expand Down Expand Up @@ -492,7 +501,7 @@ export const EuiFlyout = forwardRef(
[onClose, hasOverlayMask, outsideClickCloses]
);

const closeButton = !hideCloseButton && (
const closeButton = !hideCloseButton && !hasFlyoutMenu && (
<EuiFlyoutCloseButton
{...closeButtonProps}
onClose={onClose}
Expand Down Expand Up @@ -547,7 +556,9 @@ export const EuiFlyout = forwardRef(
>
{!isPushed && screenReaderDescription}
{closeButton}
{contentToRender}
<EuiFlyoutMenuContext.Provider value={{ onClose }}>
{contentToRender}
</EuiFlyoutMenuContext.Provider>
</Element>
</EuiFocusTrap>
</EuiFlyoutWrapper>
Expand Down
Loading