Skip to content

Commit

Permalink
[EuiDataGrid] Add several new footer/header customization APIs + bonu…
Browse files Browse the repository at this point in the history
…s cleanup (#6609)

* Add new `displayHeaderCellProps` column API

* Add new `headerCellProps` control column API

* [Setup] Move footer-related components to own folder

- for better organization/architecture

* Add new `footerCellRender` control column API

+ fix footer control columns rendering with `isExpandable` true as a default - should not be true

+ adds docs, fix broken amount total

+ reorder types slightly

* Add new `footerCellProps` control column API

* [Setup] DRY out header & footer instantiation to hooks

- this commit isn't specifically needed by this PR, but *will* be needed once we implement a custom body renderer
  • Loading branch information
cee-chen authored Feb 23, 2023
1 parent 9894efd commit a4af8d6
Show file tree
Hide file tree
Showing 20 changed files with 549 additions and 325 deletions.
11 changes: 9 additions & 2 deletions src-docs/src/views/datagrid/_snippets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ inMemory={{ level: 'sorting' }}`,
id: 'A', // required
display: <>Column A <EuiIcon type="dot" /></>, // 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
Expand All @@ -33,16 +34,22 @@ inMemory={{ level: 'sorting' }}`,
{
id: 'selection',
width: 31,
headerCellRender: () => <span>Select a Row</span>,
headerCellRender: () => <span>Select a row</span>,
headerCellProps: { className: 'eui-textCenter' },
rowCellRender: () => <div><EuiCheckbox ... /></div>,
footerCellRender: () => <span>Select a row</span>,
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 }) => {}}',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,7 @@ schemaDetectors={[
<p>
The footer row is defined by passing{' '}
<EuiCode>renderFooterCellValue</EuiCode> function prop into{' '}
<strong>EuiDataGrid</strong>.{' '}
<EuiCode>renderFooterCellValue</EuiCode> acts like a React
<strong>EuiDataGrid</strong>. This function acts like a React
component, receiving{' '}
<EuiCode>EuiDataGridCellValueElementProps</EuiCode> and returning a
React node.
Expand All @@ -304,6 +303,10 @@ schemaDetectors={[
expansion on cells without content with{' '}
<EuiCode>setCellProps({'{ isExpandable: false }'})</EuiCode>.
</p>
<p>
Control columns will render empty footer cells by default, unless a
custom <EuiCode>footerCellRender</EuiCode> function is passed.
</p>
</Fragment>
),
props: {
Expand Down
47 changes: 46 additions & 1 deletion src-docs/src/views/datagrid/schema_columns/footer_row.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { faker } from '@faker-js/faker';

import {
EuiDataGrid,
EuiCheckbox,
EuiButtonIcon,
EuiSwitch,
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -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(),
});
Expand Down Expand Up @@ -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: () => (
<EuiCheckbox
id="selectAllHeader"
aria-label="Select all rows"
onChange={() => {}}
/>
),
rowCellRender: ({ rowIndex }) => (
<EuiCheckbox
id={`selectRow${rowIndex}`}
aria-label="Select this row"
onChange={() => {}}
/>
),
footerCellRender: () => (
<EuiCheckbox
id="selectAllFooter"
aria-label="Select all rows"
onChange={() => {}}
/>
),
},
];
const trailingControlColumns = [
{
id: 'actions',
width: 36,
headerCellRender: () => (
<span className="euiScreenReaderOnly">Actions</span>
),
rowCellRender: () => (
<EuiButtonIcon aria-label="Show actions" iconType="boxesHorizontal" />
),
},
];

