From a5bb3b3a8ac444b8b13c79d5f2689a884fecff06 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 18 Jan 2022 15:12:55 -0800 Subject: [PATCH 01/13] [setup] Update testCustomHook to expose fn that allows accessing most recent state/value - without this callback, the initial returned hook values will be stale/not properly return most recent values - see next commit for example usage within useCellPopover --- .../controls/display_selector.test.tsx | 4 +- .../datagrid/utils/scrolling.test.ts | 68 +++++++++++++------ src/test/test_custom_hook.tsx | 15 +++- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/components/datagrid/controls/display_selector.test.tsx b/src/components/datagrid/controls/display_selector.test.tsx index e05cc27ac8f..62b7f7a210f 100644 --- a/src/components/datagrid/controls/display_selector.test.tsx +++ b/src/components/datagrid/controls/display_selector.test.tsx @@ -420,7 +420,9 @@ describe('useDataGridDisplaySelector', () => { describe('gridStyles', () => { it('returns an object of grid styles with user overrides', () => { const initialStyles = { ...startingStyles, stripes: true }; - const [, gridStyles] = testCustomHook(() => + const { + return: [, gridStyles], + } = testCustomHook(() => useDataGridDisplaySelector(true, initialStyles, {}) ); diff --git a/src/components/datagrid/utils/scrolling.test.ts b/src/components/datagrid/utils/scrolling.test.ts index bcfd80b2cd7..0f6f7e5fa14 100644 --- a/src/components/datagrid/utils/scrolling.test.ts +++ b/src/components/datagrid/utils/scrolling.test.ts @@ -56,7 +56,9 @@ describe('useScrollCellIntoView', () => { }); it('does nothing if the grid references are unavailable', () => { - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, gridRef: { current: null }, @@ -78,7 +80,9 @@ describe('useScrollCellIntoView', () => { offsetWidth: 500, }; - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { @@ -95,9 +99,9 @@ describe('useScrollCellIntoView', () => { it('calls scrollToItem if the specified cell is not virtualized', async () => { getCell.mockReturnValue(null); - const { scrollCellIntoView } = testCustomHook(() => - useScrollCellIntoView(args) - ); + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView(args)); await scrollCellIntoView({ rowIndex: 20, colIndex: 5 }); expect(scrollToItem).toHaveBeenCalledWith({ columnIndex: 5, rowIndex: 20 }); }); @@ -108,9 +112,9 @@ describe('useScrollCellIntoView', () => { offsetTop: 50, offsetLeft: 50, }); - const { scrollCellIntoView } = testCustomHook(() => - useScrollCellIntoView(args) - ); + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView(args)); scrollCellIntoView({ rowIndex: 1, colIndex: 1 }); expect(scrollToItem).not.toHaveBeenCalled(); @@ -130,7 +134,9 @@ describe('useScrollCellIntoView', () => { }; getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -154,7 +160,9 @@ describe('useScrollCellIntoView', () => { }; getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -177,7 +185,9 @@ describe('useScrollCellIntoView', () => { }; getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -202,7 +212,9 @@ describe('useScrollCellIntoView', () => { it('scrolls the grid down if the bottom side of the cell is out of view', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -214,7 +226,9 @@ describe('useScrollCellIntoView', () => { it('accounts for the sticky bottom footer if present', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -228,7 +242,9 @@ describe('useScrollCellIntoView', () => { it('makes no vertical adjustments if the cell is a sticky header cell', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -240,7 +256,9 @@ describe('useScrollCellIntoView', () => { it('makes no vertical adjustments if the cell is a sticky footer cell', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -265,7 +283,9 @@ describe('useScrollCellIntoView', () => { it('scrolls the grid up if the top side of the cell is out of view', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -277,7 +297,9 @@ describe('useScrollCellIntoView', () => { it('accounts for the sticky header', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -300,7 +322,9 @@ describe('useScrollCellIntoView', () => { }; getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -314,7 +338,9 @@ describe('useScrollCellIntoView', () => { it('makes no vertical adjustments if the cell is a sticky header cell', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, @@ -326,7 +352,9 @@ describe('useScrollCellIntoView', () => { it('makes no vertical adjustments if the cell is a sticky footer cell', () => { getCell.mockReturnValue(cell); - const { scrollCellIntoView } = testCustomHook(() => + const { + return: { scrollCellIntoView }, + } = testCustomHook(() => useScrollCellIntoView({ ...args, outerGridRef: { current: { ...args.outerGridRef.current, ...grid } }, diff --git a/src/test/test_custom_hook.tsx b/src/test/test_custom_hook.tsx index bc51db29da7..4152a3a6920 100644 --- a/src/test/test_custom_hook.tsx +++ b/src/test/test_custom_hook.tsx @@ -15,9 +15,18 @@ export const HookWrapper = (props: { hook?: Function }) => { return
; }; -export const testCustomHook = (hook?: Function): T => { +export const testCustomHook = ( + hook?: Function +): { return: T; getUpdatedState: () => T } => { const wrapper = mount(); - const hookValues: T = wrapper.find('div').prop('hook'); - return hookValues; + const getHookReturn = (): T => { + wrapper.update(); + return wrapper.find('div').prop('hook'); + }; + + return { + return: getHookReturn(), + getUpdatedState: getHookReturn, // Allows consuming tests to get most recent values + }; }; From 100e3146ea08e42d1e29c007bc0527f76af5e1c8 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Fri, 14 Jan 2022 12:34:48 -0800 Subject: [PATCH 02/13] Set up cell popover context - set up initial open/location state, + open/close popover APIs returned to consumers - improve auto props documentation - remove EuiDataGridCellLocation in favor of specifying rowIndex and colIndex (it's less DRY but it's easier for devs to not have to look up EuiDataGridCellLocation from our docs) --- .../body/data_grid_cell_popover.test.tsx | 41 ++- .../datagrid/body/data_grid_cell_popover.tsx | 46 +++- src/components/datagrid/data_grid.test.tsx | 2 + src/components/datagrid/data_grid.tsx | 241 +++++++++--------- src/components/datagrid/data_grid_types.ts | 19 +- 5 files changed, 230 insertions(+), 119 deletions(-) diff --git a/src/components/datagrid/body/data_grid_cell_popover.test.tsx b/src/components/datagrid/body/data_grid_cell_popover.test.tsx index 0e87a303c8e..9ab0d50e2d6 100644 --- a/src/components/datagrid/body/data_grid_cell_popover.test.tsx +++ b/src/components/datagrid/body/data_grid_cell_popover.test.tsx @@ -7,10 +7,49 @@ */ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { shallow } from 'enzyme'; import { keys } from '../../../services'; +import { testCustomHook } from '../../../test'; -import { EuiDataGridCellPopover } from './data_grid_cell_popover'; +import { + useCellPopover, + EuiDataGridCellPopover, +} from './data_grid_cell_popover'; + +describe('useCellPopover', () => { + describe('openCellPopover', () => { + it('sets popoverIsOpen state to true', () => { + const { + return: { cellPopoverContext }, + getUpdatedState, + } = testCustomHook(() => useCellPopover()); + expect(cellPopoverContext.popoverIsOpen).toEqual(false); + + act(() => + cellPopoverContext.openCellPopover({ rowIndex: 0, colIndex: 0 }) + ); + expect(getUpdatedState().cellPopoverContext.popoverIsOpen).toEqual(true); + }); + }); + + describe('closeCellPopover', () => { + it('sets popoverIsOpen state to false', () => { + const { + return: { cellPopoverContext }, + getUpdatedState, + } = testCustomHook(() => useCellPopover()); + + act(() => + cellPopoverContext.openCellPopover({ rowIndex: 0, colIndex: 0 }) + ); + expect(getUpdatedState().cellPopoverContext.popoverIsOpen).toEqual(true); + + act(() => cellPopoverContext.closeCellPopover()); + expect(getUpdatedState().cellPopoverContext.popoverIsOpen).toEqual(false); + }); + }); +}); describe('EuiDataGridCellPopover', () => { const requiredProps = { diff --git a/src/components/datagrid/body/data_grid_cell_popover.tsx b/src/components/datagrid/body/data_grid_cell_popover.tsx index 88eb4a9112d..dedfa31ebc8 100644 --- a/src/components/datagrid/body/data_grid_cell_popover.tsx +++ b/src/components/datagrid/body/data_grid_cell_popover.tsx @@ -5,18 +5,62 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import React, { JSXElementConstructor } from 'react'; + +import React, { + createContext, + useState, + useCallback, + JSXElementConstructor, +} from 'react'; import { keys } from '../../../services'; import { EuiButtonEmpty, EuiButtonEmptyProps } from '../../button/button_empty'; import { EuiFlexGroup, EuiFlexItem } from '../../flex'; import { EuiPopover, EuiPopoverFooter } from '../../popover'; import { + DataGridCellPopoverContextShape, EuiDataGridCellPopoverProps, EuiDataGridCellValueElementProps, EuiDataGridColumnCellAction, EuiDataGridColumnCellActionProps, } from '../data_grid_types'; +export const DataGridCellPopoverContext = createContext< + DataGridCellPopoverContextShape +>({ + popoverIsOpen: false, + openCellLocation: { rowIndex: 0, colIndex: 0 }, + openCellPopover: () => {}, + closeCellPopover: () => {}, +}); + +export const useCellPopover = (): { + cellPopoverContext: DataGridCellPopoverContextShape; +} => { + // Current open state & cell location are handled here + const [popoverIsOpen, setPopoverIsOpen] = useState(false); + const [openCellLocation, setOpenCellLocation] = useState({ + rowIndex: 0, + colIndex: 0, + }); + + const closeCellPopover = useCallback(() => setPopoverIsOpen(false), []); + const openCellPopover = useCallback(({ rowIndex, colIndex }) => { + // TODO: Popover anchor & content + + setOpenCellLocation({ rowIndex, colIndex }); + setPopoverIsOpen(true); + }, []); + + const cellPopoverContext = { + popoverIsOpen, + closeCellPopover, + openCellPopover, + openCellLocation, + }; + + return { cellPopoverContext }; +}; + export function EuiDataGridCellPopover({ anchorContent, cellContentProps, diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 0df619f7de6..55bfb80a3ee 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -2762,6 +2762,8 @@ describe('EuiDataGrid', () => { expect(gridRef.current).toEqual({ setIsFullScreen: expect.any(Function), setFocusedCell: expect.any(Function), + openCellPopover: expect.any(Function), + closeCellPopover: expect.any(Function), }); }); }); diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index dbb0256b477..3e1e0b893d3 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -45,6 +45,10 @@ import { EuiDataGridInMemoryRenderer, } from './utils/in_memory'; import { useHeaderIsInteractive } from './body/header/header_is_interactive'; +import { + DataGridCellPopoverContext, + useCellPopover, +} from './body/data_grid_cell_popover'; import { providedPopoverContents } from './body/popover_utils'; import { computeVisibleRows } from './utils/row_count'; import { EuiDataGridPaginationRenderer } from './utils/data_grid_pagination'; @@ -273,6 +277,11 @@ export const EuiDataGrid = forwardRef( gridItemsRendered, }); + /** + * Cell popover + */ + const { cellPopoverContext } = useCellPopover(); + /** * Toolbar & full-screen */ @@ -302,8 +311,10 @@ export const EuiDataGrid = forwardRef( setFocusedCell: ({ rowIndex, colIndex }) => { focusContext.setFocusedCell([colIndex, rowIndex]); }, + openCellPopover: cellPopoverContext.openCellPopover, + closeCellPopover: cellPopoverContext.closeCellPopover, }), - [focusContext] + [focusContext, cellPopoverContext] ); /** @@ -381,122 +392,124 @@ export const EuiDataGrid = forwardRef( return ( - - -
+ + - {showToolbar && ( - - )} - {inMemory ? ( - - ) : null} -
- -
- {pagination && props['aria-labelledby'] && ( -
+ +
+ {pagination && props['aria-labelledby'] && ( + + )} + {pagination && ( + + )} + - )} - {pagination && ( - - )} - -
-
-
+
+ + + ); } diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 05f563e4e37..151a17cedee 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -195,6 +195,13 @@ export interface DataGridFocusContextShape { focusFirstVisibleInteractiveCell: () => void; } +export interface DataGridCellPopoverContextShape { + popoverIsOpen: boolean; + closeCellPopover(): void; + openCellPopover(args: { rowIndex: number; colIndex: number }): void; + openCellLocation: { rowIndex: number; colIndex: number }; +} + export type CommonGridProps = CommonProps & HTMLAttributes & { /** @@ -301,11 +308,17 @@ export interface EuiDataGridRefProps { * toggles a modal or flyout - focus must be restored to the grid on close * to prevent keyboard or screen reader users from being stranded. */ - setFocusedCell(targetCell: EuiDataGridCellLocation): void; + setFocusedCell: (cell: { rowIndex: number; colIndex: number }) => void; + /** + * Allows manually opening the popover of the specified cell in the grid. + */ + openCellPopover: (cell: { rowIndex: number; colIndex: number }) => void; + /** + * Closes any currently open popovers in the data grid. + */ + closeCellPopover: () => void; } -export type EuiDataGridCellLocation = { rowIndex: number; colIndex: number }; - export interface EuiDataGridColumnResizerProps { columnId: string; columnWidth: number; From 048ff1a37c060251362bd909d740356fa920ed4b Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Fri, 14 Jan 2022 12:58:17 -0800 Subject: [PATCH 03/13] Pass down popoverContext to cells as a prop - I'm not using context here because we're already using this.context for focus, and unfortunately class components can only initialize one context at time using `static contextType` (see https://reactjs.org/docs/context.html#classcontexttype) --- .../data_grid_cell.test.tsx.snap | 11 +++++ .../datagrid/body/data_grid_body.tsx | 5 ++- .../datagrid/body/data_grid_cell.test.tsx | 7 +++ .../datagrid/body/data_grid_cell.tsx | 1 + .../body/data_grid_footer_row.test.tsx | 44 +++++++++++++++++++ .../datagrid/body/data_grid_footer_row.tsx | 5 ++- src/components/datagrid/data_grid_types.ts | 7 ++- 7 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap index 03fc9306cda..14969f39208 100644 --- a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap +++ b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap @@ -7,6 +7,17 @@ exports[`EuiDataGridCell renders 1`] = ` interactiveCellId="someId" isExpandable={true} popoverContent={[Function]} + popoverContext={ + Object { + "closeCellPopover": [MockFunction], + "openCellLocation": Object { + "colIndex": 0, + "rowIndex": 0, + }, + "openCellPopover": [MockFunction], + "popoverIsOpen": false, + } + } renderCellValue={[Function]} rowHeightUtils={ Object { diff --git a/src/components/datagrid/body/data_grid_body.tsx b/src/components/datagrid/body/data_grid_body.tsx index e6912ae358e..6c10315fd05 100644 --- a/src/components/datagrid/body/data_grid_body.tsx +++ b/src/components/datagrid/body/data_grid_body.tsx @@ -28,6 +28,7 @@ import { EuiDataGridCell } from './data_grid_cell'; import { EuiDataGridFooterRow } from './data_grid_footer_row'; import { EuiDataGridHeaderRow } from './header'; import { DefaultColumnFormatter } from './popover_utils'; +import { DataGridCellPopoverContext } from './data_grid_cell_popover'; import { EuiDataGridBodyProps, EuiDataGridRowManager, @@ -70,6 +71,7 @@ export const Cell: FunctionComponent = ({ rowHeightUtils, rowManager, } = data; + const popoverContext = useContext(DataGridCellPopoverContext); const { headerRowHeight } = useContext(DataGridWrapperRowsContext); const { getCorrectRowIndex } = useContext(DataGridSortingContext); @@ -118,7 +120,8 @@ export const Cell: FunctionComponent = ({ rowHeightsOptions, rowHeightUtils, setRowHeight: isFirstColumn ? setRowHeight : undefined, - rowManager: rowManager, + rowManager, + popoverContext, }; if (isLeadingControlColumn) { diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index e74c9efd830..5bd15e7e9de 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -16,6 +16,12 @@ import { DataGridFocusContext } from '../utils/focus'; import { EuiDataGridCell } from './data_grid_cell'; describe('EuiDataGridCell', () => { + const mockPopoverContext = { + popoverIsOpen: false, + openCellLocation: { rowIndex: 0, colIndex: 0 }, + closeCellPopover: jest.fn(), + openCellPopover: jest.fn(), + }; const requiredProps = { rowIndex: 0, visibleRowIndex: 0, @@ -30,6 +36,7 @@ describe('EuiDataGridCell', () => { ), popoverContent: () =>
popover
, + popoverContext: mockPopoverContext, rowHeightUtils: mockRowHeightUtils, }; diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 53c4b5d5db1..06fb6f3523f 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -404,6 +404,7 @@ export class EuiDataGridCell extends Component< width, isExpandable, popoverContent: PopoverContent, + popoverContext, interactiveCellId, columnType, className, diff --git a/src/components/datagrid/body/data_grid_footer_row.test.tsx b/src/components/datagrid/body/data_grid_footer_row.test.tsx index e62f3c5fc1c..a39669e7898 100644 --- a/src/components/datagrid/body/data_grid_footer_row.test.tsx +++ b/src/components/datagrid/body/data_grid_footer_row.test.tsx @@ -42,6 +42,17 @@ describe('EuiDataGridFooterRow', () => { isExpandable={true} key="someColumn-10" popoverContent={[Function]} + popoverContext={ + Object { + "closeCellPopover": [Function], + "openCellLocation": Object { + "colIndex": 0, + "rowIndex": 0, + }, + "openCellPopover": [Function], + "popoverIsOpen": false, + } + } renderCellValue={[Function]} rowIndex={10} visibleRowIndex={10} @@ -56,6 +67,17 @@ describe('EuiDataGridFooterRow', () => { isExpandable={true} key="someColumnWithoutSchema-10" popoverContent={[Function]} + popoverContext={ + Object { + "closeCellPopover": [Function], + "openCellLocation": Object { + "colIndex": 0, + "rowIndex": 0, + }, + "openCellPopover": [Function], + "popoverIsOpen": false, + } + } renderCellValue={[Function]} rowIndex={10} visibleRowIndex={10} @@ -94,6 +116,17 @@ describe('EuiDataGridFooterRow', () => { isExpandable={true} key="someLeadingColumn-10" popoverContent={[Function]} + popoverContext={ + Object { + "closeCellPopover": [Function], + "openCellLocation": Object { + "colIndex": 0, + "rowIndex": 0, + }, + "openCellPopover": [Function], + "popoverIsOpen": false, + } + } renderCellValue={[Function]} rowIndex={10} visibleRowIndex={10} @@ -138,6 +171,17 @@ describe('EuiDataGridFooterRow', () => { isExpandable={true} key="someTrailingColumn-10" popoverContent={[Function]} + popoverContext={ + Object { + "closeCellPopover": [Function], + "openCellLocation": Object { + "colIndex": 0, + "rowIndex": 0, + }, + "openCellPopover": [Function], + "popoverIsOpen": false, + } + } renderCellValue={[Function]} rowIndex={10} visibleRowIndex={10} diff --git a/src/components/datagrid/body/data_grid_footer_row.tsx b/src/components/datagrid/body/data_grid_footer_row.tsx index 716e77c3902..9e32656f689 100644 --- a/src/components/datagrid/body/data_grid_footer_row.tsx +++ b/src/components/datagrid/body/data_grid_footer_row.tsx @@ -7,8 +7,9 @@ */ import classnames from 'classnames'; -import React, { forwardRef, memo } from 'react'; +import React, { forwardRef, memo, useContext } from 'react'; import { EuiDataGridCell } from './data_grid_cell'; +import { DataGridCellPopoverContext } from './data_grid_cell_popover'; import { DefaultColumnFormatter } from './popover_utils'; import { EuiDataGridFooterRowProps } from '../data_grid_types'; @@ -44,11 +45,13 @@ const EuiDataGridFooterRow = memo( _dataTestSubj ); + const popoverContext = useContext(DataGridCellPopoverContext); const sharedCellProps = { rowIndex, visibleRowIndex, interactiveCellId, isExpandable: true, + popoverContext, }; return ( diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 151a17cedee..38d9e382de0 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -428,6 +428,7 @@ export interface EuiDataGridCellProps { isExpandable: boolean; className?: string; popoverContent: EuiDataGridPopoverContent; + popoverContext: DataGridCellPopoverContextShape; renderCellValue: | JSXElementConstructor | ((props: EuiDataGridCellValueElementProps) => ReactNode); @@ -450,7 +451,11 @@ export interface EuiDataGridCellState { export type EuiDataGridCellValueProps = Omit< EuiDataGridCellProps, - 'width' | 'interactiveCellId' | 'popoverContent' | 'rowManager' + | 'width' + | 'interactiveCellId' + | 'popoverContent' + | 'popoverContext' + | 'rowManager' >; export interface EuiDataGridControlColumn { /** From fd25050bc38d6afbed75e47466ece1357fd57d41 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Fri, 14 Jan 2022 14:26:09 -0800 Subject: [PATCH 04/13] Remove internal cell popoverIsOpen state - This should now be handled by the overarching context state, and the cell should simply react to it or update it (similar to how focusContext works) + add new var for hasCellButtons + add unit tests for isFocusedCell alongside isPopoverOpen (since both methods perform similar functions) --- .../datagrid/body/data_grid_cell.test.tsx | 125 +++++++++++++++--- .../datagrid/body/data_grid_cell.tsx | 59 ++++++--- src/components/datagrid/data_grid_types.ts | 1 - 3 files changed, 149 insertions(+), 36 deletions(-) diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index 5bd15e7e9de..ef7fcdd1e5d 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -58,19 +58,24 @@ describe('EuiDataGridCell', () => { }} /> ); - component.setState({ popoverIsOpen: true }); + component.setState({ enableInteractions: true }); - const cellButtons = component.find('EuiDataGridCellButtons'); - expect(component.find('EuiDataGridCellButtons')).toHaveLength(1); + const getCellButtons = () => component.find('EuiDataGridCellButtons'); + expect(getCellButtons()).toHaveLength(1); - // Should handle re-closing the popover correctly + // Should handle opening the popover + (getCellButtons().prop('onExpandClick') as Function)(); + expect(mockPopoverContext.openCellPopover).toHaveBeenCalled(); - (cellButtons.prop('onExpandClick') as Function)(); - expect(component.state('popoverIsOpen')).toEqual(false); - - component.setState({ popoverIsOpen: true }); - (cellButtons.prop('closePopover') as Function)(); - expect(component.state('popoverIsOpen')).toEqual(false); + // Should handle closing the popover + component.setProps({ + isExpandable: true, + popoverContext: { ...mockPopoverContext, popoverIsOpen: true }, + }); + (getCellButtons().prop('onExpandClick') as Function)(); + expect(mockPopoverContext.closeCellPopover).toHaveBeenCalledTimes(1); + (getCellButtons().prop('closePopover') as Function)(); + expect(mockPopoverContext.closeCellPopover).toHaveBeenCalledTimes(2); }); describe('shouldComponentUpdate', () => { @@ -139,9 +144,6 @@ describe('EuiDataGridCell', () => { it('cellProps', () => { component.setState({ cellProps: {} }); }); - it('popoverIsOpen', () => { - component.setState({ popoverIsOpen: true }); - }); it('isEntered', () => { component.setState({ isEntered: true }); }); @@ -241,6 +243,85 @@ describe('EuiDataGridCell', () => { }); }); + describe('isFocusedCell', () => { + it("returns true if the current focusedCell[x,y] matches the cell's colIndex and visibleRowIndex", () => { + const component = mount( + + + + ); + + expect((component.instance() as any).isFocusedCell()).toEqual(true); + }); + + it("returns false if the current focusedCell[x,y] does not match the cell's colIndex and visibleRowIndex", () => { + const component = mount( + + + + ); + + expect((component.instance() as any).isFocusedCell()).toEqual(false); + }); + }); + + describe('isPopoverOpen', () => { + const props = { + ...requiredProps, + popoverContext: { + ...mockPopoverContext, + popoverIsOpen: true, + openCellLocation: { colIndex: 1, rowIndex: 2 }, + }, + colIndex: 1, + visibleRowIndex: 2, + isExpandable: true, + }; + + it('returns true if the cell is expandable, the popover is open, and the cell location matches', () => { + const component = mount(); + + expect((component.instance() as any).isPopoverOpen()).toEqual(true); + }); + + it('returns false if popoverContext.popoverIsOpen is false', () => { + const component = mount( + + ); + expect((component.instance() as any).isPopoverOpen()).toEqual(false); + }); + + it("returns false if popoverContext.openCellLocation does not match the cell's colIndex and visibleRowIndex", () => { + const component = mount( + + ); + expect((component.instance() as any).isPopoverOpen()).toEqual(false); + }); + + it('returns false if the cell is not expandable, and sets popover state to closed', () => { + const component = mount( + + ); + expect((component.instance() as any).isPopoverOpen()).toEqual(false); + expect(mockPopoverContext.closeCellPopover).toHaveBeenCalled(); + }); + }); + // TODO: Test ResizeObserver logic in Cypress alongside Jest describe('row height logic & resize observers', () => { describe('recalculateAutoHeight', () => { @@ -383,7 +464,22 @@ describe('EuiDataGridCell', () => { component.simulate('keyDown', { preventDefault, key: keys.ENTER }); component.simulate('keyDown', { preventDefault, key: keys.F2 }); - expect(component.state('popoverIsOpen')).toEqual(true); + expect(mockPopoverContext.openCellPopover).toHaveBeenCalledWith({ + rowIndex: 0, + colIndex: 0, + }); + expect(mockPopoverContext.openCellPopover).toHaveBeenCalledTimes(2); + + // If the cell popover is open, the nothing should happen + jest.clearAllMocks(); + component.setProps({ + popoverContext: { ...mockPopoverContext, popoverIsOpen: true }, + }); + + component.simulate('keyDown', { preventDefault, key: keys.ENTER }); + component.simulate('keyDown', { preventDefault, key: keys.F2 }); + + expect(mockPopoverContext.openCellPopover).not.toHaveBeenCalled(); }); it('when cell is not expandable', () => { @@ -437,7 +533,6 @@ describe('EuiDataGridCell', () => { }} /> ); - component.setState({ popoverIsOpen: true }); expect( component.find('.euiDataGridRowCell__contentByHeight').exists() diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 06fb6f3523f..94fac9c4d30 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -118,7 +118,6 @@ export class EuiDataGridCell extends Component< cellContentsRef: HTMLDivElement | null = null; state: EuiDataGridCellState = { cellProps: {}, - popoverIsOpen: false, isFocused: false, isEntered: false, enableInteractions: false, @@ -312,7 +311,6 @@ export class EuiDataGridCell extends Component< } if (nextState.cellProps !== this.state.cellProps) return true; - if (nextState.popoverIsOpen !== this.state.popoverIsOpen) return true; if (nextState.isEntered !== this.state.isEntered) return true; if (nextState.isFocused !== this.state.isFocused) return true; if (nextState.enableInteractions !== this.state.enableInteractions) @@ -395,8 +393,25 @@ export class EuiDataGridCell extends Component< } }; - closePopover = () => { - this.setState({ popoverIsOpen: false }); + isPopoverOpen = () => { + const { isExpandable, popoverContext } = this.props; + const { popoverIsOpen, openCellLocation } = popoverContext; + + if ( + popoverIsOpen && + openCellLocation.colIndex === this.props.colIndex && + openCellLocation.rowIndex === this.props.visibleRowIndex + ) { + if (isExpandable) { + return true; + } else { + // If `openCellPopover` was somehow called on this cell but it's not + // supposed to be expandable, we should do nothing and set popoverIsOpen + // state back to false + popoverContext.closeCellPopover(); + } + } + return false; }; render() { @@ -404,7 +419,7 @@ export class EuiDataGridCell extends Component< width, isExpandable, popoverContent: PopoverContent, - popoverContext, + popoverContext: { closeCellPopover, openCellPopover }, interactiveCellId, columnType, className, @@ -417,17 +432,19 @@ export class EuiDataGridCell extends Component< } = this.props; const { rowIndex, colIndex } = rest; + const popoverIsOpen = this.isPopoverOpen(); + const hasCellButtons = isExpandable || column?.cellActions; const showCellButtons = this.state.isFocused || this.state.isEntered || this.state.enableInteractions || - this.state.popoverIsOpen; + popoverIsOpen; const cellClasses = classNames( 'euiDataGridRowCell', { [`euiDataGridRowCell--${columnType}`]: columnType, - ['euiDataGridRowCell--open']: this.state.popoverIsOpen, + ['euiDataGridRowCell--open']: popoverIsOpen, }, className ); @@ -450,14 +467,14 @@ export class EuiDataGridCell extends Component< const handleCellKeyDown = (event: KeyboardEvent) => { if (isExpandable) { - if (this.state.popoverIsOpen) { + if (popoverIsOpen) { return; } switch (event.key) { case keys.ENTER: case keys.F2: event.preventDefault(); - this.setState({ popoverIsOpen: true }); + openCellPopover({ rowIndex, colIndex }); break; } } else { @@ -516,7 +533,7 @@ export class EuiDataGridCell extends Component< column, columnType: columnType, isExpandable, - isExpanded: this.state.popoverIsOpen, + isExpanded: popoverIsOpen, isDetails: false, setCellContentsRef: this.setCellContentsRef, rowHeightsOptions, @@ -547,7 +564,7 @@ export class EuiDataGridCell extends Component< ); - if (isExpandable || (column && column.cellActions)) { + if (hasCellButtons) { if (showCellButtons) { anchorContent = (
@@ -558,12 +575,14 @@ export class EuiDataGridCell extends Component< rowIndex={rowIndex} colIndex={colIndex} column={column} - popoverIsOpen={this.state.popoverIsOpen} - closePopover={this.closePopover} + popoverIsOpen={popoverIsOpen} + closePopover={closeCellPopover} onExpandClick={() => { - this.setState(({ popoverIsOpen }) => ({ - popoverIsOpen: !popoverIsOpen, - })); + if (popoverIsOpen) { + closeCellPopover(); + } else { + openCellPopover({ rowIndex, colIndex }); + } }} />
@@ -580,8 +599,8 @@ export class EuiDataGridCell extends Component< } let innerContent = anchorContent; - if (isExpandable || (column && column.cellActions)) { - if (this.state.popoverIsOpen) { + if (hasCellButtons) { + if (popoverIsOpen) { innerContent = (
(this.popoverPanelRef.current = ref)} - popoverIsOpen={this.state.popoverIsOpen} + popoverIsOpen={popoverIsOpen} rowIndex={rowIndex} colIndex={colIndex} renderCellValue={rest.renderCellValue} diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 38d9e382de0..59de5d073b9 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -442,7 +442,6 @@ export interface EuiDataGridCellProps { export interface EuiDataGridCellState { cellProps: CommonProps & HTMLAttributes; - popoverIsOpen: boolean; // is expansion popover open 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 From 348d27d8ef1923f02d367861a38bd9bab0554844 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Fri, 14 Jan 2022 14:37:17 -0800 Subject: [PATCH 05/13] Update cell popovers to set the popover anchor & content - content is TODO, will likely be easier to compare when cleaning it up/moving it all at once --- .../data_grid_cell.test.tsx.snap | 2 + .../datagrid/body/data_grid_cell.test.tsx | 39 +++++++++++++++++++ .../datagrid/body/data_grid_cell.tsx | 36 +++++++++++++++++ .../datagrid/body/data_grid_cell_popover.tsx | 11 +++++- .../body/data_grid_footer_row.test.tsx | 8 ++++ src/components/datagrid/data_grid_types.ts | 2 + 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap index 14969f39208..428d926b720 100644 --- a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap +++ b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap @@ -16,6 +16,8 @@ exports[`EuiDataGridCell renders 1`] = ` }, "openCellPopover": [MockFunction], "popoverIsOpen": false, + "setPopoverAnchor": [MockFunction], + "setPopoverContent": [MockFunction], } } renderCellValue={[Function]} diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index ef7fcdd1e5d..cdaa235a348 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -21,6 +21,8 @@ describe('EuiDataGridCell', () => { openCellLocation: { rowIndex: 0, colIndex: 0 }, closeCellPopover: jest.fn(), openCellPopover: jest.fn(), + setPopoverAnchor: jest.fn(), + setPopoverContent: jest.fn(), }; const requiredProps = { rowIndex: 0, @@ -129,6 +131,19 @@ describe('EuiDataGridCell', () => { it('popoverContent', () => { component.setProps({ popoverContent: () =>
test
}); }); + it('popoverContext.popoverIsOpen', () => { + component.setProps({ + popoverContext: { ...mockPopoverContext, popoverIsOpen: true }, + }); + }); + it('popoverContext.openCellLocation', () => { + component.setProps({ + popoverContext: { + ...mockPopoverContext, + openCellLocation: { rowIndex: 5, colIndex: 5 }, + }, + }); + }); it('style', () => { component.setProps({ style: {} }); component.setProps({ style: { top: 0 } }); @@ -173,6 +188,18 @@ describe('EuiDataGridCell', () => { component.setProps({ columnId: 'newColumnId' }); expect(setState).toHaveBeenCalledWith({ cellProps: {} }); }); + + it("handles the cell popover by forwarding the cell's DOM node and contents to the parent popover context", () => { + const component = mount(); + expect(mockPopoverContext.setPopoverAnchor).not.toHaveBeenCalled(); + expect(mockPopoverContext.setPopoverContent).not.toHaveBeenCalled(); + + component.setProps({ + popoverContext: { ...mockPopoverContext, popoverIsOpen: true }, + }); + expect(mockPopoverContext.setPopoverAnchor).toHaveBeenCalled(); + expect(mockPopoverContext.setPopoverContent).toHaveBeenCalled(); + }); }); describe('componentDidMount', () => { @@ -206,6 +233,18 @@ describe('EuiDataGridCell', () => { true ); }); + + it('handles the cell popover if the current cell should have an open popover', () => { + mount( + + ); + + expect(mockPopoverContext.setPopoverAnchor).toHaveBeenCalled(); + expect(mockPopoverContext.setPopoverContent).toHaveBeenCalled(); + }); }); describe('componentWillUnmount', () => { diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 94fac9c4d30..acf60ffea8b 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -239,6 +239,10 @@ export class EuiDataGridCell extends Component< this.onFocusUpdate(true, true); this.context.setIsFocusedCellInView(true); } + + // Check if popover should be open on mount (typically only occurs if + // openCellPopover() is manually called on a location that's out of view) + this.handleCellPopover(); } isFocusedCell = () => { @@ -277,6 +281,15 @@ export class EuiDataGridCell extends Component< this.recalculateLineHeight(); } + if ( + this.props.popoverContext.popoverIsOpen !== + prevProps.popoverContext.popoverIsOpen || + this.props.popoverContext.openCellLocation !== + prevProps.popoverContext.openCellLocation + ) { + this.handleCellPopover(); + } + if (this.props.columnId !== prevProps.columnId) { this.setCellProps({}); } @@ -298,6 +311,13 @@ export class EuiDataGridCell extends Component< if (nextProps.interactiveCellId !== this.props.interactiveCellId) return true; if (nextProps.popoverContent !== this.props.popoverContent) return true; + if ( + nextProps.popoverContext.popoverIsOpen !== + this.props.popoverContext.popoverIsOpen || + nextProps.popoverContext.openCellLocation !== + this.props.popoverContext.openCellLocation + ) + return true; // respond to adjusted position & dimensions if (nextProps.style) { @@ -414,6 +434,22 @@ export class EuiDataGridCell extends Component< return false; }; + handleCellPopover = () => { + if (this.isPopoverOpen()) { + const { setPopoverAnchor, setPopoverContent } = this.props.popoverContext; + + // Set popover anchor + const cellAnchorEl = this.cellRef.current!.querySelector( + '.euiDataGridRowCell__expandFlex' // Anchor class + )!; + setPopoverAnchor(cellAnchorEl); + + // Set popover contents with cell content + const popoverContent = <>TODO, testing; + setPopoverContent(popoverContent); + } + }; + render() { const { width, diff --git a/src/components/datagrid/body/data_grid_cell_popover.tsx b/src/components/datagrid/body/data_grid_cell_popover.tsx index dedfa31ebc8..05f5e0441eb 100644 --- a/src/components/datagrid/body/data_grid_cell_popover.tsx +++ b/src/components/datagrid/body/data_grid_cell_popover.tsx @@ -31,6 +31,8 @@ export const DataGridCellPopoverContext = createContext< openCellLocation: { rowIndex: 0, colIndex: 0 }, openCellPopover: () => {}, closeCellPopover: () => {}, + setPopoverAnchor: () => {}, + setPopoverContent: () => {}, }); export const useCellPopover = (): { @@ -42,11 +44,14 @@ export const useCellPopover = (): { rowIndex: 0, colIndex: 0, }); + // Popover anchor & content are passed by individual `EuiDataGridCell`s + const [popoverAnchor, setPopoverAnchor] = useState(null); + const [popoverContent, setPopoverContent] = useState(); const closeCellPopover = useCallback(() => setPopoverIsOpen(false), []); const openCellPopover = useCallback(({ rowIndex, colIndex }) => { - // TODO: Popover anchor & content - + // Toggle our open cell state, which causes EuiDataGridCells to react/check + // if they should be the open popover and send their anchor+content if so setOpenCellLocation({ rowIndex, colIndex }); setPopoverIsOpen(true); }, []); @@ -56,6 +61,8 @@ export const useCellPopover = (): { closeCellPopover, openCellPopover, openCellLocation, + setPopoverAnchor, + setPopoverContent, }; return { cellPopoverContext }; diff --git a/src/components/datagrid/body/data_grid_footer_row.test.tsx b/src/components/datagrid/body/data_grid_footer_row.test.tsx index a39669e7898..4f7ee2b8b59 100644 --- a/src/components/datagrid/body/data_grid_footer_row.test.tsx +++ b/src/components/datagrid/body/data_grid_footer_row.test.tsx @@ -51,6 +51,8 @@ describe('EuiDataGridFooterRow', () => { }, "openCellPopover": [Function], "popoverIsOpen": false, + "setPopoverAnchor": [Function], + "setPopoverContent": [Function], } } renderCellValue={[Function]} @@ -76,6 +78,8 @@ describe('EuiDataGridFooterRow', () => { }, "openCellPopover": [Function], "popoverIsOpen": false, + "setPopoverAnchor": [Function], + "setPopoverContent": [Function], } } renderCellValue={[Function]} @@ -125,6 +129,8 @@ describe('EuiDataGridFooterRow', () => { }, "openCellPopover": [Function], "popoverIsOpen": false, + "setPopoverAnchor": [Function], + "setPopoverContent": [Function], } } renderCellValue={[Function]} @@ -180,6 +186,8 @@ describe('EuiDataGridFooterRow', () => { }, "openCellPopover": [Function], "popoverIsOpen": false, + "setPopoverAnchor": [Function], + "setPopoverContent": [Function], } } renderCellValue={[Function]} diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts index 59de5d073b9..5271cb9cadc 100644 --- a/src/components/datagrid/data_grid_types.ts +++ b/src/components/datagrid/data_grid_types.ts @@ -200,6 +200,8 @@ export interface DataGridCellPopoverContextShape { closeCellPopover(): void; openCellPopover(args: { rowIndex: number; colIndex: number }): void; openCellLocation: { rowIndex: number; colIndex: number }; + setPopoverAnchor(anchor: HTMLElement): void; + setPopoverContent(content: ReactNode): void; } export type CommonGridProps = CommonProps & From ff5207903c64c94fe61f927f76cfb7f69ca6eb21 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Fri, 14 Jan 2022 14:51:06 -0800 Subject: [PATCH 06/13] Refactor EuiDataGridCellPopover - It should no longer exist as a reusable component that belongs to every single cell, but instead as a single popover that exists at the top grid level and moves from cell to cell - I cleaned and split up the JSX for the popover (e.g. moving popover actions to data_grid_cell_buttons, where it feels like it belongs more) and think it's significantly more DRY now - note the entire `anchorContent` branch removed from EuiDataGridCell that is no longer necessary - Note that due to this change, we now have to mock EuiWrappingPopover in EuiDataGrid tests, as we see failures otherwise --- .../data_grid_cell.test.tsx.snap | 34 +++ .../datagrid/body/data_grid_cell.test.tsx | 19 +- .../datagrid/body/data_grid_cell.tsx | 88 +++--- .../body/data_grid_cell_buttons.test.tsx | 63 +++- .../datagrid/body/data_grid_cell_buttons.tsx | 44 +++ .../body/data_grid_cell_popover.test.tsx | 275 ++++++++---------- .../datagrid/body/data_grid_cell_popover.tsx | 93 +----- src/components/datagrid/data_grid.test.tsx | 8 + src/components/datagrid/data_grid.tsx | 3 +- src/components/datagrid/data_grid_types.ts | 17 +- 10 files changed, 351 insertions(+), 293 deletions(-) diff --git a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap index 428d926b720..3f57f59cf0a 100644 --- a/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap +++ b/src/components/datagrid/body/__snapshots__/data_grid_cell.test.tsx.snap @@ -167,3 +167,37 @@ exports[`EuiDataGridCell renders 1`] = `
`; + +exports[`EuiDataGridCell componentDidUpdate handles the cell popover by forwarding the cell's DOM node and contents to the parent popover context 1`] = ` +Array [ +
+
+ + +
+
, +
+
+
+
+
+
, +] +`; diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index cdaa235a348..4ec148fbdbc 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { mount, ReactWrapper } from 'enzyme'; +import { mount, render, ReactWrapper } from 'enzyme'; import { keys } from '../../../services'; import { mockRowHeightUtils } from '../utils/__mocks__/row_heights'; import { mockFocusContext } from '../utils/__mocks__/focus_context'; @@ -37,7 +37,9 @@ describe('EuiDataGridCell', () => { ), - popoverContent: () =>
popover
, + popoverContent: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), popoverContext: mockPopoverContext, rowHeightUtils: mockRowHeightUtils, }; @@ -190,7 +192,12 @@ describe('EuiDataGridCell', () => { }); it("handles the cell popover by forwarding the cell's DOM node and contents to the parent popover context", () => { - const component = mount(); + const component = mount( +