diff --git a/semcore/data-table/__tests__/data-table-scroll.browser-test.tsx b/semcore/data-table/__tests__/data-table-scroll.browser-test.tsx index 3196b85eda..0abc86da63 100644 --- a/semcore/data-table/__tests__/data-table-scroll.browser-test.tsx +++ b/semcore/data-table/__tests__/data-table-scroll.browser-test.tsx @@ -218,3 +218,48 @@ test.describe(`${TAG.VISUAL}`, () => { // add cases when hedader has interactive element }); + +/* ===================================================== +@functional +Scroll bar geometry - no snapshots here. +We verify offsets of the scroll bars against the fixed columns. +===================================================== */ +test.describe(`${TAG.FUNCTIONAL}`, () => { + test('Verify offset of horizontal scroll bar is recalculated after table resize', { + tag: [TAG.PRIORITY_HIGH, '@data-table'], + }, async ({ page }) => { + await loadPage(page, 'stories/components/data-table/tests/examples/scroll-tests/real-table.tsx', 'en'); + + // The fixed column is sized as `minmax(139px, auto)`, so it takes the leftover space in a wide + // container and shrinks back to its minimum in a narrow one. + const fixedColumn = locators.getHeadColumn(page, 1); + const horizontalScrollBars = page.locator('[data-ui-name="ScrollArea.Bar"][aria-orientation="horizontal"]'); + + await page.setViewportSize({ width: 1500, height: 900 }); + await expect(fixedColumn).toBeVisible(); + const wideColumnWidth = (await fixedColumn.boundingBox())!.width; + + await page.setViewportSize({ width: 800, height: 900 }); + + await test.step('Verify the fixed column shrinks together with the table', async () => { + await expect.poll(async () => (await fixedColumn.boundingBox())!.width, { timeout: 3000 }).toBeLessThan(wideColumnWidth); + }); + + await test.step('Verify horizontal scroll bars start at the end of the fixed column', async () => { + await expect(horizontalScrollBars.first()).toBeVisible(); + + const scrollBarsCount = await horizontalScrollBars.count(); + + for (let i = 0; i < scrollBarsCount; i++) { + const scrollBar = horizontalScrollBars.nth(i); + + await expect.poll(async () => { + const scrollBarBox = (await scrollBar.boundingBox())!; + const columnBox = (await fixedColumn.boundingBox())!; + + return Math.abs(scrollBarBox.x - (columnBox.x + columnBox.width)); + }, { timeout: 3000 }).toBeLessThanOrEqual(1); + } + }); + }); +}); diff --git a/semcore/data-table/src/components/DataTable/DataTable.tsx b/semcore/data-table/src/components/DataTable/DataTable.tsx index f3e09f6d3b..f89856111b 100644 --- a/semcore/data-table/src/components/DataTable/DataTable.tsx +++ b/semcore/data-table/src/components/DataTable/DataTable.tsx @@ -926,6 +926,9 @@ class DataTableRoot< this.calculateVerticalShadow(); this.calculateStickyHeaderAnimation(); this.calculateContainerHeight(); + this.setState({ + scrollOffset: this.getScrollOffsetValue(), + }); }, 0); this.asProps.onResize?.(entries, observer); @@ -1060,7 +1063,7 @@ class DataTableRoot< return [0, 0]; } - return this.columns.reduce( + const offsets = this.columns.reduce( (acc, column) => { if (column.fixed === 'left') { acc[0] += this.headerNodesMap.get(column.name)?.current?.getBoundingClientRect().width ?? 0; @@ -1072,6 +1075,8 @@ class DataTableRoot< }, [0, 0] as [leftOffset: number, rightOffset: number], ); + + return offsets; }; private getFixedStyle = (