Skip to content

TableView Column resizing #2883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 137 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
a762c26
initial work
Jan 4, 2022
1d4e93d
really hacky column resizing to prove flow
Jan 6, 2022
3a4645a
add resize algo
Jan 11, 2022
e8dda05
resize any column, not just first
Jan 13, 2022
3851565
merging main
Jan 13, 2022
b5fcedc
column resize working
Jan 14, 2022
5c562b9
support allowsResizing prop
Jan 21, 2022
28cd3ba
Fixed issue where mouse was not correctly tracking column sizing
Jan 21, 2022
6146c8c
use defaultWidth for uncontrolled resizeable columns
Jan 24, 2022
1499f75
clean up unused props and only calculate widths of affected columns
Jan 25, 2022
5ae06bd
move the min/max check to TableLayout so that it will correctly suppo…
Jan 25, 2022
2237b91
Add uncontrolled storybook stories
Feb 1, 2022
de81e6d
Merge branch 'adobe:main' into columnResizing
dnorth Feb 8, 2022
d9c5052
WIP refactor flow proof
Feb 4, 2022
8edb449
begin adding the resize algo
Feb 7, 2022
fa85efa
get rid of race condition error on initialization. onResize still doe…
Feb 8, 2022
790c5d2
calculate columns on resize
Feb 8, 2022
5d9a476
fix typing
Feb 8, 2022
8b5b06d
Re-introduce sticky column indices (still part of layout but outside …
Feb 8, 2022
ff76327
add defaultWidth prop to useTableState
Feb 8, 2022
c8508eb
fix column width getter for virtualizer
Feb 8, 2022
bc38051
remove unused code
Feb 8, 2022
ea8d7fc
get virtualizer width in useTableState
Feb 9, 2022
eb74736
no need for useCallback
Feb 11, 2022
fff9177
useEffect to recalc columnWidths when columns changes
Feb 14, 2022
a5e071d
cleanup code
Feb 14, 2022
6decb42
check for null in case rendering when previous render hasn't finished…
Feb 15, 2022
ff58f69
Set rounding to 2 decimal places, fix tests
Feb 14, 2022
4521e09
Add new tests for edge cases (these tests would have failed before ou…
Feb 15, 2022
b713fff
add onColumnResize prop
Feb 22, 2022
2f2ec3d
Throw error in certain prop conditions
Feb 22, 2022
f010127
resizer styling
Feb 23, 2022
0c501f4
add onColumnResizeEnd prop
Feb 23, 2022
8fc42d1
add types and fix resize bug
Feb 23, 2022
b153299
fix resize bug with static columns to the right of the resize column
Feb 23, 2022
133baf1
Merge branch 'main' into columnResizing
Feb 23, 2022
eef5cb0
remove unnecessary console log
Feb 23, 2022
8a2408d
cleanup unused TableLayout code
Feb 24, 2022
8f26199
remove unused code that was moved to useTableState
Feb 24, 2022
ddff409
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Feb 24, 2022
85a885a
clean up most prettier changes and code comments
Feb 24, 2022
f083e67
Merge branch 'columnResizing' of github.com:marshallpete/react-spectr…
Feb 24, 2022
f45fcb7
fix TableView prettier unintended changes
Feb 24, 2022
bfe6c4c
initial resize bug work
Feb 24, 2022
5b9fd90
merging
Feb 24, 2022
a5854ce
merging
Feb 24, 2022
b036393
fix TableView prettier unintended changes
Feb 24, 2022
5735265
have a default width if no defaultWidth function is provided. That wa…
Feb 24, 2022
4d8ae16
fix horizontal scroll resize bug
Feb 24, 2022
8bcf528
merging
Feb 24, 2022
f03035b
1fr if no getDefaultWidthProvided
Feb 25, 2022
59aa98c
fix TS
Feb 25, 2022
c8ac9c0
make widths more robust and add console warn for wrong format
Feb 25, 2022
85f859b
fix linting problems
Feb 25, 2022
d14e886
Merge branch 'main' into columnResizing
Feb 25, 2022
19d3aed
only add resize column if one of the columns is resizable
Feb 25, 2022
d6438ab
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Feb 25, 2022
9294509
remove console.log
Feb 25, 2022
34b6e3a
Remove error when both width and defaultWidth are provided - (width w…
Feb 28, 2022
2c2d3a8
Round to whole pixel widths via floor. This will avoid strange half-p…
Feb 28, 2022
4ea86eb
useLayoutEffect for width changes. Initialize widths in-line
Mar 1, 2022
8240301
move useColumnResizeState static functions to utils file. Reorganize …
Mar 1, 2022
378e97a
add all dependencies, memoize callbacks
Mar 4, 2022
9d22061
rename to useTableColumnResizeState for consistency with the react-ar…
Mar 4, 2022
32f00dd
Merge branch 'main' into columnResizing
dnorth Mar 4, 2022
d0f1f94
initial a11y work
Mar 4, 2022
5813ef6
add prop to get focussing working
Mar 4, 2022
2908a53
Merge branch 'columnResizing' into columnResizing-a11y
Mar 4, 2022
8126f9a
allowsResizing prop determines which code path to go down - old or ne…
Mar 7, 2022
7c51665
escape to focus table header
Mar 7, 2022
ca6e38c
Merge branch 'columnResizing' into columnResizing-a11y
Mar 7, 2022
bf24fd7
Fix feature-flagged tests and add jsdoc comment to exported component
Mar 7, 2022
3e73974
Add descriptions to TableStateProps
Mar 7, 2022
74c6b1f
somehow this fixes the doc build :cowboy:
Mar 8, 2022
ff53d5c
Merge branch 'main' into columnResizing
Mar 8, 2022
cc0bfcb
increase resizer hitbox size
Mar 9, 2022
d308046
highlight header text on hover if resizable column
Mar 9, 2022
381e50f
disable usePress if resizable
Mar 9, 2022
16f6f0b
add menu for resize and sort accessibility
Mar 9, 2022
40198c4
add sortable async resize example
Mar 9, 2022
f7fd8ee
add optional prop to specify which direction to sort
Mar 9, 2022
518a0e6
partial fix for no layoutInfo bug on async tables
Mar 9, 2022
376c942
merging columnResizing
Mar 9, 2022
88f3c22
remove unneeded spaces
Mar 9, 2022
9115326
Add hiding columns allowsResize story, also make the public table lay…
Mar 9, 2022
79b1ccd
add aria attributes
Mar 9, 2022
b0596b1
Merge branch 'columnResizing' into columnResizing-a11y
Mar 9, 2022
188b536
add aria label
Mar 9, 2022
c26ebd8
change signature of useTableColumnResizeState because it's larger tha…
Mar 9, 2022
20b851a
add minwidth to match style guide
Mar 9, 2022
25c89ac
Merge pull request #1 from marshallpete/columnResizing-a11y
marshallpete Mar 9, 2022
0e9c12e
update useTableState to remove all column resizing properties into us…
Mar 9, 2022
3bf4357
use ref for columns to solve issue with columns being hidden/shown an…
Mar 9, 2022
5ca0f8f
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Mar 9, 2022
12250eb
fix bug where resizing wouldn't work if width is not provided on the …
Mar 9, 2022
26f5364
remove console.log
Mar 9, 2022
9221f11
memoize getColumnWidth and regenerate the function whenever columnWid…
Mar 10, 2022
87a973b
PR feedback to change old code to be more understandable.
Mar 10, 2022
f9549f9
use a ref to save the state of the affected column resize changes, re…
Mar 10, 2022
d2c322b
update isStatic function to be more clear and add types to getContent…
Mar 10, 2022
3c0be58
Simplify comparison expressions and return boundedWidth from resizeCo…
Mar 11, 2022
04253c9
make getResolvedColumnWidth more clear as to its purpose
Mar 11, 2022
4f5d360
columnProps rename for clarity
Mar 11, 2022
272dc71
PR feedback - move setColumnWidthsForRef closer to ref/useState
Mar 11, 2022
0abad4e
rename util width functions to match PDF
Mar 11, 2022
fb75d7d
remove unused import
Mar 11, 2022
7ad117f
fix bad regex whoopsies
Mar 11, 2022
1999421
add aria-values to resizer and add getters to set those
Mar 11, 2022
b3f2941
merging changes
Mar 11, 2022
1212451
add useCallback to getters
Mar 11, 2022
c2571b5
adding aria-labeledby
Mar 11, 2022
77c0b56
add comments to explain why we need a spooky column
Mar 11, 2022
4ffa912
Change AffectedColumnWidhts type to integrate the array
Mar 11, 2022
38ef25f
conditionally add button props
Mar 11, 2022
8e22ad1
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Mar 11, 2022
21d6ea2
remove unneeded interface
Mar 11, 2022
e1b3314
Update packages/@react-stately/virtualizer/src/Virtualizer.ts
marshallpete Mar 11, 2022
8329218
remove unneeded array copy
marshallpete Mar 14, 2022
e7d7973
switch to pure function that doesn't mutate inputs
Mar 14, 2022
7259f56
rename variables for clarity
Mar 14, 2022
1e2ee48
removing the react-aria dependency in react-stately.
Mar 14, 2022
ca2f0a8
Revert "removing the react-aria dependency in react-stately."
Mar 14, 2022
ca48557
add rfc
Mar 15, 2022
6ad30c1
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Mar 15, 2022
0c73f6b
Add first round of tests for useTableColumnResizeState
Mar 15, 2022
25eb15f
Merge branch 'main' into columnResizing
dannify Mar 16, 2022
d7b6e74
get layoutinfo if undefined
Mar 17, 2022
a7fc5cd
add divider story and undefined table width/height story
Mar 17, 2022
dd013db
support rtl
Mar 17, 2022
50ebf80
Merge branch 'columnResizing' of https://github.com/marshallpete/reac…
Mar 17, 2022
c68881d
make Enter and Space do the same thing as Esc when resizing columns
Mar 17, 2022
d4ef1a8
remove rtl class and use logical properties instead
Mar 17, 2022
5741bd3
revert to return if layoutinfo undefined
Mar 17, 2022
588f0fd
fix col-resize cursor flicker issue
Mar 18, 2022
452d284
clarify comment
Mar 18, 2022
7e9f9bd
fixed virtualizer bug root cause and removed aria dependency in stately
Mar 18, 2022
b34aa30
Update packages/@react-aria/table/src/useTableColumnResize.ts
marshallpete Mar 18, 2022
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
46 changes: 46 additions & 0 deletions packages/@adobe/spectrum-css-temp/components/table/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,44 @@ svg.spectrum-Table-sortedIcon {
}
}

.spectrum-Table--resizingColumn {
.spectrum-Table-row,
.spectrum-Table-headCell {
cursor: col-resize;
}
}

.spectrum-Table-columnResizer {
display: flex;
justify-content: end;
box-sizing: border-box;
position: absolute;
inset-block-start: 0px;
inset-inline-end: 0px;
inline-size: 10px;
block-size: 100%;
cursor: col-resize;
user-select: none;

&::after {
content: "";
position: absolute;
display: block;
box-sizing: border-box;
inline-size: 1px;
block-size: 100%;
background-color: var(--spectrum-table-divider-border-color);
}

&:active,
&:focus {
&::after {
inline-size: 2px;
background-color: var(--spectrum-global-color-blue-400);
}
}
}

.spectrum-Table-cell--alignCenter {
text-align: center;
}
Expand Down Expand Up @@ -236,6 +274,14 @@ svg.spectrum-Table-sortedIcon {
border-inline-end-width: var(--spectrum-table-divider-border-size);
}

.spectrum-Table-cell--divider {
&.is-resizable {
&:hover {
border-inline-end-width: 3px;
}
}
}

.spectrum-Table-row {
position: relative;
cursor: default;
Expand Down
6 changes: 6 additions & 0 deletions packages/@adobe/spectrum-css-temp/components/table/skin.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ governing permissions and limitations under the License.
}
}
}

