From c3594307c078cb98bb933b8855202005aa5110ee Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Mon, 25 Oct 2021 13:24:23 -0700 Subject: [PATCH] [WIP] Convert lineCount to use height cache+observer --- src-docs/src/views/datagrid/datagrid.js | 1 + .../datagrid/__mocks__/row_height_utils.ts | 3 +- .../datagrid/body/data_grid_body.tsx | 28 ++--- .../datagrid/body/data_grid_cell.test.tsx | 6 +- .../datagrid/body/data_grid_cell.tsx | 13 +-- src/components/datagrid/row_height_utils.ts | 102 ++++++------------ 6 files changed, 54 insertions(+), 99 deletions(-) diff --git a/src-docs/src/views/datagrid/datagrid.js b/src-docs/src/views/datagrid/datagrid.js index d2780c5d3b52..f6e8bb8ba667 100644 --- a/src-docs/src/views/datagrid/datagrid.js +++ b/src-docs/src/views/datagrid/datagrid.js @@ -418,6 +418,7 @@ export default () => { onChangePage: onChangePage, }} onColumnResize={onColumnResize.current} + rowHeightsOptions={{ defaultHeight: { lineCount: 2 } }} /> ); diff --git a/src/components/datagrid/__mocks__/row_height_utils.ts b/src/components/datagrid/__mocks__/row_height_utils.ts index dac8430c3abc..46f7ccbb48c6 100644 --- a/src/components/datagrid/__mocks__/row_height_utils.ts +++ b/src/components/datagrid/__mocks__/row_height_utils.ts @@ -20,7 +20,7 @@ export const mockRowHeightUtils = ({ flexGrow: 1, })), isDefinedHeight: jest.fn(() => true), - isAutoHeight: jest.fn(() => false), + shouldCacheCellHeight: jest.fn(() => false), setRowHeight: jest.fn(), getRowHeight: jest.fn(() => 32), getFont: jest.fn(() => null), @@ -29,6 +29,7 @@ export const mockRowHeightUtils = ({ (currentRowHeight: number, cachedRowHeight: number) => currentRowHeight === cachedRowHeight ), + getRowHeightOption: jest.fn(), getCalculatedHeight: jest.fn( (heightOption: EuiDataGridRowHeightOption, defaultHeight: number) => { if (typeof heightOption === 'object') { diff --git a/src/components/datagrid/body/data_grid_body.tsx b/src/components/datagrid/body/data_grid_body.tsx index ef05ec122128..6e26c937303b 100644 --- a/src/components/datagrid/body/data_grid_body.tsx +++ b/src/components/datagrid/body/data_grid_body.tsx @@ -28,7 +28,7 @@ import { useMutationObserver, } from '../../observer/mutation_observer'; import { useResizeObserver } from '../../observer/resize_observer'; -import { DEFAULT_ROW_HEIGHT, AUTO_HEIGHT } from '../row_height_utils'; +import { DEFAULT_ROW_HEIGHT } from '../row_height_utils'; import { EuiDataGridCell } from './data_grid_cell'; import { DataGridSortingContext, @@ -546,22 +546,16 @@ export const EuiDataGridBody: FunctionComponent = ( const correctRowIndex = getCorrectRowIndex(rowIndex); let height; - if (rowHeightsOptions) { - if (rowHeightsOptions.rowHeights) { - const initialHeight = rowHeightsOptions.rowHeights[correctRowIndex]; - - if (initialHeight) { - height = rowHeightUtils.getCalculatedHeight( - initialHeight, - minRowHeight, - correctRowIndex - ); - } - } - - if (!height && rowHeightsOptions.defaultHeight === AUTO_HEIGHT) { - height = rowHeightUtils.getRowHeight(correctRowIndex); - } + const rowHeightOption = rowHeightUtils.getRowHeightOption( + correctRowIndex, + rowHeightsOptions + ); + if (rowHeightOption) { + height = rowHeightUtils.getCalculatedHeight( + rowHeightOption, + minRowHeight, + correctRowIndex + ); } return height || defaultHeight; diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx index 7b8e9592469c..a4fa7003f17c 100644 --- a/src/components/datagrid/body/data_grid_cell.test.tsx +++ b/src/components/datagrid/body/data_grid_cell.test.tsx @@ -168,8 +168,8 @@ describe('EuiDataGridCell', () => { describe('componentDidUpdate', () => { it('recalculates row height on every update', () => { - const { isAutoHeight, setRowHeight } = mockRowHeightUtils; - (isAutoHeight as jest.Mock).mockImplementation(() => true); + const { shouldCacheCellHeight, setRowHeight } = mockRowHeightUtils; + (shouldCacheCellHeight as jest.Mock).mockImplementation(() => true); const component = mountEuiDataGridCellWithContext({ rowHeightsOptions: { defaultHeight: 'auto' }, @@ -179,7 +179,7 @@ describe('EuiDataGridCell', () => { component.setProps({ rowIndex: 2 }); // Trigger any update expect(setRowHeight).toHaveBeenCalled(); - (isAutoHeight as jest.Mock).mockRestore(); + (shouldCacheCellHeight as jest.Mock).mockRestore(); }); it('resets cell props when the cell columnId changes', () => { diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx index 0260120b12f1..3b27753810af 100644 --- a/src/components/datagrid/body/data_grid_cell.tsx +++ b/src/components/datagrid/body/data_grid_cell.tsx @@ -201,16 +201,7 @@ export class EuiDataGridCell extends Component< if (cellRef && getRowHeight && rowHeightUtils && rowHeightsOptions) { const { rowIndex, colIndex, visibleRowIndex } = this.props; - const isAutoHeight = rowHeightUtils.isAutoHeight( - rowIndex, - rowHeightsOptions - ); - const isHeightSame = rowHeightUtils.compareHeights( - cellRef.offsetHeight, - getRowHeight(rowIndex) - ); - - if (isAutoHeight && !isHeightSame) { + if (rowHeightUtils.shouldCacheCellHeight(rowIndex, rowHeightsOptions)) { rowHeightUtils.setRowHeight( rowIndex, colIndex, @@ -316,7 +307,7 @@ export class EuiDataGridCell extends Component< hasResizeObserver && rowHeightUtils && rowHeightsOptions && - rowHeightUtils.isAutoHeight(rowIndex, rowHeightsOptions) + rowHeightUtils.shouldCacheCellHeight(rowIndex, rowHeightsOptions) ) { if (ref) { const { colIndex, visibleRowIndex } = this.props; diff --git a/src/components/datagrid/row_height_utils.ts b/src/components/datagrid/row_height_utils.ts index 11b2f0f48c47..63073b9a921b 100644 --- a/src/components/datagrid/row_height_utils.ts +++ b/src/components/datagrid/row_height_utils.ts @@ -11,27 +11,16 @@ import type { VariableSizeGrid as Grid } from 'react-window'; import { isObject, isNumber } from '../../services/predicate'; import { EuiDataGridStyleCellPaddings, - EuiDataGridStyleFontSizes, EuiDataGridStyle, EuiDataGridRowHeightOption, EuiDataGridRowHeightsOptions, } from './data_grid_types'; // TODO: Once JS variables are available, use them here instead of hard-coded maps -const cellPaddingsMap: Record = { - s: '4px', - m: '6px', - l: '8px', -}; -const fontSizesMap: Record = { - s: '12px', - m: '14px', - l: '16px', -}; -const lineHeightsMap: Record = { - s: '1.14286rem', - m: '1.71429rem', - l: '1.71429rem', +const cellPaddingsMap: Record = { + s: 4, + m: 6, + l: 8, }; export const AUTO_HEIGHT = 'auto'; @@ -43,11 +32,9 @@ export class RowHeightUtils { private styles: { paddingTop: number; paddingBottom: number; - lineHeight: number; } = { paddingTop: 0, paddingBottom: 0, - lineHeight: 1, }; private heightsCache = new Map>(); private timerId: any; @@ -107,21 +94,25 @@ export class RowHeightUtils { this.heightsCache.clear(); } - isAutoHeight( + shouldCacheCellHeight( rowIndex: number, rowHeightsOptions: EuiDataGridRowHeightsOptions ) { - if (rowHeightsOptions.rowHeights?.[rowIndex] === AUTO_HEIGHT) { + const height = this.getRowHeightOption(rowIndex, rowHeightsOptions); + + if (height === AUTO_HEIGHT) { return true; } - - if (rowHeightsOptions.defaultHeight === AUTO_HEIGHT) { + if (this.isLineCount(height)) { return true; } - return false; } + isLineCount(option?: EuiDataGridRowHeightOption) { + return isObject(option) && option.lineCount; + } + isDefinedHeight( rowIndex: number, rowHeightsOptions: EuiDataGridRowHeightsOptions @@ -136,42 +127,27 @@ export class RowHeightUtils { return false; } - computeStylesForGridCell( - gridStyles: EuiDataGridStyle, - lineHeight: string | undefined - ) { - const fakeCell = document.createElement('div'); - fakeCell.style.padding = cellPaddingsMap[gridStyles.cellPadding!]; - fakeCell.style.fontSize = fontSizesMap[gridStyles.fontSize!]; - fakeCell.style.lineHeight = - lineHeight || lineHeightsMap[gridStyles.fontSize!]; - - document.body.appendChild(fakeCell); - const allStyles = getComputedStyle(fakeCell); + computeStylesForGridCell(gridStyles: EuiDataGridStyle) { this.styles = { - paddingTop: this.getNumberFromPx(allStyles.paddingTop), - paddingBottom: this.getNumberFromPx(allStyles.paddingBottom), - lineHeight: this.getNumberFromPx(allStyles.lineHeight), + paddingTop: cellPaddingsMap[gridStyles.cellPadding!], + paddingBottom: cellPaddingsMap[gridStyles.cellPadding!], }; - document.body.removeChild(fakeCell); // we need clear the height cache so that it recalculates heights for new styles this.clearHeightsCache(); } - getNumberFromPx(style?: string) { - return style ? parseInt(style.replace('px', ''), 10) : 0; - } - getComputedCellStyles() { return this.styles; } - calculateHeightForLineCount(lineCount: number) { - return Math.ceil( - lineCount * this.styles.lineHeight + - this.styles.paddingTop + - this.styles.paddingBottom + getRowHeightOption( + rowIndex: number, + rowHeightsOptions?: EuiDataGridRowHeightsOptions + ) { + return ( + rowHeightsOptions?.rowHeights?.[rowIndex] ?? + rowHeightsOptions?.defaultHeight ); } @@ -180,21 +156,19 @@ export class RowHeightUtils { defaultHeight: number, rowIndex?: number ) { - if (isObject(heightOption)) { - if (heightOption.lineCount) { - return this.calculateHeightForLineCount(heightOption.lineCount); - } - - if (heightOption.height) { - return Math.max(heightOption.height, defaultHeight); - } + if (isObject(heightOption) && heightOption.height) { + return Math.max(heightOption.height, defaultHeight); } if (heightOption && isNumber(heightOption)) { return Math.max(heightOption, defaultHeight); } - if (heightOption === AUTO_HEIGHT && rowIndex) { + if (this.isLineCount(heightOption) && rowIndex != null) { + return this.getRowHeight(rowIndex); + } + + if (heightOption === AUTO_HEIGHT && rowIndex != null) { return this.getRowHeight(rowIndex); } @@ -205,23 +179,17 @@ export class RowHeightUtils { rowHeightsOptions: EuiDataGridRowHeightsOptions, rowIndex: number ): CSSProperties => { - if (this.isAutoHeight(rowIndex, rowHeightsOptions)) { - return {}; - } + const height = this.getRowHeightOption(rowIndex, rowHeightsOptions); - let initialHeight = - rowHeightsOptions.rowHeights && rowHeightsOptions.rowHeights[rowIndex]; - - if (!initialHeight) { - initialHeight = rowHeightsOptions.defaultHeight; + if (height === AUTO_HEIGHT) { + return {}; } - if (isObject(initialHeight) && initialHeight.lineCount) { + if (this.isLineCount(height)) { return { - WebkitLineClamp: initialHeight.lineCount, + WebkitLineClamp: (height as { lineCount: number }).lineCount, display: '-webkit-box', WebkitBoxOrient: 'vertical', - height: '100%', overflow: 'hidden', }; }