diff --git a/src/components/datagrid/body/cell/data_grid_cell.tsx b/src/components/datagrid/body/cell/data_grid_cell.tsx index 9e1fdcd32e3..e1ead508adf 100644 --- a/src/components/datagrid/body/cell/data_grid_cell.tsx +++ b/src/components/datagrid/body/cell/data_grid_cell.tsx @@ -47,7 +47,123 @@ import { import { DefaultCellPopover } from './data_grid_cell_popover'; import { HandleInteractiveChildren } from './focus_utils'; -const Cell: React.FunctionComponent<{ +const EuiDataGridCellContent: FunctionComponent< + EuiDataGridCellValueProps & { + setCellProps: EuiDataGridCellValueElementProps['setCellProps']; + setCellContentsRef: EuiDataGridCell['setCellContentsRef']; + isExpanded: boolean; + isControlColumn: boolean; + isFocused: boolean; + ariaRowIndex: number; + rowHeight?: EuiDataGridRowHeightOption; + cellActions?: ReactNode; + } +> = memo( + ({ + renderCellValue, + renderCellContext, + column, + setCellContentsRef, + rowIndex, + colIndex, + ariaRowIndex, + rowHeight, + rowHeightUtils, + isControlColumn, + isFocused, + cellActions, + ...rest + }) => { + // React is more permissible than the TS types indicate + const CellElement = + renderCellValue as JSXElementConstructor; + + const cellHeightType = + rowHeightUtils?.getHeightType(rowHeight) || 'default'; + + const classes = classNames( + 'euiDataGridRowCell__content', + `euiDataGridRowCell__content--${cellHeightType}Height`, + !isControlColumn && { + 'eui-textBreakWord': cellHeightType !== 'default', + 'eui-textTruncate': cellHeightType === 'default', + } + ); + + const mergedProps = useMemo(() => { + if (renderCellContext) { + return { + ...renderCellContext(), + ...rest, + }; + } else { + return rest; + } + }, [rest, renderCellContext]); + + let cellContent = ( +
+ +
+ ); + if (cellHeightType === 'lineCount' && !isControlColumn) { + const lines = rowHeightUtils!.getLineCount(rowHeight)!; + cellContent = ( + + {cellContent} + + ); + } + + const screenReaderText = ( + + + + ); + + return ( + <> + {cellContent} + {screenReaderText} + {cellActions} + + ); + } +); +EuiDataGridCellContent.displayName = 'EuiDataGridCellContent'; + +export const Cell: React.FunctionComponent<{ ariaRowIndex: number; isFocused: boolean; cellRef: React.MutableRefObject; @@ -143,132 +259,7 @@ const Cell: React.FunctionComponent<{ ); } ); - -const EuiDataGridCellContent: FunctionComponent< - EuiDataGridCellValueProps & { - setCellProps: EuiDataGridCellValueElementProps['setCellProps']; - setCellContentsRef: EuiDataGridCell['setCellContentsRef']; - isExpanded: boolean; - isControlColumn: boolean; - isFocused: boolean; - ariaRowIndex: number; - rowHeight?: EuiDataGridRowHeightOption; - cellActions?: ReactNode; - } -> = memo( - ({ - renderCellValue, - renderCellContext, - column, - setCellContentsRef, - rowIndex, - colIndex, - ariaRowIndex, - rowHeight, - rowHeightUtils, - isControlColumn, - isFocused, - cellActions, - ...rest - }) => { - // React is more permissible than the TS types indicate - const CellElement = - renderCellValue as JSXElementConstructor; - - const cellHeightType = - rowHeightUtils?.getHeightType(rowHeight) || 'default'; - - const classes = classNames( - 'euiDataGridRowCell__content', - `euiDataGridRowCell__content--${cellHeightType}Height`, - !isControlColumn && { - 'eui-textBreakWord': cellHeightType !== 'default', - 'eui-textTruncate': cellHeightType === 'default', - } - ); - - const mergedProps = useMemo(() => { - if (renderCellContext) { - return { - ...rest, - ...renderCellContext(), - }; - } else { - return { - ...rest, - }; - } - }, [rest, renderCellContext]); - - const cellContent = useMemo(() => { - return ( -
- -
- ); - }, [ - CellElement, - classes, - column, - colIndex, - mergedProps, - rowIndex, - setCellContentsRef, - rest.columnType, - ]); - - const truncatedCellContent = useMemo(() => { - if (cellHeightType === 'lineCount' && !isControlColumn) { - const lines = rowHeightUtils!.getLineCount(rowHeight)!; - return ( - - {cellContent} - - ); - } else { - return cellContent; - } - }, [ - cellContent, - cellHeightType, - isControlColumn, - rowHeightUtils, - rowHeight, - ]); - - return ( - <> - {truncatedCellContent} - - - - - ); - } -); -EuiDataGridCellContent.displayName = 'EuiDataGridCellContent'; +Cell.displayName = 'Cell'; export class EuiDataGridCell extends Component< EuiDataGridCellProps, @@ -647,7 +638,6 @@ export class EuiDataGridCell extends Component< }; handleCellExpansionClick = () => { - console.log('fire'); const { popoverContext: { openCellPopover, closeCellPopover }, visibleRowIndex, @@ -661,8 +651,12 @@ export class EuiDataGridCell extends Component< } }; - onMouseEnter = () => this.setState({ isHovered: true }); - onMouseLeave = () => this.setState({ isHovered: false }); + onMouseEnter = () => { + this.setState({ isHovered: true }); + }; + onMouseLeave = () => { + this.setState({ isHovered: false }); + }; render() { const { diff --git a/src/components/datagrid/body/cell/data_grid_cell_actions.test.tsx b/src/components/datagrid/body/cell/data_grid_cell_actions.test.tsx index ac88bd41bb3..fe16e085dd9 100644 --- a/src/components/datagrid/body/cell/data_grid_cell_actions.test.tsx +++ b/src/components/datagrid/body/cell/data_grid_cell_actions.test.tsx @@ -34,15 +34,17 @@ describe('EuiDataGridCellActions', () => {
- + + +
`); - const button: Function = component - .find('ExpandButton') - .renderProp('children'); + const button: Function = component.find('EuiI18n').renderProp('children'); expect(button('expandButtonTitle')).toMatchInlineSnapshot(` { key="0" rowIndex={0} /> - + + + `); }); diff --git a/src/components/datagrid/body/cell/data_grid_cell_actions.tsx b/src/components/datagrid/body/cell/data_grid_cell_actions.tsx index 26602b79902..701b25655f2 100644 --- a/src/components/datagrid/body/cell/data_grid_cell_actions.tsx +++ b/src/components/datagrid/body/cell/data_grid_cell_actions.tsx @@ -6,13 +6,7 @@ * Side Public License, v 1. */ -import React, { - JSXElementConstructor, - useMemo, - useCallback, - type FunctionComponent, - type MouseEventHandler, -} from 'react'; +import React, { JSXElementConstructor, useMemo, useCallback } from 'react'; import { EuiDataGridColumn, EuiDataGridColumnCellAction, @@ -28,23 +22,22 @@ import { import { EuiFlexGroup, EuiFlexItem } from '../../../flex'; import { EuiPopoverFooter } from '../../../popover'; -const ButtonComponent = (props: EuiButtonIconProps) => ( - -); - -const ExpandButton: FunctionComponent<{ onExpandClick: MouseEventHandler }> = ({ +export const EuiDataGridCellActions = ({ onExpandClick, + column, + rowIndex, + colIndex, +}: { + onExpandClick: () => void; + column?: EuiDataGridColumn; + rowIndex: number; + colIndex: number; }) => { - return ( + // Note: The cell expand button/expansion popover is *always* rendered if + // column.cellActions is present (regardless of column.isExpandable). + // This is because cell actions are not otherwise accessible to keyboard + // or screen reader users + const expandButton = ( = ({ )} ); -}; - -export const EuiDataGridCellActions = ({ - onExpandClick, - column, - rowIndex, - colIndex, -}: { - onExpandClick: () => void; - column?: EuiDataGridColumn; - rowIndex: number; - colIndex: number; -}) => { - // Note: The cell expand button/expansion popover is *always* rendered if - // column.cellActions is present (regardless of column.isExpandable). - // This is because cell actions are not otherwise accessible to keyboard - // or screen reader users const additionalButtons = useMemo(() => { if (!column || !Array.isArray(column?.cellActions)) return []; + const ButtonComponent = (props: EuiButtonIconProps) => ( + + ); + const [visibleCellActions] = getVisibleCellActions( column?.cellActions, column?.visibleCellActions @@ -111,8 +100,7 @@ export const EuiDataGridCellActions = ({ return (
- {[...additionalButtons]} - + {[...additionalButtons, expandButton]}
); }; diff --git a/src/components/datagrid/body/cell/data_grid_cell_popover.tsx b/src/components/datagrid/body/cell/data_grid_cell_popover.tsx index a5d294399b1..13c1785656f 100644 --- a/src/components/datagrid/body/cell/data_grid_cell_popover.tsx +++ b/src/components/datagrid/body/cell/data_grid_cell_popover.tsx @@ -78,19 +78,6 @@ export const useCellPopover = (): { [popoverIsOpen, cellLocation] ); - const cellPopoverContext = useMemo(() => { - return { - popoverIsOpen, - closeCellPopover, - openCellPopover, - cellLocation, - setPopoverAnchorPosition, - setPopoverAnchor, - setPopoverContent, - setCellPopoverProps, - }; - }, [popoverIsOpen, closeCellPopover, openCellPopover, cellLocation]); - // Override the default EuiPopover `onClickOutside` behavior, since the toggling // popover button isn't actually the DOM node we pass to `button`. Otherwise, // clicking the expansion cell action triggers an outside click @@ -126,6 +113,16 @@ export const useCellPopover = (): { ); return useMemo(() => { + const cellPopoverContext = { + popoverIsOpen, + closeCellPopover, + openCellPopover, + cellLocation, + setPopoverAnchorPosition, + setPopoverAnchor, + setPopoverContent, + setCellPopoverProps, + }; // Note that this popover is rendered once at the top grid level, rather than one popover per cell const cellPopover = popoverIsOpen && popoverAnchor && ( { const requiredProps = { @@ -33,13 +33,13 @@ describe('Cell', () => { }; it('is a light wrapper around EuiDataGridCell', () => { - const component = shallow(); + const component = shallow(); expect(component.find('EuiDataGridCell').exists()).toBe(true); }); it('renders leading control column cells', () => { const component = shallow( - { it('renders trailing control column cells', () => { const component = shallow( - { it('renders text transform classes based on schema', () => { const component = shallow( - { it('allows passing optional EuiDataGridCellProps overrides', () => { const component = shallow( - & Pick< EuiDataGridBodyProps, @@ -52,7 +53,7 @@ type CellProps = Pick< * It grabs context, determines the type of cell being rendered * (e.g. control vs data cell), & sets shared props between all cells */ -export const Cell: FunctionComponent = memo( +export const CellWrapper: FunctionComponent = memo( ({ colIndex, visibleRowIndex, @@ -143,81 +144,61 @@ export const Cell: FunctionComponent = memo( textTransform, ]); - const cellContent = useMemo(() => { - if (isLeadingControlColumn) { - const leadingColumn = leadingControlColumns[colIndex]; - const { id, rowCellRender } = leadingColumn; - - return ( - - ); - } else if (isTrailingControlColumn) { - const columnOffset = columns.length + leadingControlColumns.length; - const trailingcolIndex = colIndex - columnOffset; - const trailingColumn = trailingControlColumns[trailingcolIndex]; - const { id, rowCellRender } = trailingColumn; - - return ( - - ); - } else { - // this is a normal data cell - const columnType = schema[columnId] - ? schema[columnId].columnType - : null; - - const isExpandable = - column.isExpandable !== undefined ? column.isExpandable : true; - - const width = columnWidths[columnId] || defaultColumnWidth; - - return ( - - ); - } - }, [ - colIndex, - isLeadingControlColumn, - isTrailingControlColumn, - rest, - columnId, - column, - columnWidths, - defaultColumnWidth, - renderCellValue, - renderCellPopover, - interactiveCellId, - sharedCellProps, - schema, - columns, - leadingControlColumns, - trailingControlColumns, - ]); - return cellContent; + if (isLeadingControlColumn) { + const leadingColumn = leadingControlColumns[colIndex]; + const { id, rowCellRender } = leadingColumn; + + return ( + + ); + } else if (isTrailingControlColumn) { + const columnOffset = columns.length + leadingControlColumns.length; + const trailingcolIndex = colIndex - columnOffset; + const trailingColumn = trailingControlColumns[trailingcolIndex]; + const { id, rowCellRender } = trailingColumn; + + return ( + + ); + } else { + // this is a normal data cell + const columnType = schema[columnId] ? schema[columnId].columnType : null; + + const isExpandable = + column?.isExpandable !== undefined ? column?.isExpandable : true; + + const width = columnWidths[columnId] || defaultColumnWidth; + + return ( + + ); + } } ); + +CellWrapper.displayName = 'CellWrapper'; diff --git a/src/components/datagrid/body/cell/index.ts b/src/components/datagrid/body/cell/index.ts index ed2338e8de2..97cbb9d8106 100644 --- a/src/components/datagrid/body/cell/index.ts +++ b/src/components/datagrid/body/cell/index.ts @@ -8,7 +8,7 @@ export { EuiDataGridCell } from './data_grid_cell'; -export { Cell } from './data_grid_cell_wrapper'; +export { CellWrapper } from './data_grid_cell_wrapper'; export { DataGridCellPopoverContext, diff --git a/src/components/datagrid/body/data_grid_body_custom.tsx b/src/components/datagrid/body/data_grid_body_custom.tsx index f2819d0a557..062449f1bfb 100644 --- a/src/components/datagrid/body/data_grid_body_custom.tsx +++ b/src/components/datagrid/body/data_grid_body_custom.tsx @@ -24,7 +24,7 @@ import { } from '../data_grid_types'; import { useDataGridHeader } from './header'; import { useDataGridFooter } from './footer'; -import { Cell } from './cell'; +import { CellWrapper } from './cell'; export const EuiDataGridBodyCustomRender: FunctionComponent< EuiDataGridBodyProps @@ -171,7 +171,7 @@ export const EuiDataGridBodyCustomRender: FunctionComponent< style, ...cellProps, }; - return ; + return ; }, [cellProps, getRowHeight, rowHeightUtils, rowHeightsOptions] ); diff --git a/src/components/datagrid/body/data_grid_body_virtualized.test.tsx b/src/components/datagrid/body/data_grid_body_virtualized.test.tsx index 8359f01414b..4e90776b7a4 100644 --- a/src/components/datagrid/body/data_grid_body_virtualized.test.tsx +++ b/src/components/datagrid/body/data_grid_body_virtualized.test.tsx @@ -56,7 +56,7 @@ describe('EuiDataGridBodyVirtualized', () => { renderFooterCellValue={() =>