&.is-resizable {
&.is-hovered {
color: var(--spectrum-table-header-text-color-hover);
}
}
}

/* Helper for shared drop target overlay */
Expand Down
4 changes: 3 additions & 1 deletion packages/@react-aria/table/src/useTableColumnHeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ interface ColumnHeaderAria {
*/
export function useTableColumnHeader<T>(props: ColumnHeaderProps, state: TableState<T>, ref: RefObject<HTMLElement>): ColumnHeaderAria {
let {node} = props;
let allowsResizing = node.props.allowsResizing;
let allowsSorting = node.props.allowsSorting;
let {gridCellProps} = useGridCell(props, state, ref);

let isSelectionCellDisabled = node.props.isSelectionCell && state.selectionManager.selectionMode === 'single';
let {pressProps} = usePress({
isDisabled: !allowsSorting || isSelectionCellDisabled,
// Disabled for allowsResizing because if resizing is allowed, a menu trigger is added to the column header.
isDisabled: !allowsSorting || isSelectionCellDisabled || allowsResizing,
Comment on lines +51 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a minor point:
Is adding a menu trigger to the column header when the column supports resizing an interaction pattern we'll be recommending for a non-Spectrum tables as well? If not, then I don't know if we wanna disable the press to sort interactions here, perhaps the pressProps from this hook should be overridden in the TableView instead.

Just thinking about a case where someone using our table hooks implements column resizing in a such a way that pressing the column headers should perform the sort action still and resizing via keyboard is handled in a different way (keyboard shortcut maybe? I'll need to dig to see if any other tables support resizing columns via keyboard).

onPress() {
state.sort(node.key);
}
Expand Down
76 changes: 76 additions & 0 deletions packages/@react-aria/table/src/useTableColumnResize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {focusSafely, useFocusable} from '@react-aria/focus';
import {mergeProps} from '@react-aria/utils';
import {useKeyboard, useMove} from '@react-aria/interactions';
import {useLocale} from '@react-aria/i18n';
import {useRef} from 'react';

export function useTableColumnResize(state, item, ref): any {
const stateRef = useRef(null);
// keep track of what the cursor on the body is so it can be restored back to that when done resizing
const cursor = useRef(null);
stateRef.current = state;

let {direction} = useLocale();
let {focusableProps} = useFocusable({excludeFromTabOrder: true}, ref);
let {keyboardProps} = useKeyboard({
onKeyDown: (e) => {
if (e.key === 'Tab') {
// useKeyboard stops propagation by default. We want to continue propagation for tab so focus leaves the table
e.continuePropagation();
}
if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') {
// switch focus back to the column header on escape
const columnHeader = ref.current.previousSibling;
if (columnHeader) {
focusSafely(columnHeader);
}
}
}
});

const columnResizeWidthRef = useRef(null);
const {moveProps} = useMove({
onMoveStart() {
stateRef.current.onColumnResizeStart();
columnResizeWidthRef.current = stateRef.current.getColumnWidth(item.key);
cursor.current = document.body.style.cursor;
document.body.style.setProperty('cursor', 'col-resize');
},
onMove({deltaX, pointerType}) {
if (direction === 'rtl') {
deltaX *= -1;
}
// if moving up/down only, no need to resize
if (deltaX !== 0) {
if (pointerType === 'keyboard') {
deltaX *= 10;
}
columnResizeWidthRef.current += deltaX;
stateRef.current.onColumnResize(item, columnResizeWidthRef.current);
}
},
onMoveEnd() {
stateRef.current.onColumnResizeEnd();
columnResizeWidthRef.current = 0;
document.body.style.cursor = cursor.current;
}
});

return {
resizerProps: {
...mergeProps(moveProps, focusableProps, keyboardProps)
}
};
}
3 changes: 3 additions & 0 deletions packages/@react-spectrum/table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"url": "https://github.com/adobe/react-spectrum"
},
"dependencies": {
"@react-aria/button": "^3.4.1",
"@babel/runtime": "^7.6.2",
"@react-aria/focus": "^3.5.3",
"@react-aria/grid": "^3.2.4",
Expand All @@ -40,7 +41,9 @@
"@react-aria/utils": "^3.11.3",
"@react-aria/virtualizer": "^3.3.8",
"@react-aria/visually-hidden": "^3.2.6",
"@react-spectrum/button": "^3.7.1",
"@react-spectrum/checkbox": "^3.3.2",
"@react-spectrum/menu": "^3.6.1",
"@react-spectrum/progress": "^3.1.6",
"@react-spectrum/tooltip": "^3.1.7",
"@react-spectrum/utils": "^3.6.6",
Expand Down
32 changes: 32 additions & 0 deletions packages/@react-spectrum/table/src/Resizer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable jsx-a11y/role-supports-aria-props */
import {classNames} from '@react-spectrum/utils';
import {FocusRing} from '@react-aria/focus';
import React from 'react';
import styles from '@adobe/spectrum-css-temp/components/table/vars.css';
import {useTableColumnResize} from '@react-aria/table/src/useTableColumnResize';
import {useTableContext} from './TableView';


function Resizer(props, ref) {
const {item} = props;
let state = useTableContext();
let {resizerProps} = useTableColumnResize(state, item, ref);
return (
<FocusRing focusRingClass={classNames(styles, 'focus-ring')}>
<div
ref={ref}
{...resizerProps}
className={classNames(styles, 'spectrum-Table-columnResizer')}
role="separator"
aria-orientation="vertical"
aria-label="Resize column"
aria-labelledby={item.key}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't actually point to a id that exists in the DOM. Maybe you could use getColumnHeaderId?

As an aside I noticed that the column headers also have lost their "columnheader" role in favor of the "button" role provided by MenuTrigger, note to self to double check that the rest of the attributes are still valid (it seems ok so far?)

aria-valuenow={state.getColumnWidth(item.key)}
aria-valuemin={state.getColumnMinWidth(item.key)}
aria-valuemax={state.getColumnMaxWidth(item.key)} />
</FocusRing>
);
}

const _Resizer = React.forwardRef(Resizer);
export {_Resizer as Resizer};
Loading