diff --git a/src-docs/src/views/datagrid/_snippets.tsx b/src-docs/src/views/datagrid/_snippets.tsx index 66f82019fcd..672e1417364 100644 --- a/src-docs/src/views/datagrid/_snippets.tsx +++ b/src-docs/src/views/datagrid/_snippets.tsx @@ -11,6 +11,7 @@ inMemory={{ level: 'sorting' }}`, id: 'A', // required display: <>Column A , // optional column header rendering displayAsText: 'Column A', // column header as plain text + displayHeaderCellProps: { className: 'eui-textCenter' }, // optional column header cell props initialWidth: 150, // starting width of 150px isResizable: false, // prevents the user from resizing width isExpandable: false, // doesn't allow clicking in to see the content in a popup @@ -33,16 +34,22 @@ inMemory={{ level: 'sorting' }}`, { id: 'selection', width: 31, - headerCellRender: () => Select a Row, + headerCellRender: () => Select a row, + headerCellProps: { className: 'eui-textCenter' }, rowCellRender: () =>
, + footerCellRender: () => Select a row, + footerCellProps: { className: 'eui-textCenter' }, }, ]}`, trailingControlColumns: `trailingControlColumns={[ { id: 'actions', width: 40, - headerCellRender: () => null, + headerCellRender: () => 'Actions', + headerCellProps: { className: 'euiScreenReaderOnly' }, rowCellRender: MyGridActionsComponent, + footerCellRender: () => null, + footerCellProps: { data-test-subj: 'emptyFooterCell' }, }, ]}`, renderCellValue: 'renderCellValue={({ rowIndex, columnId }) => {}}', diff --git a/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js b/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js index ef65697d7fe..6119176f991 100644 --- a/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js +++ b/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js @@ -293,8 +293,7 @@ schemaDetectors={[

The footer row is defined by passing{' '} renderFooterCellValue function prop into{' '} - EuiDataGrid.{' '} - renderFooterCellValue acts like a React + EuiDataGrid. This function acts like a React component, receiving{' '} EuiDataGridCellValueElementProps and returning a React node. @@ -304,6 +303,10 @@ schemaDetectors={[ expansion on cells without content with{' '} setCellProps({'{ isExpandable: false }'}).

+

+ Control columns will render empty footer cells by default, unless a + custom footerCellRender function is passed. +

), props: { diff --git a/src-docs/src/views/datagrid/schema_columns/footer_row.js b/src-docs/src/views/datagrid/schema_columns/footer_row.js index cda16af202b..8a92932cf71 100644 --- a/src-docs/src/views/datagrid/schema_columns/footer_row.js +++ b/src-docs/src/views/datagrid/schema_columns/footer_row.js @@ -3,6 +3,8 @@ import { faker } from '@faker-js/faker'; import { EuiDataGrid, + EuiCheckbox, + EuiButtonIcon, EuiSwitch, EuiFlexGroup, EuiFlexItem, @@ -14,7 +16,7 @@ for (let i = 1; i < 20; i++) { raw_data.push({ name: `${faker.name.lastName()}, ${faker.name.firstName()} ${faker.name.suffix()}`, date: `${faker.date.past()}`, - amount: faker.commerce.price(), + amount: `$${faker.commerce.price()}`, phone: faker.phone.number(), version: faker.system.semver(), }); @@ -65,6 +67,47 @@ const columns = [ }, ]; +const leadingControlColumns = [ + { + id: 'selection', + width: 32, + // Check state doesn't actually work - this is just a static example + headerCellRender: () => ( + {}} + /> + ), + rowCellRender: ({ rowIndex }) => ( + {}} + /> + ), + footerCellRender: () => ( + {}} + /> + ), + }, +]; +const trailingControlColumns = [ + { + id: 'actions', + width: 36, + headerCellRender: () => ( + Actions + ), + rowCellRender: () => ( + + ), + }, +]; + const footerCellValues = { amount: `Total: ${raw_data .reduce((acc, { amount }) => acc + Number(amount.split('$')[1]), 0) @@ -125,6 +168,8 @@ export default () => { aria-label="Data grid footer row demo" columns={columns} columnVisibility={{ visibleColumns, setVisibleColumns }} + leadingControlColumns={leadingControlColumns} + trailingControlColumns={trailingControlColumns} rowCount={raw_data.length} renderCellValue={RenderCellValue} renderFooterCellValue={ diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap index fe51a6c7c16..fa2037f092a 100644 --- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap +++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap @@ -1071,7 +1071,7 @@ Array [ role="row" >
= ( }); /** - * Header + * Header & footer */ - const [headerRowRef, setHeaderRowRef] = useState(null); - useMutationObserver(headerRowRef, handleHeaderMutation, { - subtree: true, - childList: true, - }); - const { height: headerRowHeight } = useResizeObserver(headerRowRef, 'height'); - - const headerRow = useMemo(() => { - return ( - - ); - }, [ + const { headerRow, headerRowHeight } = useDataGridHeader({ + headerIsInteractive, + handleHeaderMutation, switchColumnPos, setVisibleColumns, leadingControlColumns, @@ -321,47 +295,21 @@ export const EuiDataGridBody: FunctionComponent = ( setColumnWidth, schema, schemaDetectors, - headerIsInteractive, - ]); - - useHeaderFocusWorkaround(headerIsInteractive); + }); - /** - * Footer - */ - const [footerRowRef, setFooterRowRef] = useState(null); - const { height: footerRowHeight } = useResizeObserver(footerRowRef, 'height'); - - const footerRow = useMemo(() => { - if (renderFooterCellValue == null) return null; - return ( - - ); - }, [ - columnWidths, - columns, - defaultColumnWidth, - interactiveCellId, - leadingControlColumns, + const { footerRow, footerRowHeight } = useDataGridFooter({ renderFooterCellValue, renderCellPopover, - schema, + rowIndex: visibleRowCount, + visibleRowIndex: visibleRowCount, + interactiveCellId, + leadingControlColumns, trailingControlColumns, - visibleRowCount, - ]); + columns, + columnWidths, + defaultColumnWidth, + schema, + }); /** * Handle scrolling cells fully into view diff --git a/src/components/datagrid/body/data_grid_footer_row.test.tsx b/src/components/datagrid/body/data_grid_footer_row.test.tsx deleted file mode 100644 index eca2c81be9c..00000000000 --- a/src/components/datagrid/body/data_grid_footer_row.test.tsx +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 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 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { shallow } from 'enzyme'; - -import { EuiDataGridFooterRow } from './data_grid_footer_row'; - -describe('EuiDataGridFooterRow', () => { - const requiredProps = { - rowIndex: 10, - leadingControlColumns: [], - trailingControlColumns: [], - columns: [{ id: 'someColumn' }, { id: 'someColumnWithoutSchema' }], - schema: { someColumn: { columnType: 'string' } }, - columnWidths: { someColumn: 30 }, - renderCellValue: () =>
, - interactiveCellId: 'someId', - }; - - it('renders columns', () => { - const component = shallow(); - - expect(component).toMatchInlineSnapshot(` -
- - -
- `); - }); - - it('renders leading control columns', () => { - const component = shallow( -
, - rowCellRender: () =>
, - width: 25, - }, - ]} - /> - ); - - expect(component).toMatchInlineSnapshot(` -
- -
- `); - - const renderCellValue: Function = component - .find('EuiDataGridCell') - .prop('renderCellValue'); - expect(renderCellValue()).toEqual(null); - }); - - it('renders trailing control columns', () => { - const component = shallow( -
, - rowCellRender: () =>
, - width: 50, - }, - ]} - /> - ); - - expect(component).toMatchInlineSnapshot(` -
- -
- `); - - const renderCellValue: Function = component - .find('EuiDataGridCell') - .prop('renderCellValue'); - expect(renderCellValue()).toEqual(null); - }); - - it('renders striped styling if the footer row is odd', () => { - const component = shallow( - - ); - expect(component.hasClass('euiDataGridRow--striped')).toBe(true); - }); -}); diff --git a/src/components/datagrid/body/_data_grid_footer_row.scss b/src/components/datagrid/body/footer/_data_grid_footer_row.scss similarity index 100% rename from src/components/datagrid/body/_data_grid_footer_row.scss rename to src/components/datagrid/body/footer/_data_grid_footer_row.scss diff --git a/src/components/datagrid/body/data_grid_footer_row.spec.tsx b/src/components/datagrid/body/footer/data_grid_footer_row.spec.tsx similarity index 97% rename from src/components/datagrid/body/data_grid_footer_row.spec.tsx rename to src/components/datagrid/body/footer/data_grid_footer_row.spec.tsx index eaad99596a1..49d90eec1e2 100644 --- a/src/components/datagrid/body/data_grid_footer_row.spec.tsx +++ b/src/components/datagrid/body/footer/data_grid_footer_row.spec.tsx @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -/// +/// import React, { useState, useEffect } from 'react'; -import { EuiDataGrid } from '../'; +import { EuiDataGrid } from '../../'; describe('EuiDataGridFooterRow', () => { const mockData = [10, 15, 20]; diff --git a/src/components/datagrid/body/footer/data_grid_footer_row.test.tsx b/src/components/datagrid/body/footer/data_grid_footer_row.test.tsx new file mode 100644 index 00000000000..9373b798ab2 --- /dev/null +++ b/src/components/datagrid/body/footer/data_grid_footer_row.test.tsx @@ -0,0 +1,245 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow, render } from 'enzyme'; + +import { EuiDataGridFooterRow } from './data_grid_footer_row'; + +describe('EuiDataGridFooterRow', () => { + const requiredProps = { + rowIndex: 10, + leadingControlColumns: [], + trailingControlColumns: [], + columns: [{ id: 'someColumn' }, { id: 'someColumnWithoutSchema' }], + schema: { someColumn: { columnType: 'string' } }, + columnWidths: { someColumn: 30 }, + renderCellValue: () =>
, + interactiveCellId: 'someId', + }; + + it('renders columns', () => { + const component = shallow(); + + expect(component).toMatchInlineSnapshot(` +
+ + +
+ `); + }); + + describe('control columns', () => { + const requiredColumnProps = { + headerCellRender: () =>
, + rowCellRender: () =>
, + width: 25, + }; + + it('renders leading control columns as null/empty by default', () => { + const component = shallow( + + ); + + expect(component).toMatchInlineSnapshot(` +
+ +
+ `); + + const renderCellValue: Function = component + .find('EuiDataGridCell') + .prop('renderCellValue'); + expect(renderCellValue()).toEqual(null); + }); + + it('renders trailing control columns as null/empty by default', () => { + const component = shallow( + + ); + + expect(component).toMatchInlineSnapshot(` +
+ +
+ `); + + const renderCellValue: Function = component + .find('EuiDataGridCell') + .prop('renderCellValue'); + expect(renderCellValue()).toEqual(null); + }); + + it('renders control column `footerCellRender`s and `footerCellProps` if passed', () => { + const component = render( + ( +
+ ), + footerCellProps: { className: 'leading' }, + }, + ]} + trailingControlColumns={[ + { + id: 'someTrailingColumn', + ...requiredColumnProps, + footerCellRender: () => ( +
+ ), + footerCellProps: { className: 'trailing' }, + }, + ]} + /> + ); + + expect(component.find('.euiDataGridFooterCell.leading')).toHaveLength(1); + expect( + component.find('[data-test-subj="customLeadingControlFooterCell"]') + ).toHaveLength(1); + + expect(component.find('.euiDataGridFooterCell.trailing')).toHaveLength(1); + expect( + component.find('[data-test-subj="customTrailingControlFooterCell"]') + ).toHaveLength(1); + }); + }); + + it('renders striped styling if the footer row is odd', () => { + const component = shallow( + + ); + expect(component.hasClass('euiDataGridRow--striped')).toBe(true); + }); +}); diff --git a/src/components/datagrid/body/data_grid_footer_row.tsx b/src/components/datagrid/body/footer/data_grid_footer_row.tsx similarity index 63% rename from src/components/datagrid/body/data_grid_footer_row.tsx rename to src/components/datagrid/body/footer/data_grid_footer_row.tsx index ca78dacc3cd..085bef3dcc1 100644 --- a/src/components/datagrid/body/data_grid_footer_row.tsx +++ b/src/components/datagrid/body/footer/data_grid_footer_row.tsx @@ -8,9 +8,11 @@ import classnames from 'classnames'; import React, { forwardRef, memo, useContext } from 'react'; -import { EuiDataGridCell } from './data_grid_cell'; -import { DataGridCellPopoverContext } from './data_grid_cell_popover'; -import { EuiDataGridFooterRowProps } from '../data_grid_types'; +import { EuiDataGridCell } from '../data_grid_cell'; +import { DataGridCellPopoverContext } from '../data_grid_cell_popover'; +import { EuiDataGridFooterRowProps } from '../../data_grid_types'; + +const renderEmpty = () => null; const EuiDataGridFooterRow = memo( forwardRef( @@ -50,7 +52,6 @@ const EuiDataGridFooterRow = memo( rowIndex, visibleRowIndex, interactiveCellId, - isExpandable: true, popoverContext, }; @@ -62,17 +63,25 @@ const EuiDataGridFooterRow = memo( data-test-subj={dataTestSubj} {...rest} > - {leadingControlColumns.map(({ id, width }, i) => ( - null} - className="euiDataGridFooterCell euiDataGridRowCell--controlColumn" - /> - ))} + {leadingControlColumns.map( + ({ id, width, footerCellRender, footerCellProps }, i) => ( + + ) + )} {columns.map(({ id }, i) => { const columnType = schema[id] ? schema[id].columnType : null; const width = columnWidths[id] || defaultColumnWidth; @@ -88,25 +97,35 @@ const EuiDataGridFooterRow = memo( width={width || undefined} renderCellValue={renderCellValue} renderCellPopover={renderCellPopover} + isExpandable={true} className="euiDataGridFooterCell" /> ); })} - {trailingControlColumns.map(({ id, width }, i) => { - const colIndex = i + columns.length + leadingControlColumns.length; + {trailingControlColumns.map( + ({ id, width, footerCellRender, footerCellProps }, i) => { + const colIndex = + i + columns.length + leadingControlColumns.length; - return ( - null} - className="euiDataGridFooterCell euiDataGridRowCell--controlColumn" - /> - ); - })} + return ( + + ); + } + )}
); } diff --git a/src/components/datagrid/body/footer/index.ts b/src/components/datagrid/body/footer/index.ts new file mode 100644 index 00000000000..bcad6737661 --- /dev/null +++ b/src/components/datagrid/body/footer/index.ts @@ -0,0 +1,10 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +export { EuiDataGridFooterRow } from './data_grid_footer_row'; +export { useDataGridFooter } from './use_data_grid_footer'; diff --git a/src/components/datagrid/body/footer/use_data_grid_footer.tsx b/src/components/datagrid/body/footer/use_data_grid_footer.tsx new file mode 100644 index 00000000000..03873087592 --- /dev/null +++ b/src/components/datagrid/body/footer/use_data_grid_footer.tsx @@ -0,0 +1,41 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import React, { useState, useMemo } from 'react'; + +import { useResizeObserver } from '../../../observer/resize_observer'; + +import { EuiDataGridFooterRowProps } from '../../data_grid_types'; +import { EuiDataGridFooterRow } from './data_grid_footer_row'; + +type Props = Omit & { + renderFooterCellValue?: EuiDataGridFooterRowProps['renderCellValue']; +}; + +/** + * DRY out setting up the grid footer and its refs & observers + */ +export const useDataGridFooter = (props: Props) => { + const [footerRowRef, setFooterRowRef] = useState(null); + const { height: footerRowHeight } = useResizeObserver(footerRowRef, 'height'); + + const footerRow = useMemo(() => { + const { renderFooterCellValue, ...footerProps } = props; + if (renderFooterCellValue == null) return null; + + return ( + + ); + }, Object.values(props)); // eslint-disable-line react-hooks/exhaustive-deps + + return { footerRow, footerRowHeight }; +}; diff --git a/src/components/datagrid/body/header/data_grid_control_header_cell.tsx b/src/components/datagrid/body/header/data_grid_control_header_cell.tsx index 21ee49fbc2f..b42bb779d60 100644 --- a/src/components/datagrid/body/header/data_grid_control_header_cell.tsx +++ b/src/components/datagrid/body/header/data_grid_control_header_cell.tsx @@ -7,6 +7,8 @@ */ import React, { FunctionComponent } from 'react'; +import classNames from 'classnames'; + import { EuiDataGridControlHeaderCellProps } from '../../data_grid_types'; import { EuiDataGridHeaderCellWrapper } from './data_grid_header_cell_wrapper'; @@ -15,11 +17,20 @@ export const EuiDataGridControlHeaderCell: FunctionComponent { - const { headerCellRender: HeaderCellRender, width, id } = controlColumn; + const { + headerCellRender: HeaderCellRender, + headerCellProps, + width, + id, + } = controlColumn; return ( { - const { id, display, displayAsText } = column; + const { id, display, displayAsText, displayHeaderCellProps } = column; const width = columnWidths[id] || defaultColumnWidth; const columnType = schema[id] ? schema[id].columnType : null; - const classes = classnames({ - [`euiDataGridHeaderCell--${columnType}`]: columnType, - }); + const classes = classnames( + { [`euiDataGridHeaderCell--${columnType}`]: columnType }, + displayHeaderCellProps?.className + ); const { setFocusedCell, focusFirstVisibleInteractiveCell } = useContext( DataGridFocusContext @@ -95,11 +96,12 @@ export const EuiDataGridHeaderCell: FunctionComponent {column.isResizable !== false && width != null ? ( diff --git a/src/components/datagrid/body/header/index.ts b/src/components/datagrid/body/header/index.ts index 283cf2a6f02..703425876a5 100644 --- a/src/components/datagrid/body/header/index.ts +++ b/src/components/datagrid/body/header/index.ts @@ -7,3 +7,4 @@ */ export { EuiDataGridHeaderRow } from './data_grid_header_row'; +export { useDataGridHeader } from './use_data_grid_header'; diff --git a/src/components/datagrid/body/header/use_data_grid_header.tsx b/src/components/datagrid/body/header/use_data_grid_header.tsx new file mode 100644 index 00000000000..b709fe829e3 --- /dev/null +++ b/src/components/datagrid/body/header/use_data_grid_header.tsx @@ -0,0 +1,43 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import React, { useState, useMemo } from 'react'; + +import { useMutationObserver } from '../../../observer/mutation_observer'; +import { useResizeObserver } from '../../../observer/resize_observer'; + +import { useHeaderFocusWorkaround } from '../../utils/focus'; +import { EuiDataGridHeaderRowProps } from '../../data_grid_types'; +import { EuiDataGridHeaderRow } from './data_grid_header_row'; + +type Props = EuiDataGridHeaderRowProps & { + handleHeaderMutation: MutationCallback; +}; + +/** + * DRY out setting up the grid header and its refs & observers + */ +export const useDataGridHeader = ({ + handleHeaderMutation, + ...props +}: Props) => { + const [headerRowRef, setHeaderRowRef] = useState(null); + useMutationObserver(headerRowRef, handleHeaderMutation, { + subtree: true, + childList: true, + }); + const { height: headerRowHeight } = useResizeObserver(headerRowRef, 'height'); + + const headerRow = useMemo(() => { + return ; + }, Object.values(props)); // eslint-disable-line react-hooks/exhaustive-deps + + useHeaderFocusWorkaround(props.headerIsInteractive); + + return { headerRow, headerRowHeight }; +}; diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 1ee9c75b647..b707625b890 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -679,6 +679,7 @@ describe('EuiDataGrid', () => { id: 'leading', width: 50, headerCellRender: () => leading heading, + headerCellProps: { className: 'leadingControlCol' }, rowCellRender: ({ rowIndex }) => rowIndex, }, ]} @@ -687,6 +688,7 @@ describe('EuiDataGrid', () => { id: 'trailing', width: 50, headerCellRender: () => trailing heading, + headerCellProps: { className: 'trailingControlCol' }, rowCellRender: ({ rowIndex }) => rowIndex, }, ]} @@ -699,6 +701,8 @@ describe('EuiDataGrid', () => { ); expect(component).toMatchSnapshot(); + expect(component.find('.leadingControlCol')).toHaveLength(1); + expect(component.find('.trailingControlCol')).toHaveLength(1); }); it('can hide the toolbar', () => { @@ -1459,6 +1463,36 @@ describe('EuiDataGrid', () => { expect(getCellColorAt(0)).toEqual('blue'); expect(getCellColorAt(1)).toEqual(undefined); }); + + test('column display, displayAsText, and displayHeaderCellProps', () => { + const component = render( + {}, + }} + columns={[ + { + id: 'ColumnA', + display: Hello world, + displayAsText: 'displayAsText', + displayHeaderCellProps: { className: 'displayHeaderCellProps' }, + }, + ]} + rowCount={1} + renderCellValue={({ rowIndex, columnId }) => + `${rowIndex}, ${columnId}` + } + /> + ); + const colHeaderCell = component.find( + '.euiDataGridHeaderCell.displayHeaderCellProps' + ); + expect(colHeaderCell).toHaveLength(1); + expect(colHeaderCell.find('[data-test-subj="display"]')).toHaveLength(1); + expect(colHeaderCell.find('[title="displayAsText"]')).toHaveLength(1); + }); }); describe('column sorting', () => { diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 180ed1f2c3c..c03d3a4bb10 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -547,18 +547,30 @@ export interface EuiDataGridControlColumn { * Used as the React `key` when rendering content */ id: string; + /** + * Width of the column, users are unable to change this + */ + width: number; /** * Component to render in the column header */ headerCellRender: ComponentType; + /** + * Optional props to pass to the column header cell + */ + headerCellProps?: HTMLAttributes; /** * Component to render for each row in the column */ rowCellRender: EuiDataGridCellProps['renderCellValue']; /** - * Width of the column, uses are unable to change this + * Component to render in the optional column footer */ - width: number; + footerCellRender?: EuiDataGridCellProps['renderCellValue']; + /** + * Optional props to pass to the column footer cell + */ + footerCellProps?: HTMLAttributes; } export interface EuiDataGridColumn { @@ -577,6 +589,10 @@ export interface EuiDataGridColumn { * If not passed, `id` will be shown as the column name. */ displayAsText?: string; + /** + * Optional props to pass to the column header cell + */ + displayHeaderCellProps?: HTMLAttributes; /** * Initial width (in pixels) of the column */ diff --git a/upcoming_changelogs/6609.md b/upcoming_changelogs/6609.md new file mode 100644 index 00000000000..16632cc60ee --- /dev/null +++ b/upcoming_changelogs/6609.md @@ -0,0 +1,7 @@ +- Added the `displayHeaderCellProps` API to `EuiDataGrid`'s columns, which allows passing custom props directly to column header cells +- Added the new `headerCellProps`/`footerCellProps` APIs to `EuiDataGrid`'s control columns, which allows passing custom props directly to control column header or footer cells +- Added a new `footerCellRender` API to `EuiDataGrid`'s control columns, which allows completely customizing control column rendering (previously rendered an empty cell) + +**Bug fixes** + +- Fixed `EuiDataGrid` footer control columns rendering with cell expansion popovers when they should not have been