diff --git a/CHANGELOG.md b/CHANGELOG.md index c59462f7794..f3fe39984ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Fixed invalid color entry passed to `EuiBadge` color prop ([#4481](https://github.com/elastic/eui/pull/4481)) - Fixed `EuiCodeBlock` focus-state if content overflows ([#4463]https://github.com/elastic/eui/pull/4463) +- Fixed issues in `EuiDataGrid` around unnecessary scroll bars and container heights not updating ([#4468](https://github.com/elastic/eui/pull/4468)) ## [`31.5.0`](https://github.com/elastic/eui/tree/v31.5.0) diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx index 0c244b428d7..28b00f9b4c1 100644 --- a/src/components/datagrid/data_grid.tsx +++ b/src/components/datagrid/data_grid.tsx @@ -59,7 +59,7 @@ import { import { EuiDataGridCellProps } from './data_grid_cell'; import { EuiButtonEmpty } from '../button'; import { keys, htmlIdGenerator } from '../../services'; -import { EuiDataGridBody } from './data_grid_body'; +import { EuiDataGridBody, VIRTUALIZED_CONTAINER_CLASS } from './data_grid_body'; import { useDataGridColumnSelector } from './column_selector'; import { useDataGridStyleSelector, startingStyles } from './style_selector'; import { EuiTablePagination } from '../table/table_pagination'; @@ -297,6 +297,47 @@ function renderPagination(props: EuiDataGridProps, controls: string) { ); } +/** + * Returns the size of the cell container minus the scroll bar width. + * To do so, this hook is listening for size changes of the container itself, + * as well as pagination changes to make sure every update is caught. + * + * This is necessary because there is no callback/event fired by the browser + * indicating the scroll bar state has changed. + * @param resizeRef the wrapper element containging the data grid + * @param pageSize the currently applied page size + */ +function useVirtualizeContainerWidth( + resizeRef: HTMLDivElement | null, + pageSize: number | undefined +) { + const [virtualizeContainerWidth, setVirtualizeContainerWidth] = useState(0); + const virtualizeContainer = resizeRef?.getElementsByClassName( + VIRTUALIZED_CONTAINER_CLASS + )[0] as HTMLDivElement | null; + + // re-render data grid on size changes + useResizeObserver(virtualizeContainer); + + useEffect(() => { + if (virtualizeContainer?.clientWidth) { + setVirtualizeContainerWidth(virtualizeContainer.clientWidth); + } + }, [virtualizeContainer?.clientWidth]); + + useEffect(() => { + // wait for layout to settle, then measure virtualize container + setTimeout(() => { + if (virtualizeContainer?.clientWidth) { + const containerWidth = virtualizeContainer.clientWidth; + setVirtualizeContainerWidth(containerWidth); + } + }, 100); + }, [pageSize, virtualizeContainer]); + + return virtualizeContainerWidth; +} + function useDefaultColumnWidth( gridWidth: number, leadingControlColumns: EuiDataGridControlColumn[], @@ -730,6 +771,11 @@ export const EuiDataGrid: FunctionComponent = (props) => { } }, [resizeRef, gridDimensions]); + const virtualizeContainerWidth = useVirtualizeContainerWidth( + resizeRef, + pagination?.pageSize + ); + const hasRoomForGridControls = IS_JEST_ENVIRONMENT ? true : gridWidth > minSizeForControls || isFullScreen; @@ -801,7 +847,9 @@ export const EuiDataGrid: FunctionComponent = (props) => { // compute the default column width from the container's clientWidth and count of visible columns const defaultColumnWidth = useDefaultColumnWidth( - gridDimensions.width, + // use clientWidth of the virtualization container to take scroll bar into account + // if that's not possible fall back to the size of the wrapper element + virtualizeContainerWidth || gridDimensions.width, leadingControlColumns, trailingControlColumns, orderedVisibleColumns diff --git a/src/components/datagrid/data_grid_body.tsx b/src/components/datagrid/data_grid_body.tsx index 83a413e2e44..e86b54e3104 100644 --- a/src/components/datagrid/data_grid_body.tsx +++ b/src/components/datagrid/data_grid_body.tsx @@ -91,6 +91,8 @@ export interface EuiDataGridBodyProps { toolbarHeight: number; } +export const VIRTUALIZED_CONTAINER_CLASS = 'euiDataGrid__virtualized'; + const defaultComparator: NonNullable< EuiDataGridSchemaDetector['comparator'] > = (a, b, direction) => { @@ -290,7 +292,7 @@ const InnerElement: VariableSizeGridProps['innerElementType'] = forwardRef< InnerElement.displayName = 'EuiDataGridInnerElement'; const INITIAL_ROW_HEIGHT = 34; -const SCROLLBAR_HEIGHT = 15; +const SCROLLBAR_HEIGHT = 16; const IS_JEST_ENVIRONMENT = global.hasOwnProperty('_isJest'); export const EuiDataGridBody: FunctionComponent = ( @@ -524,10 +526,10 @@ export const EuiDataGridBody: FunctionComponent = ( const [height, setHeight] = useState(undefined); const [width, setWidth] = useState(undefined); - // reset height constraint when rowCount changes + // reset height constraint when rowCount or fullscreen setting changes useEffect(() => { setHeight(undefined); - }, [rowCount]); + }, [rowCount, isFullScreen]); const wrapperRef = useRef(null); const wrapperDimensions = useResizeObserver(wrapperRef.current); @@ -584,7 +586,7 @@ export const EuiDataGridBody: FunctionComponent = (