Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/table/__tests__/columns-width.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,70 @@ test('prints a warning when resizable columns have non-numeric width', () => {
);
});

describe('measurement on re-render', () => {
const stableColumns: TableProps.ColumnDefinition<Item>[] = [
{ id: 'id', header: 'id', cell: item => item.id, width: 150 },
{ id: 'text', header: 'text', cell: item => item.text, width: 200 },
];

test('does not measure column widths when re-rendering with unchanged columns', () => {
const getBoundingClientRectSpy = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect');
const { rerender } = renderTable(
<Table
columnDefinitions={stableColumns}
items={defaultItems}
resizableColumns={true}
stickyColumns={{ first: 1 }}
/>
);

// Ignore measurements from the initial render; only re-renders should be measurement-free.
getBoundingClientRectSpy.mockClear();

// Re-render with new items but the same column definitions (e.g. typing in the filter box).
rerender(
<Table
columnDefinitions={stableColumns}
items={[{ id: 1, text: 'updated' }]}
resizableColumns={true}
stickyColumns={{ first: 1 }}
/>
);

expect(getBoundingClientRectSpy).not.toHaveBeenCalled();

getBoundingClientRectSpy.mockRestore();
});

test('does measure column widths when the columns change', () => {
const getBoundingClientRectSpy = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect');
const { rerender } = renderTable(
<Table
columnDefinitions={stableColumns}
items={defaultItems}
resizableColumns={true}
stickyColumns={{ first: 1 }}
/>
);

getBoundingClientRectSpy.mockClear();

// Re-render with an added column: widths must be recomputed, so measurement is expected.
rerender(
<Table
columnDefinitions={[...stableColumns, { id: 'extra', header: 'extra', cell: () => '-' }]}
items={defaultItems}
resizableColumns={true}
stickyColumns={{ first: 1 }}
/>
);

expect(getBoundingClientRectSpy).toHaveBeenCalled();

getBoundingClientRectSpy.mockRestore();
});
});

describe('with stickyHeader=true', () => {
const originalFn = window.CSS.supports;
beforeEach(() => {
Expand Down
36 changes: 19 additions & 17 deletions src/table/internal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useCallback, useImperativeHandle, useRef } from 'react';
import React, { useCallback, useImperativeHandle, useMemo, useRef } from 'react';
import clsx from 'clsx';

import { useContainerQuery } from '@cloudscape-design/component-toolkit';
Expand Down Expand Up @@ -299,11 +299,10 @@ const InternalTable = React.forwardRef(
const { moveFocusDown, moveFocusUp, moveFocus } = useSelectionFocusMove(selectionType, allItems.length);
const { onRowClickHandler, onRowContextMenuHandler } = useRowEvents({ onRowClick, onRowContextMenu });

const visibleColumnDefinitions = getVisibleColumnDefinitions({
columnDefinitions,
columnDisplay,
visibleColumns,
});
const visibleColumnDefinitions = useMemo(
() => getVisibleColumnDefinitions({ columnDefinitions, columnDisplay, visibleColumns }),
[columnDefinitions, columnDisplay, visibleColumns]
);

const visibleColumnIds = visibleColumnDefinitions.map((col, idx) => getColumnKey(col, idx).toString());

Expand Down Expand Up @@ -374,17 +373,20 @@ const InternalTable = React.forwardRef(
headerIdRef.current = id;
}, []);

const visibleColumnWidthsWithSelection: ColumnWidthDefinition[] = [];
const visibleColumnIdsWithSelection: PropertyKey[] = [];
if (hasSelection) {
visibleColumnWidthsWithSelection.push({ id: selectionColumnId, width: SELECTION_COLUMN_WIDTH });
visibleColumnIdsWithSelection.push(selectionColumnId);
}
for (let columnIndex = 0; columnIndex < visibleColumnDefinitions.length; columnIndex++) {
const columnId = getColumnKey(visibleColumnDefinitions[columnIndex], columnIndex);
visibleColumnWidthsWithSelection.push({ ...visibleColumnDefinitions[columnIndex], id: columnId });
visibleColumnIdsWithSelection.push(columnId);
}
const { visibleColumnWidthsWithSelection, visibleColumnIdsWithSelection } = useMemo(() => {
const widths: ColumnWidthDefinition[] = [];
const ids: PropertyKey[] = [];
if (hasSelection) {
widths.push({ id: selectionColumnId, width: SELECTION_COLUMN_WIDTH });
ids.push(selectionColumnId);
}
for (let columnIndex = 0; columnIndex < visibleColumnDefinitions.length; columnIndex++) {
const columnId = getColumnKey(visibleColumnDefinitions[columnIndex], columnIndex);
widths.push({ ...visibleColumnDefinitions[columnIndex], id: columnId });
ids.push(columnId);
}
return { visibleColumnWidthsWithSelection: widths, visibleColumnIdsWithSelection: ids };
}, [hasSelection, visibleColumnDefinitions]);

const stickyState = useStickyColumns({
visibleColumns: visibleColumnIdsWithSelection,
Expand Down
Loading