Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ exports[`EuiDataGrid rendering renders additional toolbar controls 1`] = `
A
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -684,7 +684,7 @@ exports[`EuiDataGrid rendering renders additional toolbar controls 1`] = `
B
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -1099,7 +1099,7 @@ exports[`EuiDataGrid rendering renders control columns 1`] = `
A
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -1151,7 +1151,7 @@ exports[`EuiDataGrid rendering renders control columns 1`] = `
B
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -1719,7 +1719,7 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
Column A
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -1772,7 +1772,7 @@ exports[`EuiDataGrid rendering renders custom column headers 1`] = `
</div>
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -2162,7 +2162,7 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
A
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -2214,7 +2214,7 @@ exports[`EuiDataGrid rendering renders with common and div attributes 1`] = `
B
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exports[`EuiDataGridBodyCustomRender treats \`renderCustomGridBody\` as a render
columnA
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -86,7 +86,7 @@ exports[`EuiDataGridBodyCustomRender treats \`renderCustomGridBody\` as a render
columnB
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ exports[`EuiDataGridBodyVirtualized renders 1`] = `
columnA
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down Expand Up @@ -90,7 +90,7 @@ exports[`EuiDataGridBodyVirtualized renders 1`] = `
columnB
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`ColumnActions renders 1`] = `
<body>
<div>
<div
class="euiPopover euiPopover-isOpen emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiPopover-isOpen euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-controls="euiPopover_generated-id_panelId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`EuiDataGridHeaderCell renders 1`] = `
someColumn
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe('ColumnActions', () => {
hasFocusTrap: false,
setPropsFromColumnActions: jest.fn(),
actionsButtonRef: jest.fn(),
showColumnActionsAlways: false,
};

it('renders', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const ColumnActions: FunctionComponent<
hasFocusTrap: boolean;
setPropsFromColumnActions: (props: PropsFromColumnActions) => void;
actionsButtonRef: Ref<HTMLButtonElement>;
showColumnActionsAlways: boolean;
}
> = memo(
({
Expand All @@ -101,6 +102,7 @@ export const ColumnActions: FunctionComponent<
hasFocusTrap,
setPropsFromColumnActions,
actionsButtonRef,
showColumnActionsAlways,
}) => {
/**
* Popover logic and accessibility
Expand Down Expand Up @@ -194,6 +196,7 @@ export const ColumnActions: FunctionComponent<
panelPaddingSize="none"
offset={7}
anchorPosition="downRight"
className="euiDataGridHeaderCell__columnActionsPopover"
css={styles.euiDataGridHeaderCell__popover}
button={
<EuiButtonIcon
Expand All @@ -211,6 +214,8 @@ export const ColumnActions: FunctionComponent<
css={[
styles.euiDataGridHeaderCell__actions.action,
styles.euiDataGridHeaderCell__actions.end,
showColumnActionsAlways &&
styles.euiDataGridHeaderCell__actionAlwaysVisible,
]}
data-test-subj={`dataGridHeaderCellActionButton-${id}`}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ export const euiDataGridHeaderCellStyles = (euiThemeContext: UseEuiTheme) => {
/* Remove inline struts from EuiButtonIcon */
line-height: 0;
`,
/** Undo hide-on-hover affordance when headerColumnActionsVisibility is `always` */
euiDataGridHeaderCell__actionAlwaysVisible: css`
opacity: 1 !important; /* stylelint-disable-line declaration-no-important */
transform: none !important; /* stylelint-disable-line declaration-no-important */
${logicalCSS(
'margin-left',
'0 !important'
)}/* stylelint-disable-line declaration-no-important */
`,
euiDataGridHeaderCell__actions: {
action: css`
overflow: hidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,36 @@ describe('EuiDataGridHeaderCell', () => {
expect(container.querySelector('.euiPopover')).not.toBeInTheDocument();
});

it('applies stable header layout classes for headerColumnActionsVisibility', () => {
const { getByTestSubject } = render(
<EuiDataGridHeaderCell
{...requiredProps}
gridStyles={{
header: 'shade',
headerColumnActionsVisibility: 'always',
}}
/>
);
expect(getByTestSubject('dataGridHeaderCell-someColumn')).toHaveClass(
'euiDataGridHeaderCell--columnActionsAlwaysVisible'
);
});

it('applies overlay class for headerColumnActionsDisplay', () => {
const { getByTestSubject } = render(
<EuiDataGridHeaderCell
{...requiredProps}
gridStyles={{
header: 'shade',
headerColumnActionsDisplay: 'overlay',
}}
/>
);
expect(getByTestSubject('dataGridHeaderCell-someColumn')).toHaveClass(
'euiDataGridHeaderCell--columnActionsOverlay'
);
});

describe('resizing', () => {
it('renders a resizer', () => {
const { getByTestSubject } = render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ export const EuiDataGridHeaderCell: FunctionComponent<EuiDataGridHeaderCellProps
{
[`euiDataGridHeaderCell--${columnType}`]: columnType,
'euiDataGridHeaderCell--hasColumnActions': hasColumnActions,
'euiDataGridHeaderCell--columnActionsAlwaysVisible':
hasColumnActions &&
gridStyles.headerColumnActionsVisibility === 'always',
'euiDataGridHeaderCell--columnActionsOverlay':
hasColumnActions &&
gridStyles.headerColumnActionsDisplay === 'overlay',
},
displayHeaderCellProps?.className
);
Expand Down Expand Up @@ -137,6 +143,9 @@ export const EuiDataGridHeaderCell: FunctionComponent<EuiDataGridHeaderCellProps
css={[
styles.euiDataGridHeaderCell__actions.action,
styles.euiDataGridHeaderCell__actions.start,
gridStyles.headerColumnActionsVisibility === 'always'
? styles.euiDataGridHeaderCell__actionAlwaysVisible
: undefined,
]}
/>
</span>
Expand Down Expand Up @@ -176,6 +185,9 @@ export const EuiDataGridHeaderCell: FunctionComponent<EuiDataGridHeaderCellProps
hasFocusTrap={hasFocusTrap}
setPropsFromColumnActions={setPropsFromColumnActions}
actionsButtonRef={actionsButtonRef}
showColumnActionsAlways={
gridStyles.headerColumnActionsVisibility === 'always'
}
/>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,36 @@ export const euiDataGridHeaderCellWrapperStyles = (
}
}

/* Match showActions gap when column actions stay visible (stable header height) */
&.euiDataGridHeaderCell--columnActionsAlwaysVisible {
&,
& > [data-focus-lock-disabled] {
gap: ${euiTheme.size.xxs};
}
}

/*
* When actions are overlaid they are not flex items; keep a steady gap between
* remaining flex items so hover/focus does not toggle layout.
*/
&.euiDataGridHeaderCell--columnActionsOverlay {
&,
& > [data-focus-lock-disabled] {
gap: ${euiTheme.size.xxs};
}

.euiDataGridHeaderCell__columnActionsPopover {
position: absolute;
${logicalCSS('top', 0)}
${logicalCSS('bottom', 0)}
${logicalCSS('right', 0)}
display: flex;
align-items: center;
${logicalCSS('margin-left', 0)}
z-index: ${Number(euiTheme.levels.header) + 1};
}
}

/* Workaround for focus trap */
& > [data-focus-lock-disabled] {
display: flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('EuiDataGridHeaderRow', () => {
someColumn
</div>
<div
class="euiPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
class="euiPopover euiDataGridHeaderCell__columnActionsPopover emotion-euiPopover-block-euiDataGridHeaderCell__popover"
>
<button
aria-expanded="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ describe('useDataGridDisplaySelector', () => {
"fontSize": "m",
"footer": "overline",
"header": "shade",
"headerColumnActionsDisplay": "inline",
"headerColumnActionsVisibility": "hover",
"rowHover": "highlight",
"stickyFooter": true,
"stripes": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export const startingStyles: EuiDataGridStyle = {
header: 'shade',
footer: 'overline',
stickyFooter: true,
headerColumnActionsVisibility: 'hover',
headerColumnActionsDisplay: 'inline',
};
const emptyRowHeightsOptions: EuiDataGridRowHeightsOptions = {};

Expand Down
24 changes: 24 additions & 0 deletions packages/eui/src/components/datagrid/data_grid_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,19 @@ export type EuiDataGridStyleFooter = 'shade' | 'overline' | 'striped';
export type EuiDataGridStyleRowHover = 'highlight' | 'none';
export type EuiDataGridStyleCellPaddings = 's' | 'm' | 'l';

/**
* When `always`, the column header actions (⋮) control stays visible instead of
* appearing only on row hover or focus, which keeps header height stable when
* header labels wrap to multiple lines.
*/
export type EuiDataGridStyleHeaderColumnActionsVisibility = 'hover' | 'always';

/**
* When `overlay`, the column header actions control is absolutely positioned over
* the header cell so toggling its visibility does not change flex layout or header height.
*/
export type EuiDataGridStyleHeaderColumnActionsDisplay = 'inline' | 'overlay';

export interface EuiDataGridStyle {
/**
* Size of fonts used within the row and column cells
Expand Down Expand Up @@ -924,6 +937,17 @@ export interface EuiDataGridStyle {
* @default hover
*/
rowHover?: EuiDataGridStyleRowHover;
/**
* Controls visibility of the per-column header actions menu (⋮).
* @default hover
*/
headerColumnActionsVisibility?: EuiDataGridStyleHeaderColumnActionsVisibility;
/**
* Whether the column header actions control participates in flex layout (`inline`)
* or is layered on top of the header cell content (`overlay`), avoiding layout shift on hover.
* @default inline
*/
headerColumnActionsDisplay?: EuiDataGridStyleHeaderColumnActionsDisplay;
/**
* Optionally pass custom classes to highlight or customize certain rows
*/
Expand Down
Loading