diff --git a/src/hooks/useGridDimensions.ts b/src/hooks/useGridDimensions.ts index 507b282617..749ba42004 100644 --- a/src/hooks/useGridDimensions.ts +++ b/src/hooks/useGridDimensions.ts @@ -1,14 +1,16 @@ import { useRef, useState } from 'react'; import { useLayoutEffect } from './useLayoutEffect'; +import { ceil } from '../utils'; + export function useGridDimensions(): [ ref: React.RefObject, width: number, height: number ] { const gridRef = useRef(null); - const [gridWidth, setGridWidth] = useState(1); - const [gridHeight, setGridHeight] = useState(1); + const [inlineSize, setInlineSize] = useState(1); + const [blockSize, setBlockSize] = useState(1); useLayoutEffect(() => { const { ResizeObserver } = window; @@ -17,20 +19,19 @@ export function useGridDimensions(): [ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (ResizeObserver == null) return; - function saveDimensions() { - // Get dimensions without scrollbars. - // The dimensions given by the callback entries in Firefox do not substract the scrollbar sizes. - // https://bugzilla.mozilla.org/show_bug.cgi?id=1733042 - const { clientWidth, clientHeight } = gridRef.current!; - // TODO: remove once fixed upstream - // we reduce width by 1px here to avoid layout issues in Chrome - // https://bugs.chromium.org/p/chromium/issues/detail?id=1206298 - setGridWidth(clientWidth - (devicePixelRatio % 1 === 0 ? 0 : 1)); - setGridHeight(clientHeight); - } - - saveDimensions(); - const resizeObserver = new ResizeObserver(saveDimensions); + const { clientWidth, clientHeight, offsetWidth, offsetHeight } = gridRef.current!; + const { width, height } = gridRef.current!.getBoundingClientRect(); + const initialWidth = width - offsetWidth + clientWidth; + const initialHeight = height - offsetHeight + clientHeight; + + setInlineSize(handleDevicePixelRatio(initialWidth)); + setBlockSize(initialHeight); + + const resizeObserver = new ResizeObserver((entries) => { + const size = entries[0].contentBoxSize[0]; + setInlineSize(handleDevicePixelRatio(size.inlineSize)); + setBlockSize(size.blockSize); + }); resizeObserver.observe(gridRef.current!); return () => { @@ -38,5 +39,12 @@ export function useGridDimensions(): [ }; }, []); - return [gridRef, gridWidth, gridHeight]; + return [gridRef, inlineSize, blockSize]; +} + +// TODO: remove once fixed upstream +// we reduce width by 1px here to avoid layout issues in Chrome +// https://bugs.chromium.org/p/chromium/issues/detail?id=1206298 +function handleDevicePixelRatio(size: number) { + return size - (devicePixelRatio === 1 ? 0 : ceil(devicePixelRatio)); } diff --git a/src/utils/index.ts b/src/utils/index.ts index a532f85fd5..0b16258fbb 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -6,7 +6,7 @@ export * from './keyboardUtils'; export * from './selectedCellUtils'; export * from './styleUtils'; -export const { min, max, round, floor, sign, abs } = Math; +export const { min, max, round, floor, sign, abs, ceil } = Math; export function assertIsValidKeyGetter( keyGetter: unknown diff --git a/test/setup.ts b/test/setup.ts index cca0fa5f6f..9538b20c3a 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -9,7 +9,9 @@ if (typeof window !== 'undefined') { } observe() { - this.callback([], this); + // patch inlineSize/blockSize to pretend we're rendering DataGrid at 1920p/1080p + // @ts-expect-error + this.callback([{ contentBoxSize: [{ inlineSize: 1920, blockSize: 1080 }] }], this); } unobserve() {}