Skip to content

Commit 14531b4

Browse files
Marshall PetersonDanny North
Marshall Peterson
authored and
Danny North
committed
move the min/max check to TableLayout so that it will correctly support percentage values for min/max
1 parent 1499f75 commit 14531b4

File tree

4 files changed

+100
-19
lines changed

4 files changed

+100
-19
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@ export function useTableColumnResize(state, item): any {
2121
const columnResizeWidthRef = useRef(null);
2222
const {moveProps} = useMove({
2323
onMoveStart() {
24-
stateRef.current.setCurrentResizeColumn(item.key);
24+
stateRef.current.setCurrentResizeColumn(item);
2525
stateRef.current.addResizedColumn(item.key);
2626
columnResizeWidthRef.current = stateRef.current.getColumnWidth(item.key);
2727
},
2828
onMove({deltaX}) {
2929
columnResizeWidthRef.current += deltaX;
30-
let widthRespectingBoundaries = Math.max(item.props.minWidth || 75, Math.min(columnResizeWidthRef.current, item.props.maxWidth || Infinity));
31-
stateRef.current.setResizeDelta(widthRespectingBoundaries);
32-
stateRef.current.setColumnWidth(item.key, widthRespectingBoundaries);
30+
stateRef.current.setResizeDelta(columnResizeWidthRef.current);
3331
},
3432
onMoveEnd() {
3533
stateRef.current.setCurrentResizeColumn();

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

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {IllustratedMessage} from '@react-spectrum/illustratedmessage';
2828
import {Link} from '@react-spectrum/link';
2929
import {LoadingState, SelectionMode} from '@react-types/shared';
3030
import {Radio, RadioGroup} from '@react-spectrum/radio';
31-
import React, {Key, useState} from 'react';
31+
import React, {Key, useMemo, useState} from 'react';
3232
import {SearchField} from '@react-spectrum/searchfield';
3333
import {storiesOf} from '@storybook/react';
3434
import {Switch} from '@react-spectrum/switch';
@@ -1070,6 +1070,12 @@ storiesOf('TableView', module)
10701070
</TableBody>
10711071
</TableView>
10721072
)
1073+
)
1074+
.add(
1075+
'resizable columns, controlled',
1076+
() => (
1077+
<ResizableColumnsControlled />
1078+
)
10731079
);
10741080

10751081
function AsyncLoadingExample() {
@@ -1419,3 +1425,60 @@ export function TableWithBreadcrumbs() {
14191425
</Flex>
14201426
);
14211427
}
1428+
1429+
function ResizableColumnsControlled() {
1430+
let columns = [
1431+
{
1432+
key: 0,
1433+
label: 'File Name',
1434+
allowsResizing: true,
1435+
width: 300
1436+
},
1437+
{
1438+
key: 1,
1439+
label: 'Type',
1440+
allowsResizing: true,
1441+
width: 200
1442+
},
1443+
{
1444+
key: 2,
1445+
label: 'Size',
1446+
allowsResizing: true,
1447+
width: 96
1448+
}
1449+
];
1450+
1451+
let [columnState, setColumnState] = useState(columns);
1452+
1453+
let onResize = (key, prevWidth, newWidth) => {
1454+
if (newWidth !== prevWidth) {
1455+
let updatedColumnState = columnState.map(c => key === c.key ? {...c, width: newWidth} : c);
1456+
setColumnState(updatedColumnState);
1457+
1458+
}
1459+
1460+
};
1461+
1462+
1463+
return (
1464+
<TableView aria-label="TableView with resizable columns" width={600} height={200}>
1465+
<TableHeader>
1466+
{
1467+
columnState.map(c => useMemo(() => (<Column allowsResizing={c.allowsResizing} width={c.width} onResize={(newWidth) => onResize(c.key, c.width, newWidth)}>{c.label}</Column>), [c.width]))
1468+
}
1469+
</TableHeader>
1470+
<TableBody>
1471+
<Row>
1472+
<Cell>2018 Proposal</Cell>
1473+
<Cell>PDF</Cell>
1474+
<Cell>214 KB</Cell>
1475+
</Row>
1476+
<Row>
1477+
<Cell>Budget</Cell>
1478+
<Cell>XLS</Cell>
1479+
<Cell>120 KB</Cell>
1480+
</Row>
1481+
</TableBody>
1482+
</TableView>
1483+
);
1484+
}

packages/@react-stately/layout/src/TableLayout.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ type TableLayoutOptions<T> = ListLayoutOptions<T> & {
2121
getDefaultWidth: (props) => string | number,
2222
columnWidths: Map<Key, number>,
2323
getColumnWidth: (key: Key) => number,
24-
setColumnWidth: (key: Key, width: number) => void,
24+
setColumnWidth: (column: any, width: number) => void,
2525
hasResizedColumn: (key: Key) => boolean,
26-
currentResizeColumn: Key,
26+
currentResizeColumn: any,
2727
resizeDelta: number
2828
}
2929

@@ -35,9 +35,9 @@ export class TableLayout<T> extends ListLayout<T> {
3535
stickyColumnIndices: number[];
3636
getDefaultWidth: (props) => string | number;
3737
getColumnWidth_: (key: Key) => number;
38-
setColumnWidth: (key: Key, width: number) => void;
38+
setColumnWidth_: (column: any, width: number) => void;
3939
hasResizedColumn: (key: Key) => boolean;
40-
currentResizeColumn: Key;
40+
currentResizeColumn: any;
4141
resizeDelta: number;
4242
wasLoading = false;
4343
isLoading = false;
@@ -47,7 +47,7 @@ export class TableLayout<T> extends ListLayout<T> {
4747
this.getDefaultWidth = options.getDefaultWidth;
4848
this.columnWidths = options.columnWidths;
4949
this.getColumnWidth_ = options.getColumnWidth;
50-
this.setColumnWidth = options.setColumnWidth;
50+
this.setColumnWidth_ = options.setColumnWidth;
5151
this.hasResizedColumn = options.hasResizedColumn;
5252
this.currentResizeColumn = options.currentResizeColumn;
5353
this.columnWidthsRef = this.columnWidths;
@@ -71,11 +71,26 @@ export class TableLayout<T> extends ListLayout<T> {
7171
this.wasLoading = this.isLoading;
7272
this.isLoading = loadingState === 'loading' || loadingState === 'loadingMore';
7373

74-
const resizeIndex = this.collection.columns.findIndex(column => column.key === this.currentResizeColumn);
75-
let affectedResizeColumns = this.collection.columns.slice(resizeIndex + 1, this.collection.columns.length);
76-
let remainingSpace = this.virtualizer.visibleRect.width;
77-
remainingSpace = this.collection.columns.slice(0, resizeIndex + 1).reduce((acc, column) => acc - this.getColumnWidth_(column.key), this.virtualizer.visibleRect.width);
74+
// only rebuild columns that come after the column being resized, if no column is being resized, they will all be built
75+
const resizeIndex = this.collection.columns.findIndex(column => column.key === this.currentResizeColumn?.key);
76+
// if resizing, set the column width for the resized column to the delta bounded by it's min/max
77+
if (resizeIndex > -1) {
78+
const columnProps = this.collection.columns[resizeIndex].props;
79+
const boundedResizeDelta = Math.max(this.getMinWidth(columnProps?.minWidth), Math.min(this.getMaxWidth(columnProps.maxWidth), this.resizeDelta));
80+
81+
if (columnProps.width) {
82+
// Controlled component - explicit width is defined and should always win.
83+
// Unsure: Set column width to current width but call onResize with the new width?
84+
this.setColumnWidth_(this.currentResizeColumn, columnProps.width);
85+
columnProps.onResize && columnProps.onResize(boundedResizeDelta);
86+
} else {
87+
this.setColumnWidth(this.currentResizeColumn, boundedResizeDelta);
88+
}
89+
}
90+
const affectedResizeColumns = this.collection.columns.slice(resizeIndex + 1, this.collection.columns.length);
91+
const remainingSpace = this.collection.columns.slice(0, resizeIndex + 1).reduce((acc, column) => acc - this.getColumnWidth_(column.key), this.virtualizer.visibleRect.width);
7892
this.buildColumnWidths(affectedResizeColumns, remainingSpace);
93+
7994
let header = this.buildHeader();
8095
let body = this.buildBody(0);
8196
body.layoutInfo.rect.width = Math.max(header.layoutInfo.rect.width, body.layoutInfo.rect.width);
@@ -86,6 +101,11 @@ export class TableLayout<T> extends ListLayout<T> {
86101
];
87102
}
88103

104+
setColumnWidth(column, newWidth) {
105+
this.setColumnWidth_(column, newWidth);
106+
column.props.onResize && column.props.onResize(newWidth);
107+
}
108+
89109
buildColumnWidths(affectedResizeColumns: GridNode<T>[], remainingSpace: number) {
90110
this.stickyColumnIndices = [];
91111

@@ -104,7 +124,7 @@ export class TableLayout<T> extends ListLayout<T> {
104124
if (this.getIsStatic(width)) {
105125
let w = this.parseWidth(width);
106126
this.columnWidthsRef.set(column.key, w);
107-
this.setColumnWidth(column.key, w);
127+
this.setColumnWidth(column, w);
108128
remainingSpace -= w;
109129
} else {
110130
remainingColumns.add(column);
@@ -126,7 +146,7 @@ export class TableLayout<T> extends ListLayout<T> {
126146
let i = 0;
127147
for (let column of remainingColumns) {
128148
this.columnWidthsRef.set(column.key, remCols[i].columnWidth);
129-
this.setColumnWidth(column.key, remCols[i].columnWidth);
149+
this.setColumnWidth(column, remCols[i].columnWidth);
130150
i++;
131151
}
132152
}

packages/@react-stately/table/src/useTableState.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface TableState<T> extends GridState<T, ITableCollection<T>> {
3737

3838
columnWidths(): Map<Key, number>,
3939
getColumnWidth(key: Key): number,
40-
setColumnWidth(key: Key, width: number),
40+
setColumnWidth(column: any, width: number),
4141

4242
hasResizedColumn(key: Key): boolean,
4343
addResizedColumn(key: Key),
@@ -102,8 +102,8 @@ export function useTableState<T extends object>(
102102
return columnWidthsRef.current.get(key);
103103
}
104104

105-
function setColumnWidthNew(key: Key, width: number) {
106-
columnWidthsRef.current.set(key, width);
105+
function setColumnWidthNew(column: any, width: number) {
106+
columnWidthsRef.current.set(column.key, width);
107107
// new map so that change detection is triggered
108108
setColumnWidths(new Map(columnWidthsRef.current));
109109
}

0 commit comments

Comments
 (0)