Skip to content
Merged
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
37 changes: 36 additions & 1 deletion packages/eui-theme-common/src/global_styling/mixins/borders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ export type BorderSides =
| 'vertical'
| 'all';

/**
* Defines styles for floating boarders applied in DARK mode via EUI shadow utils
*/
export const euiShadowFloatingBorderStyles = (
euiThemeContext: UseEuiTheme,
options: {
side?: BorderSides;
borderColor?: string;
borderWidth?: string;
borderStyle?: string;
}
) => {
return `
/* create a containing block without using \`position\` to prevent CSS specificity issues and unexpected overrides;
\`transform: translateZ(0)\` is the least likely to affect other behaviors (overflow, layout) */
transform: translateZ(0);

${euiBorderStyles(euiThemeContext, options)}
`;
};

/**
* Shared style for floating borders.
* Uses a pseudo element with `border` attribute to prevent both dimension changes due to
* the border width as well as visible gaps due to the need of a transparent border in LIGHT mode.
*/
export const euiBorderStyles = (
euiThemeContext: UseEuiTheme,
options: {
Expand All @@ -48,6 +74,15 @@ export const euiBorderStyles = (
const borderProperty = getBorderSide(side);

return `
${borderProperty}: ${borderWidth} ${borderStyle} ${borderColor};
&::after {
content: '';
position: absolute;
inset: 0;
/* ensure to keep on top of flush content */
z-index: 0;
${borderProperty}: ${borderWidth} ${borderStyle} ${borderColor};
border-radius: inherit;
pointer-events: none;
}
`;
};
4 changes: 2 additions & 2 deletions packages/eui-theme-common/src/global_styling/mixins/shadow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
_EuiThemeShadowHoverSize,
_EuiThemeShadowSize,
} from '../variables/shadow';
import { BorderSides, euiBorderStyles } from './borders';
import { BorderSides, euiShadowFloatingBorderStyles } from './borders';

export interface EuiShadowOptions {
/** @deprecated */
Expand Down Expand Up @@ -290,7 +290,7 @@ const _shadowStyles = (
const { border = 'all', type = 'box-shadow' } = options;
const borderStyle =
euiThemeContext.colorMode === 'DARK' && border !== 'none'
? `${euiBorderStyles(euiThemeContext, {
? `${euiShadowFloatingBorderStyles(euiThemeContext, {
side: border ?? 'all',
})}`
: '';
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const euiBottomBarStyles = (euiThemeContext: UseEuiTheme) => {
background-color: ${euiTheme.components.bottomBarBackground};
${logicalCSS('border-top', euiTheme.border.thin)}
${highContrastModeStyles(euiThemeContext, {
none: euiShadowFlat(euiThemeContext, { border: 'top' }),
none: euiShadowFlat(euiThemeContext, { border: 'none' }),
})}
/* prevent shadow from overlapping content in compositions */
clip-path: polygon(0 -100vh, 100% -100vh, 100% 100%, 0 100%);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,16 +203,17 @@ export const InScrollablePopover: Story = {
}}
panelPaddingSize="none"
anchorPosition="downLeft"
panelProps={{
css: css`
>
<div
css={css`
${logicalCSS('max-height', '250px')}
${useEuiScrollBar()};
${/* eslint-disable-next-line local/css-logical-properties */ ''}
overflow-y: auto;
`,
}}
>
<EuiContextMenu {...args} />
`}
>
<EuiContextMenu {...args} />
</div>
</EuiPopover>
);
},
Expand Down
5 changes: 3 additions & 2 deletions packages/eui/src/components/header/header.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ export const euiHeaderStyles = (euiThemeContext: UseEuiTheme) => {
${logicalCSS('border-bottom', euiTheme.border.thin)}
${euiShadowXSmall(euiThemeContext, {
border: 'none',
})};
})}

& + & {
/* uses the global class as & might not reference the same due to dynamic classes */
& + .euiHeader {
clip-path: polygon(0 0, 100% 0, 100% 100vh, 0 100vh);
}
`,
Expand Down
33 changes: 32 additions & 1 deletion packages/eui/src/components/panel/panel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@ import {
disableStorybookControls,
enableFunctionToggleControls,
} from '../../../.storybook/utils';
import { highContrastModeStyles, logicalCSS } from '../../global_styling';
import {
euiShadow,
highContrastModeStyles,
logicalCSS,
} from '../../global_styling';
import { useEuiTheme } from '../../services';
import { EuiPanel, EuiPanelProps } from './panel';
import { EuiSpacer } from '../spacer';
import { EuiSplitPanel } from './split_panel';

const meta: Meta<EuiPanelProps> = {
title: 'Layout/EuiPanel',
Expand Down Expand Up @@ -89,6 +95,9 @@ export const Kitchensink: Story = {
children: 'Panel content',
},
render: function Render(args: EuiPanelProps) {
const euiThemeContext = useEuiTheme();
const { euiTheme } = euiThemeContext;

return (
<>
<EuiPanel {...args} hasBorder onClick={undefined} />
Expand Down Expand Up @@ -128,6 +137,28 @@ export const Kitchensink: Story = {
Footer
</EuiPanel>
</EuiPanel>

<EuiSpacer size="m" />

<EuiSplitPanel.Outer>
<EuiSplitPanel.Inner>Top or left panel</EuiSplitPanel.Inner>
<EuiSplitPanel.Inner color="subdued">
Bottom or right panel
</EuiSplitPanel.Inner>
</EuiSplitPanel.Outer>

<EuiSpacer size="m" />

<div
css={css`
padding: ${euiTheme.size.base};
background-color: ${euiTheme.colors.backgroundBasePlain};
border-radius: ${euiTheme.border.radius.small};
${euiShadow(euiThemeContext)};
`}
>
Custom panel
</div>
</>
);
},
Expand Down
29 changes: 17 additions & 12 deletions packages/eui/src/components/panel/panel.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
*/

import { css } from '@emotion/react';
import { euiShadow, euiShadowHover } from '@elastic/eui-theme-common';
import {
euiBorderStyles,
euiShadow,
euiShadowHover,
} from '@elastic/eui-theme-common';

import { UseEuiTheme } from '../../services';
import {
Expand All @@ -33,13 +37,15 @@ export const euiPanelBorderStyles = (

return highContrastModeStyles(euiThemeContext, {
none: `
border: ${
borderColor ?? hasVisibleBorder
? `${euiTheme.border.width.thin} solid ${euiTheme.border.color}`
: colorMode === 'DARK'
? `${euiTheme.border.width.thin} solid ${euiTheme.colors.borderBaseFloating}`
: 'none'
};
/* Using a pseudo element for the border instead of floating border only
because the transparent border might otherwise be visible with arbitrary
full-width/height content in light mode. */
${euiBorderStyles(euiThemeContext, {
borderColor:
borderColor ?? hasVisibleBorder
? euiTheme.border.color
: euiTheme.colors.borderBaseFloating,
})}
`,
preferred: `
border: ${euiTheme.border.thin};
Expand All @@ -63,16 +69,15 @@ export const euiPanelStyles = (euiThemeContext: UseEuiTheme) => {

hasShadow: css`
${euiShadow(euiThemeContext, 'm')}
`,

hasBorder: css`
${euiPanelBorderStyles(euiThemeContext, {
borderColor: euiTheme.border.color,
hasFloatingBorder: false,
})}
`,

hasBorder: css`
border: ${euiTheme.border.thin};
`,

radius: {
none: css``,
m: css`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ this might result in duplicate neighboring borders. To adjust this, use the `bor
import { euiShadow } from '@elastic/eui';

const styles = css`
${euiShadow('s', { border: 'none'})}
${euiShadow('s', { border: 'all'})}
${euiShadow('s', { border: 'top'})}
${euiShadow('s', { border: 'bottom'})}
${euiShadow('s', { border: 'left'})}
${euiShadow('s', { border: 'right'})}
${euiShadow('s', { border: 'horizontal'})}
${euiShadow('s', { border: 'vertical'})}
${euiShadow(euiThemeContext, 's', { border: 'none'})}
${euiShadow(euiThemeContext, 's', { border: 'all'})}
${euiShadow(euiThemeContext, 's', { border: 'top'})}
${euiShadow(euiThemeContext, 's', { border: 'bottom'})}
${euiShadow(euiThemeContext, 's', { border: 'left'})}
${euiShadow(euiThemeContext, 's', { border: 'right'})}
${euiShadow(euiThemeContext, 's', { border: 'horizontal'})}
${euiShadow(euiThemeContext, 's', { border: 'vertical'})}
`;
```
</Example.Snippet>
Expand Down Expand Up @@ -123,6 +123,130 @@ export default () => {
}
```

## Scroll behavior

:::warning Do not combine shadow utils and scroll behavior styles on the same element
:::

Combining EUI shadow utils like `euiShadow()` and scroll behavior (e.g. via `overflow: scroll` or `overflow: auto`) on the same element will cause the floating border
in DARK mode to be scrolled. If you want to combine both, separate the styles onto different elements by placing the shadow util on the outer wrapper and the scroll
behavior on the inner one.

<Example.Snippet>
```ts
import { euiShadow } from '@elastic/eui';
import { css } from '@emotion/react';

const Component = () => {
const euiThemeContext = useEuiTheme();

const shadowStyles = css`
${euiShadow(euiThemeContext, 's')};
`;
const scrollContainerStyles = css`
max-height: 100px;
overflow-y: auto;
/* specific scroll bar styling */
${useEuiScrollBar()};
`;

return (
<div css={shadowStyles}>
<div css={scrollContainerStyles}>
// scrollable content
</div>
</div>
);
}
```
</Example.Snippet>

```tsx interactive
import React, { useState } from 'react';
import {
useEuiTheme,
EuiPopover,
EuiButton,
EuiContextMenu,
EuiPanel,
EuiThemeProvider,
logicalCSS,
useEuiScrollBar,
} from '@elastic/eui';
import { css } from '@emotion/react';

export default () => {
const [isPopoverOpen, setPopoverOpen] = useState(false);

const Example = () => {
return (
<EuiPanel hasShadow={false} css={css`
display: flex;
align-items: center;
justify-content: center;
block-size: 200px;
`}>
<EuiPopover
button={
<EuiButton onClick={() => setPopoverOpen(!isPopoverOpen)}>
Toggle context menu
</EuiButton>
}
isOpen={isPopoverOpen}
closePopover={() => {
setPopoverOpen(false);
}}
panelPaddingSize="none"
anchorPosition="rightCenter"
>
<div
css={css`
${logicalCSS('max-height', '100px')}
${useEuiScrollBar()};
overflow-y: auto;
`}
>
<EuiContextMenu
initialPanelId={0}
panels={[
{
id: 0,
title: 'This is a context menu',
items: [
{
name: 'Item 1',
icon: 'search',
},
{
name: 'Item 2',
icon: 'user',
},
{
name: 'Item 3',
icon: 'document',
},
{
name: 'Item 5',
icon: 'cheer',
}
],
},
]}
/>
</div>
</EuiPopover>
</EuiPanel>
)
}

return (
<EuiThemeProvider colorMode="dark" wrapperProps={{ cloneElement: true }}>
<Example />
</EuiThemeProvider>
);
};
```

## Hover states

Each shadowed surface, when interactive, follows the same hover effect rule: it moves up one level.
Expand Down