From 201479a11480e47864389c0bf4c4d7bb7f6d743f Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Tue, 14 Feb 2023 13:46:11 -0800 Subject: [PATCH 1/9] adding separate mode for enabling resize this make it so the user would have to hit Enter to start resizing. This allows us to have the resizers always be visible and still preserve grid navigation between columns. --- .../@react-aria/interactions/src/useMove.ts | 22 ++++-- packages/@react-aria/table/docs/useTable.mdx | 68 ++++++++++++------- .../table/src/useTableColumnResize.ts | 8 ++- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/packages/@react-aria/interactions/src/useMove.ts b/packages/@react-aria/interactions/src/useMove.ts index 5f42caf5ac4..c0dbbbc1165 100644 --- a/packages/@react-aria/interactions/src/useMove.ts +++ b/packages/@react-aria/interactions/src/useMove.ts @@ -27,13 +27,17 @@ interface EventBase { altKey: boolean } +export interface MoveProps extends MoveEvents { + disableLeftRightHandling?: boolean +} + /** * Handles move interactions across mouse, touch, and keyboard, including dragging with * the mouse or touch, and using the arrow keys. Normalizes behavior across browsers and * platforms, and ignores emulated mouse events on touch devices. */ -export function useMove(props: MoveEvents): MoveResult { - let {onMoveStart, onMove, onMoveEnd} = props; +export function useMove(props: MoveProps): MoveResult { + let {onMoveStart, onMove, onMoveEnd, disableLeftRightHandling} = props; let state = useRef<{ didMove: boolean, @@ -198,14 +202,18 @@ export function useMove(props: MoveEvents): MoveResult { case 'Left': case 'ArrowLeft': e.preventDefault(); - e.stopPropagation(); - triggerKeyboardMove(e, -1, 0); + if (!disableLeftRightHandling) { + e.stopPropagation(); + triggerKeyboardMove(e, -1, 0); + } break; case 'Right': case 'ArrowRight': e.preventDefault(); - e.stopPropagation(); - triggerKeyboardMove(e, 1, 0); + if (!disableLeftRightHandling) { + e.stopPropagation(); + triggerKeyboardMove(e, 1, 0); + } break; case 'Up': case 'ArrowUp': @@ -223,7 +231,7 @@ export function useMove(props: MoveEvents): MoveResult { }; return moveProps; - }, [state, onMoveStart, onMove, onMoveEnd, addGlobalListener, removeGlobalListener]); + }, [state, onMoveStart, onMove, onMoveEnd, addGlobalListener, removeGlobalListener, disableLeftRightHandling]); return {moveProps}; } diff --git a/packages/@react-aria/table/docs/useTable.mdx b/packages/@react-aria/table/docs/useTable.mdx index 3abd5836698..c39341fe48b 100644 --- a/packages/@react-aria/table/docs/useTable.mdx +++ b/packages/@react-aria/table/docs/useTable.mdx @@ -989,32 +989,20 @@ should cause focus to shift to the resizer itself, displaying the resizer for to accordingly. ```tsx example export=true render=false -import {useDescription} from '@react-aria/utils'; -import {useHover, usePress} from '@react-aria/interactions'; +// Reuse the Button from your component library. See below for details. +import {Button} from 'your-component-library'; function ResizableTableColumnHeader({column, state, layoutState, onResizeStart, onResize, onResizeEnd}) { - let {widths} = layoutState; + let {widths} = layoutState; let ref = useRef(null); let resizerRef = useRef(null); let {columnHeaderProps} = useTableColumnHeader({node: column}, state, ref); let {isFocusVisible, focusProps} = useFocusRing(); - let {hoverProps, isHovered} = useHover({}); - let showResizer = isHovered || layoutState.resizingColumn === column.key; let allowsResizing = column.props.allowsResizing; - let {pressProps} = usePress({ - isDisabled: !allowsResizing, - onPress() { - layoutState.onColumnResizeStart(column.key); - // Brief delay before moving focus to resizer input for screenreaders/Safari - setTimeout(() => resizerRef.current?.focus(), 50); - } - }); - let descriptionProps = useDescription('Press to start resizing the column.'); - return ( 1 ? 'center' : 'left', @@ -1029,17 +1017,22 @@ function ResizableTableColumnHeader({column, state, layoutState, onResizeStart, }} ref={ref}>
-
{column.rendered} -
+ {allowsResizing && - + }
@@ -1061,15 +1054,17 @@ Note that we apply `visibility: hidden` to hide the resizer so that we reserve s import {useTableColumnResize} from '@react-aria/table'; const Resizer = React.forwardRef((props, ref) => { - let {column, layoutState, onResizeStart, onResize, onResizeEnd, triggerRef, showResizer} = props; + let {column, layoutState, onResizeStart, onResize, onResizeEnd, triggerRef} = props; let {resizerProps, inputProps} = useTableColumnResize({ column, label: 'Resizer', onResizeStart, onResize, onResizeEnd, - triggerRef + triggerRef, + activateResizeManually: true }, layoutState, ref); + let {focusProps, isFocusVisible} = useFocusRing(); return (
{ height: 'auto', border: '2px', borderStyle: 'none solid', - borderColor: layoutState.resizingColumn === column.key ? 'orange' : 'grey', + borderColor: layoutState.resizingColumn === column.key || isFocusVisible ? 'orange' : 'grey', touchAction: 'none', flex: '0 0 auto', boxSizing: 'border-box', - visibility: showResizer ? 'visible' : 'hidden', marginLeft: '4px' }} {...resizerProps}> + {...mergeProps(inputProps, focusProps)} />
); }); ``` +### Button + +The `Button` component is used in the above example to toggle the menu. It is built using the [useButton](useButton.html) hook, and can be shared with many other components. + +
+ Show code + +```tsx example export=true render=false +import {useButton} from '@react-aria/button'; + +function Button(props) { + let ref = useRef(null); + let {focusProps, isFocusVisible} = useFocusRing(); + let outline = isFocusVisible + ? '2px solid orange' + : 'none'; + let {buttonProps} = useButton(props, ref); + return ; +} +``` + +
+ + ### Resizable table body Similar to `TableRowGroup` and `TableHeaderRow`, `TableRow` and `TableCell` only require minor style changes to diff --git a/packages/@react-aria/table/src/useTableColumnResize.ts b/packages/@react-aria/table/src/useTableColumnResize.ts index aae52ed8362..b87232228ac 100644 --- a/packages/@react-aria/table/src/useTableColumnResize.ts +++ b/packages/@react-aria/table/src/useTableColumnResize.ts @@ -46,7 +46,8 @@ export interface AriaTableColumnResizeProps { /** Called for every resize event that results in new column sizes. */ onResize?: (widths: Map) => void, /** Called when resizing ends. */ - onResizeEnd?: (widths: Map) => void + onResizeEnd?: (widths: Map) => void, + activateResizeManually?: boolean } export interface AriaTableColumnResizeState extends Omit, 'widths'> {} @@ -58,7 +59,7 @@ export interface AriaTableColumnResizeState extends Omit