Skip to content

Commit

Permalink
[WIP] Convert lineCount to use height cache+observer
Browse files Browse the repository at this point in the history
  • Loading branch information
cee-chen committed Oct 25, 2021
1 parent 3e833d3 commit c359430
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 99 deletions.
1 change: 1 addition & 0 deletions src-docs/src/views/datagrid/datagrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ export default () => {
onChangePage: onChangePage,
}}
onColumnResize={onColumnResize.current}
rowHeightsOptions={{ defaultHeight: { lineCount: 2 } }}
/>
</DataContext.Provider>
);
Expand Down
3 changes: 2 additions & 1 deletion src/components/datagrid/__mocks__/row_height_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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') {
Expand Down
28 changes: 11 additions & 17 deletions src/components/datagrid/body/data_grid_body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -546,22 +546,16 @@ export const EuiDataGridBody: FunctionComponent<EuiDataGridBodyProps> = (
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;
Expand Down
6 changes: 3 additions & 3 deletions src/components/datagrid/body/data_grid_cell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand All @@ -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', () => {
Expand Down
13 changes: 2 additions & 11 deletions src/components/datagrid/body/data_grid_cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
102 changes: 35 additions & 67 deletions src/components/datagrid/row_height_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<EuiDataGridStyleCellPaddings, string> = {
s: '4px',
m: '6px',
l: '8px',
};
const fontSizesMap: Record<EuiDataGridStyleFontSizes, string> = {
s: '12px',
m: '14px',
l: '16px',
};
const lineHeightsMap: Record<EuiDataGridStyleFontSizes, string> = {
s: '1.14286rem',
m: '1.71429rem',
l: '1.71429rem',
const cellPaddingsMap: Record<EuiDataGridStyleCellPaddings, number> = {
s: 4,
m: 6,
l: 8,
};

export const AUTO_HEIGHT = 'auto';
Expand All @@ -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<number, Record<number, number>>();
private timerId: any;
Expand Down Expand Up @@ -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
Expand All @@ -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
);
}

Expand All @@ -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);
}

Expand All @@ -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',
};
}
Expand Down

0 comments on commit c359430

Please sign in to comment.