const footerCellValues = {
amount: `Total: ${raw_data
.reduce((acc, { amount }) => acc + Number(amount.split('$')[1]), 0)
Expand Down Expand Up @@ -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={
Expand Down
4 changes: 2 additions & 2 deletions src/components/datagrid/__snapshots__/data_grid.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ Array [
role="row"
>
<div
class="euiDataGridHeaderCell euiDataGridHeaderCell--controlColumn"
class="euiDataGridHeaderCell euiDataGridHeaderCell--controlColumn leadingControlCol"
data-gridcell-column-id="leading"
data-gridcell-column-index="0"
data-gridcell-row-index="-1"
Expand Down Expand Up @@ -1194,7 +1194,7 @@ Array [
</p>
</div>
<div
class="euiDataGridHeaderCell euiDataGridHeaderCell--controlColumn"
class="euiDataGridHeaderCell euiDataGridHeaderCell--controlColumn trailingControlCol"
data-gridcell-column-id="trailing"
data-gridcell-column-index="3"
data-gridcell-row-index="-1"
Expand Down
2 changes: 1 addition & 1 deletion src/components/datagrid/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@import 'mixins';
@import 'data_grid';
@import 'body/header/data_grid_header_row';
@import 'body/data_grid_footer_row';
@import 'body/footer/data_grid_footer_row';
@import 'body/header/data_grid_column_resizer';
@import 'data_grid_data_row';
@import 'controls/data_grid_toolbar';
Expand Down
86 changes: 17 additions & 69 deletions src/components/datagrid/body/data_grid_body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,17 @@ import React, {
createContext,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import {
GridChildComponentProps,
VariableSizeGrid as Grid,
VariableSizeGridProps,
} from 'react-window';
import { useMutationObserver } from '../../observer/mutation_observer';
import { useResizeObserver } from '../../observer/resize_observer';
import { EuiDataGridCell } from './data_grid_cell';
import { EuiDataGridFooterRow } from './data_grid_footer_row';
import { EuiDataGridHeaderRow } from './header';
import { useDataGridHeader } from './header';
import { useDataGridFooter } from './footer';
import { DataGridCellPopoverContext } from './data_grid_cell_popover';
import {
EuiDataGridBodyProps,
Expand All @@ -41,7 +38,6 @@ import {
} from '../utils/grid_height_width';
import { useDefaultColumnWidth, useColumnWidths } from '../utils/col_widths';
import { useRowHeightUtils, useDefaultRowHeight } from '../utils/row_heights';
import { useHeaderFocusWorkaround } from '../utils/focus';
import { useScrollBars, useScroll } from '../utils/scrolling';
import { DataGridSortingContext } from '../utils/sorting';
import { IS_JEST_ENVIRONMENT } from '../../../utils';
Expand Down Expand Up @@ -284,33 +280,11 @@ export const EuiDataGridBody: FunctionComponent<EuiDataGridBodyProps> = (
});

/**
* Header
* Header & footer
*/
const [headerRowRef, setHeaderRowRef] = useState<HTMLDivElement | null>(null);
useMutationObserver(headerRowRef, handleHeaderMutation, {
subtree: true,
childList: true,
});
const { height: headerRowHeight } = useResizeObserver(headerRowRef, 'height');

const headerRow = useMemo(() => {
return (
<EuiDataGridHeaderRow
ref={setHeaderRowRef}
switchColumnPos={switchColumnPos}
setVisibleColumns={setVisibleColumns}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
columns={columns}
columnWidths={columnWidths}
defaultColumnWidth={defaultColumnWidth}
setColumnWidth={setColumnWidth}
schema={schema}
schemaDetectors={schemaDetectors}
headerIsInteractive={headerIsInteractive}
/>
);
}, [
const { headerRow, headerRowHeight } = useDataGridHeader({
headerIsInteractive,
handleHeaderMutation,
switchColumnPos,
setVisibleColumns,
leadingControlColumns,
Expand All @@ -321,47 +295,21 @@ export const EuiDataGridBody: FunctionComponent<EuiDataGridBodyProps> = (
setColumnWidth,
schema,
schemaDetectors,
headerIsInteractive,
]);

useHeaderFocusWorkaround(headerIsInteractive);
});

/**
* Footer
*/
const [footerRowRef, setFooterRowRef] = useState<HTMLDivElement | null>(null);
const { height: footerRowHeight } = useResizeObserver(footerRowRef, 'height');

const footerRow = useMemo(() => {
if (renderFooterCellValue == null) return null;
return (
<EuiDataGridFooterRow
ref={setFooterRowRef}
leadingControlColumns={leadingControlColumns}
trailingControlColumns={trailingControlColumns}
columns={columns}
schema={schema}
columnWidths={columnWidths}
defaultColumnWidth={defaultColumnWidth}
renderCellValue={renderFooterCellValue}
renderCellPopover={renderCellPopover}
rowIndex={visibleRowCount}
visibleRowIndex={visibleRowCount}
interactiveCellId={interactiveCellId}
/>
);
}, [
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
Expand Down
Loading

0 comments on commit a4af8d6

Please sign in to comment.