diff --git a/packages/main/CLAUDE.md b/packages/main/CLAUDE.md index a97fad82570..2214e980596 100644 --- a/packages/main/CLAUDE.md +++ b/packages/main/CLAUDE.md @@ -446,7 +446,7 @@ useEffect(() => { { cy.get('[data-component-name="AnalyticalTableBody"]').should('have.prop', 'scrollTop', 2500); }); + it('retainColumnWidth: recalculates widths after columns change', () => { + const columnsA = [ + { Header: 'Name', accessor: 'name' }, + { Header: 'Age', accessor: 'age' }, + ]; + const columnsB = [ + { Header: 'Product', accessor: 'product' }, + { Header: 'Price', accessor: 'price' }, + { Header: 'Qty', accessor: 'qty' }, + ]; + const dataA = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + ]; + const dataB = [ + { product: 'Widget', price: '$10', qty: 5 }, + { product: 'Gadget', price: '$20', qty: 3 }, + ]; + + function TestComp() { + const [useB, setUseB] = useState(false); + return ( + <> + + + + ); + } + + cy.mount(); + cy.get('[data-column-id="name"]').invoke('outerWidth').should('be.gt', 150).as('initialWidth'); + + // resize first column + cy.get('[data-component-name="AnalyticalTableResizer"]') + .eq(0) + .realMouseDown() + .realMouseMove(-50, 0, { scrollBehavior: false }); + cy.get('body').realMouseUp(); + cy.get('@initialWidth').then((initialWidth) => { + cy.get('[data-column-id="name"]').invoke('outerWidth').should('not.eq', initialWidth); + }); + + cy.get('[data-testid="switch"]').click(); + cy.get('[data-column-id="product"]').invoke('outerWidth').should('be.gt', 150); + cy.get('[data-column-id="price"]').invoke('outerWidth').should('be.gt', 150); + cy.get('[data-column-id="qty"]').invoke('outerWidth').should('be.gt', 150); + }); + cypressPassThroughTestsFactory(AnalyticalTable, { data, columns }); }); diff --git a/packages/main/src/components/AnalyticalTable/docs/FAQ.mdx b/packages/main/src/components/AnalyticalTable/docs/FAQ.mdx index 0775e3c8e21..0665431b836 100644 --- a/packages/main/src/components/AnalyticalTable/docs/FAQ.mdx +++ b/packages/main/src/components/AnalyticalTable/docs/FAQ.mdx @@ -158,42 +158,71 @@ For other elements or components, we recommend either disabling event propagatio ## How to stop the table state from automatically resetting when the data changes? -By default, the `AnalyticalTable` will reset the sorters, filters, grouping, selected rows, etc. when the table data changes. It will also reset all manually resized columns if the container width changes. -In case you want to keep the current state of the Table, you can disable this behavior by using the `reactTableOptions` prop or for column resize the `retainColumnWidth` prop. +By default, the `AnalyticalTable` resets most table state whenever the `data` or `columns` reference changes. + +### What resets when? + +Each `autoReset*` option defaults to `true`. Most trigger on **`data`** changes, but `autoResetResize` is the exception - it triggers on **`columns`** changes. + +
+Full list of autoReset* options + +| `reactTableOptions` option | Default | Resets on | What it resets | +| -------------------------- | ------- | ---------------- | ------------------------------------------- | +| `autoResetSelectedRows` | `true` | `data` change | Row selection (`selectedRowIds`) | +| `autoResetSortBy` | `true` | `data` change | Sort state (unless `manualSortBy`) | +| `autoResetFilters` | `true` | `data` change | Filter state (unless `manualFilters`) | +| `autoResetGlobalFilter` | `true` | `data` change | Global filter (unless `manualGlobalFilter`) | +| `autoResetGroupBy` | `true` | `data` change | Grouping state (unless `manualGroupBy`) | +| `autoResetExpanded` | `true` | `data` change | Expanded rows | +| `autoResetHiddenColumns` | `true` | `data` change | Hidden columns | +| `autoResetResize` | `true` | `columns` change | User-resized column widths | + +
+ +**Important:** Column resize widths are never reset by `data` changes - only by `columns` changes. If you want to preserve user-resized widths across column changes, set `autoResetResize: false`. + +### `retainColumnWidth` prop + +`retainColumnWidth` is a separate mechanism from `autoResetResize`. It controls what happens on **container resizes** (e.g., window resize): + +- **Without** `retainColumnWidth`: A container resize clears user-resized column widths and triggers dynamic width recalculation. +- **With** `retainColumnWidth`: User-resized column widths are preserved across container resizes. + +### Keeping state across data updates + +To prevent automatic resets when updating data, set the corresponding `autoReset*` option to `false` in `reactTableOptions`. The ref-based flag shown below is optional - it avoids an unnecessary re-render by reading the flag during render instead of toggling state: ```jsx -const [data, setData] = React.useState([]) -const skipPageResetRef = React.useRef(false) +const [data, setData] = useState([]) +const skipPageResetRef = useRef(false) const updateData = newData => { - // When data gets updated with this function, set a flag - // to disable all of the auto resetting + // When data gets updated with this function, set a flag to disable all of the auto resetting skipPageResetRef.current = true setData(newData) } -React.useEffect(() => { - // After the table has updated, always remove the flag +useEffect(() => { + // After the table has updated, remove the flag skipPageResetRef.current = false }) ``` diff --git a/packages/main/src/components/AnalyticalTable/tableReducer/stateReducer.ts b/packages/main/src/components/AnalyticalTable/tableReducer/stateReducer.ts index 73b7156bae8..0af59677b2e 100644 --- a/packages/main/src/components/AnalyticalTable/tableReducer/stateReducer.ts +++ b/packages/main/src/components/AnalyticalTable/tableReducer/stateReducer.ts @@ -67,6 +67,9 @@ export const stateReducer: TableInstance['stateReducer'] = (state, action, _prev return { ...state, subComponentsHeight: payload }; case 'TABLE_COL_RESIZED': return { ...state, tableColResized: payload }; + case 'resetResize': + // reset `tableColResized` state, when react-table resize state is reset + return { ...state, tableColResized: undefined }; case 'ROW_COLLAPSED_FLAG': return { ...state, rowCollapsed: payload }; case 'COLUMN_DND_START':