Skip to content

Commit f5f2631

Browse files
authored
Table resizing api audit fixes (#3855)
1 parent 694a181 commit f5f2631

File tree

7 files changed

+70
-17
lines changed

7 files changed

+70
-17
lines changed

packages/@react-aria/table/src/useTableColumnResize.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ export interface AriaTableColumnResizeProps<T> {
4848
* */
4949
onMoveEnd?: (e: MoveEndEvent) => void,
5050
/** Called when resizing starts. */
51-
onResizeStart: (key: Key) => void,
51+
onResizeStart?: (widths: Map<Key, number | string>) => void,
5252
/** Called for every resize event that results in new column sizes. */
53-
onResize: (widths: Map<Key, number | string>) => void,
53+
onResize?: (widths: Map<Key, number | string>) => void,
5454
/** Called when resizing ends. */
55-
onResizeEnd: (key: Key) => void
55+
onResizeEnd?: (widths: Map<Key, number | string>) => void
5656
}
5757

5858

@@ -96,8 +96,9 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
9696

9797
let startResize = useCallback((item) => {
9898
if (!isResizing.current) {
99+
lastSize.current = layoutState.onColumnResize(item.key, layoutState.getColumnWidth(item.key));
99100
layoutState.onColumnResizeStart(item.key);
100-
onResizeStart?.(item.key);
101+
onResizeStart?.(lastSize.current);
101102
}
102103
isResizing.current = true;
103104
}, [isResizing, onResizeStart, layoutState]);

packages/@react-aria/table/stories/example-resizing.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function Table(props) {
8585
{[...headerRow.childNodes].map(column =>
8686
column.props.isSelectionCell
8787
? <TableSelectAllCell key={column.key} column={column} state={state} widths={widths} />
88-
: <TableColumnHeader key={column.key} column={column} state={state} widths={widths} layoutState={layoutState} onResize={props.onResize} onResizeEnd={props.onResizeEnd} />
88+
: <TableColumnHeader key={column.key} column={column} state={state} widths={widths} layoutState={layoutState} onResizeStart={props.onResizeStart} onResize={props.onResize} onResizeEnd={props.onResizeEnd} />
8989
)}
9090
</TableHeaderRow>
9191
))}
@@ -125,11 +125,12 @@ export function TableHeaderRow({item, state, children, className}) {
125125
</tr>
126126
);
127127
}
128-
function Resizer({column, state, layoutState, onResize, onResizeEnd}) {
128+
function Resizer({column, state, layoutState, onResizeStart, onResize, onResizeEnd}) {
129129
let ref = useRef(null);
130130
let {resizerProps, inputProps} = useTableColumnResize({
131131
column,
132132
label: 'Resizer',
133+
onResizeStart,
133134
onResize,
134135
onResizeEnd
135136
} as AriaTableColumnResizeProps<any>, state, layoutState, ref);
@@ -162,7 +163,7 @@ function Resizer({column, state, layoutState, onResize, onResizeEnd}) {
162163
</>
163164
);
164165
}
165-
export function TableColumnHeader({column, state, widths, layoutState, onResize, onResizeEnd}) {
166+
export function TableColumnHeader({column, state, widths, layoutState, onResizeStart, onResize, onResizeEnd}) {
166167
let ref = useRef();
167168
let {columnHeaderProps} = useTableColumnHeader({node: column}, state, ref);
168169
let {isFocusVisible, focusProps} = useFocusRing();
@@ -196,7 +197,7 @@ export function TableColumnHeader({column, state, widths, layoutState, onResize,
196197
</div>
197198
{
198199
column.props.allowsResizing &&
199-
<Resizer column={column} state={state} layoutState={layoutState} onResize={onResize} onResizeEnd={onResizeEnd} />
200+
<Resizer column={column} state={state} layoutState={layoutState} onResizeStart={onResizeStart} onResize={onResize} onResizeEnd={onResizeEnd} />
200201
}
201202
</div>
202203
</th>

packages/@react-aria/table/test/tableResizingTests.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,25 @@ export let resizingTests = (render, rerender, Table, ControlledTable, resizeCol,
526526
expect(onResizeEnd).toHaveBeenCalledWith(mapFromWidths(columnNames, [113, 112, '1fr', '1fr', '4fr']));
527527
expect(getColumnWidths(tree)).toStrictEqual([113, 112, 113, 112, 450]);
528528
});
529+
530+
it('onResizeStart called with expected values', function () {
531+
let columns = [
532+
{name: 'Name', uid: 'name', width: '1fr'},
533+
{name: 'Type', uid: 'type', width: '1fr'},
534+
{name: 'Height', uid: 'height'},
535+
{name: 'Weight', uid: 'weight'},
536+
{name: 'Level', uid: 'level', width: '4fr'}
537+
];
538+
539+
let columnNames = ['Name', 'Type', 'Height', 'Weight', 'Level'];
540+
let onResizeStart = jest.fn();
541+
542+
let tree = render(<ControlledTable columns={columns} onResizeStart={onResizeStart} />);
543+
expect(getColumnWidths(tree)).toStrictEqual([113, 112, 113, 112, 450]);
544+
resizeCol(tree, 'Height', -50);
545+
expect(onResizeStart).toHaveBeenCalledTimes(1);
546+
expect(onResizeStart).toHaveBeenCalledWith(mapFromWidths(columnNames, [113, 112, 113, '1fr', '4fr']));
547+
});
529548
});
530549

531550
describe('resizing table', () => {

packages/@react-spectrum/table/src/Resizer.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable jsx-a11y/role-supports-aria-props */
22
import {classNames} from '@react-spectrum/utils';
3+
import {ColumnSize} from '@react-types/table';
34
import {FocusRing} from '@react-aria/focus';
45
import {GridNode} from '@react-types/grid';
56
// @ts-ignore
@@ -16,9 +17,9 @@ interface ResizerProps<T> {
1617
column: GridNode<T>,
1718
showResizer: boolean,
1819
triggerRef: RefObject<HTMLDivElement>,
19-
onResizeStart: (key: Key) => void,
20-
onResize: (widths: Map<Key, number | string>) => void,
21-
onResizeEnd: (key: Key) => void,
20+
onResizeStart: (widths: Map<Key, ColumnSize>) => void,
21+
onResize: (widths: Map<Key, ColumnSize>) => void,
22+
onResizeEnd: (widths: Map<Key, ColumnSize>) => void,
2223
onMoveResizer: (e: MoveMoveEvent) => void
2324
}
2425

packages/@react-spectrum/table/src/TableView.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ interface TableContextValue<T> {
9494
setIsInResizeMode: (val: boolean) => void,
9595
isEmpty: boolean,
9696
onFocusedResizer: () => void,
97-
onResizeStart: (key: Key) => void,
97+
onResizeStart: (widths: Map<Key, ColumnSize>) => void,
9898
onResize: (widths: Map<Key, ColumnSize>) => void,
99-
onResizeEnd: (key: Key) => void,
99+
onResizeEnd: (widths: Map<Key, ColumnSize>) => void,
100100
onMoveResizer: (e: MoveMoveEvent) => void,
101101
headerMenuOpen: boolean,
102102
setHeaderMenuOpen: (val: boolean) => void
@@ -114,7 +114,7 @@ export function useVirtualizerContext() {
114114

115115
function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<HTMLDivElement>) {
116116
props = useProviderProps(props);
117-
let {isQuiet, onAction, onResizeEnd: propsOnResizeEnd} = props;
117+
let {isQuiet, onAction, onResizeStart: propsOnResizeStart, onResizeEnd: propsOnResizeEnd} = props;
118118
let {styleProps} = useStyleProps(props);
119119

120120
let [showSelectionCheckboxes, setShowSelectionCheckboxes] = useState(props.selectionStyle !== 'highlight');
@@ -369,9 +369,10 @@ function TableView<T extends object>(props: SpectrumTableProps<T>, ref: DOMRef<H
369369
lastResizeInteractionModality.current = undefined;
370370
}
371371
};
372-
let onResizeStart = useCallback(() => {
372+
let onResizeStart = useCallback((widths) => {
373373
setIsResizing(true);
374-
}, [setIsResizing]);
374+
propsOnResizeStart?.(widths);
375+
}, [setIsResizing, propsOnResizeStart]);
375376
let onResizeEnd = useCallback((widths) => {
376377
setIsInResizeMode(false);
377378
setIsResizing(false);
@@ -504,7 +505,7 @@ function TableVirtualizer({layout, collection, lastResizeInteractionModality, fo
504505
let resizerAtEdge = resizerPosition > Math.max(state.virtualizer.contentSize.width, state.virtualizer.visibleRect.width) - 3;
505506
// this should be fine, every movement of the resizer causes a rerender
506507
// scrolling can cause it to lag for a moment, but it's always updated
507-
let resizerInVisibleRegion = resizerPosition < state.virtualizer.visibleRect.width + (isNaN(bodyRef.current?.scrollLeft) ? 0 : bodyRef.current?.scrollLeft);
508+
let resizerInVisibleRegion = resizerPosition < state.virtualizer.visibleRect.maxX;
508509
let shouldHardCornerResizeCorner = resizerAtEdge && resizerInVisibleRegion;
509510

510511
// minimize re-render caused on Resizers by memoing this

packages/@react-spectrum/table/stories/Table.stories.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,32 @@ storiesOf('TableView', module)
13031303
),
13041304
{chromatic: {disable: true}}
13051305
)
1306+
.add(
1307+
'allowsResizing, onColumnResizeStart action',
1308+
() => (
1309+
<TableView aria-label="TableView with resizable columns" width={800} height={200} onResizeStart={action('onResizeStart')}>
1310+
<TableHeader>
1311+
<Column allowsResizing defaultWidth="1fr">File Name</Column>
1312+
<Column allowsResizing defaultWidth="2fr">Type</Column>
1313+
<Column allowsResizing defaultWidth="2fr">Size</Column>
1314+
<Column allowsResizing defaultWidth="1fr">Weight</Column>
1315+
</TableHeader>
1316+
<TableBody>
1317+
<Row>
1318+
<Cell>2018 Proposal</Cell>
1319+
<Cell>PDF</Cell>
1320+
<Cell>214 KB</Cell>
1321+
<Cell>1 LB</Cell>
1322+
</Row>
1323+
<Row>
1324+
<Cell>Budget</Cell>
1325+
<Cell>XLS</Cell>
1326+
<Cell>120 KB</Cell>
1327+
<Cell>20 LB</Cell>
1328+
</Row>
1329+
</TableBody>
1330+
</TableView>
1331+
))
13061332
.add(
13071333
'allowsResizing, onColumnResize action',
13081334
() => (

packages/@react-types/table/src/index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export interface SpectrumTableProps<T> extends TableProps<T>, SpectrumSelectionP
4545
renderEmptyState?: () => JSX.Element,
4646
/** Handler that is called when a user performs an action on a row. */
4747
onAction?: (key: Key) => void,
48+
/**
49+
* Handler that is called when a user starts a column resize.
50+
*/
51+
onResizeStart?: (widths: Map<Key, ColumnSize>) => void,
4852
/**
4953
* Handler that is called when a user performs a column resize.
5054
* Can be used with the width property on columns to put the column widths into

0 commit comments

Comments
 (0)