Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Added `readOnly` prop to `EuiMarkdownEditor` ([#5627](https://github.com/elastic/eui/pull/5627))
- Added support for supplying `breadcrumbs` and `breadcrumbProps` directly to `EuiPageHeader` ([#5634](https://github.com/elastic/eui/pull/5634))
- Extended props of `EuiBreadcrumb` to include `HTMLElement` and `color` inherited from `EuiLink` ([#5634](https://github.com/elastic/eui/pull/5634))
- Updated `EuiDataGrid` to allow setting individual cell `isExpandable` state via `setCellProps` ([#5667](https://github.com/elastic/eui/pull/5667))

## [`49.0.0`](https://github.com/elastic/eui/tree/v49.0.0)

Expand Down
3 changes: 3 additions & 0 deletions src-docs/src/views/datagrid/datagrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ const RenderCellValue = ({ rowIndex, columnId, setCellProps }) => {
});
}
}
if (rowIndex === 2) {
setCellProps({ isExpandable: false });
}
}, [rowIndex, columnId, setCellProps, data]);

function getFormatted() {
Expand Down
32 changes: 31 additions & 1 deletion src/components/datagrid/body/data_grid_cell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React from 'react';
import React, { useEffect } from 'react';
import { mount, render, ReactWrapper } from 'enzyme';
import { keys } from '../../../services';
import { mockRowHeightUtils } from '../utils/__mocks__/row_heights';
Expand Down Expand Up @@ -385,6 +385,36 @@ describe('EuiDataGridCell', () => {
});
});

describe('isExpandable', () => {
it('falls back to props.isExpandable which is derived from the column config', () => {
const component = mount(
<EuiDataGridCell {...requiredProps} isExpandable={true} />
);

expect(component.find('renderCellValue').prop('isExpandable')).toBe(true);
});

it('allows overriding column.isExpandable with setCellProps({ isExpandable })', () => {
const RenderCellValue = ({ setCellProps }: any) => {
useEffect(() => {
setCellProps({ isExpandable: false });
}, [setCellProps]);
return 'cell render';
};
const component = mount(
<EuiDataGridCell
{...requiredProps}
isExpandable={true}
renderCellValue={RenderCellValue}
/>
);

expect(component.find('RenderCellValue').prop('isExpandable')).toBe(
false
);
});
});

// TODO: Test ResizeObserver logic in Cypress alongside Jest
describe('row height logic & resize observers', () => {
describe('recalculateAutoHeight', () => {
Expand Down
44 changes: 27 additions & 17 deletions src/components/datagrid/body/data_grid_cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import React, {
createRef,
FocusEvent,
FunctionComponent,
HTMLAttributes,
JSXElementConstructor,
KeyboardEvent,
memo,
Expand All @@ -29,6 +28,7 @@ import { DataGridFocusContext } from '../utils/focus';
import {
EuiDataGridCellProps,
EuiDataGridCellState,
EuiDataGridSetCellProps,
EuiDataGridCellValueElementProps,
EuiDataGridCellValueProps,
EuiDataGridCellPopoverElementProps,
Expand Down Expand Up @@ -160,7 +160,7 @@ export class EuiDataGridCell extends Component<

if (doFocusUpdate) {
const interactables = this.getInteractables();
if (this.props.isExpandable === false && interactables.length === 1) {
if (this.isExpandable() === false && interactables.length === 1) {
Comment thread
cee-chen marked this conversation as resolved.
// Only one element can be interacted with
interactables[0].focus({ preventScroll });
} else {
Expand Down Expand Up @@ -353,7 +353,7 @@ export class EuiDataGridCell extends Component<
return false;
}

setCellProps = (cellProps: HTMLAttributes<HTMLDivElement>) => {
setCellProps = (cellProps: EuiDataGridSetCellProps) => {
this.setState({ cellProps });
};

Expand All @@ -379,7 +379,7 @@ export class EuiDataGridCell extends Component<
// * if the cell children include portalled content React will bubble the focus
// event up, which can trigger the focus() call below, causing focus lock fighting
if (this.cellRef.current === e.target) {
const { colIndex, visibleRowIndex, isExpandable } = this.props;
const { colIndex, visibleRowIndex } = this.props;
// focus in next tick to give potential focus capturing mechanisms time to release their traps
// also clear any previous focus timeout that may still be queued
if (EuiDataGridCell.activeFocusTimeoutId) {
Expand All @@ -390,7 +390,7 @@ export class EuiDataGridCell extends Component<
this.context.setFocusedCell([colIndex, visibleRowIndex]);

const interactables = this.getInteractables();
if (interactables.length === 1 && isExpandable === false) {
if (interactables.length === 1 && this.isExpandable() === false) {
interactables[0].focus();
this.setState({ disableCellTabIndex: true });
}
Expand Down Expand Up @@ -425,12 +425,17 @@ export class EuiDataGridCell extends Component<
}
};

isExpandable = () => {
// props.isExpandable inherits from column.isExpandable
// state.cellProps allows consuming applications to override isExpandable on a per-cell basis
return this.state.cellProps.isExpandable ?? this.props.isExpandable;
};

isPopoverOpen = () => {
const { isExpandable, popoverContext } = this.props;
const { popoverIsOpen, cellLocation } = popoverContext;
const { popoverIsOpen, cellLocation } = this.props.popoverContext;

return (
isExpandable &&
this.isExpandable() &&
popoverIsOpen &&
cellLocation.colIndex === this.props.colIndex &&
cellLocation.rowIndex === this.props.visibleRowIndex
Expand Down Expand Up @@ -493,7 +498,6 @@ export class EuiDataGridCell extends Component<
render() {
const {
width,
isExpandable,
popoverContext: { closeCellPopover, openCellPopover },
interactiveCellId,
columnType,
Expand All @@ -507,6 +511,7 @@ export class EuiDataGridCell extends Component<
} = this.props;
const { rowIndex, visibleRowIndex, colIndex } = rest;

const isExpandable = this.isExpandable();
const popoverIsOpen = this.isPopoverOpen();
const hasCellActions = isExpandable || column?.cellActions;
const showCellActions =
Expand All @@ -524,21 +529,26 @@ export class EuiDataGridCell extends Component<
className
);

const cellProps = {
...this.state.cellProps,
'data-test-subj': classNames(
'dataGridRowCell',
this.state.cellProps['data-test-subj']
),
className: classNames(cellClasses, this.state.cellProps.className),
const {
isExpandable: _, // Not a valid DOM property, so needs to be destructured out
style: cellPropsStyle,
className: cellPropsClassName,
'data-test-subj': cellPropsDataTestSubj,
...setCellProps
} = this.state.cellProps;

const cellProps: EuiDataGridSetCellProps = {
...setCellProps,
'data-test-subj': classNames('dataGridRowCell', cellPropsDataTestSubj),
className: classNames(cellClasses, cellPropsClassName),
};

cellProps.style = {
...style, // from react-window
top: 0, // The cell's row will handle top positioning
width, // column width, can be undefined
lineHeight: rowHeightsOptions?.lineHeight ?? undefined, // lineHeight configuration
...cellProps.style, // apply anything from setCellProps({style})
...cellPropsStyle, // apply anything from setCellProps({ style })
};

const handleCellKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
Expand Down
9 changes: 7 additions & 2 deletions src/components/datagrid/data_grid_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,18 @@ interface SharedRenderCellElementProps {
schema: string | undefined | null;
}

export type EuiDataGridSetCellProps = CommonProps &
HTMLAttributes<HTMLDivElement> & {
isExpandable?: boolean;
};

export interface EuiDataGridCellValueElementProps
extends SharedRenderCellElementProps {
/**
* Callback function to set custom props & attributes on the cell's wrapping `div` element;
* it's best to wrap calls to `setCellProps` in a `useEffect` hook
*/
setCellProps: (props: CommonProps & HTMLAttributes<HTMLDivElement>) => void;
setCellProps: (props: EuiDataGridSetCellProps) => void;
/**
* Whether or not the cell is expandable, comes from the #EuiDataGridColumn `isExpandable` which defaults to `true`
*/
Expand Down Expand Up @@ -482,7 +487,7 @@ export interface EuiDataGridCellProps {
}

export interface EuiDataGridCellState {
cellProps: CommonProps & HTMLAttributes<HTMLDivElement>;
cellProps: EuiDataGridSetCellProps;
isFocused: boolean; // tracks if this cell has focus or not, used to enable tabIndex on the cell
isEntered: boolean; // enables focus trap for non-expandable cells with multiple interactive elements
enableInteractions: boolean; // cell got hovered at least once, so cell button and popover interactions are rendered
Expand Down