From 5e4b032aca9bb65cf29699e70e58bf41d1d2b873 Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Mon, 11 May 2026 14:34:15 +1000 Subject: [PATCH 1/8] fix: table resizing click stuck --- packages/react-aria-components/src/Table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index e020e0369ba..7bb0508ef47 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -1395,7 +1395,7 @@ export const ColumnResizer = forwardRef(function ColumnResizer( {isResizing && isMouseDown && ReactDOM.createPortal( -
, +
, document.body )} From 7fb76560f639a9cf1d490e9f452ab40d638d3d46 Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Mon, 11 May 2026 14:48:51 +1000 Subject: [PATCH 2/8] fix cursor styles --- packages/react-aria-components/src/Table.tsx | 5 ++++- .../react-aria-components/test/Table.test.js | 21 +++++++++++++++++++ .../src/table/useTableColumnResize.ts | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index 7bb0508ef47..1501347fa59 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -1379,7 +1379,10 @@ export const ColumnResizer = forwardRef(function ColumnResizer( } let DOMProps = filterDOMProps(props, {global: true}); + + // Cursor overlay is used to style the cursor against the entire screen. + // Do not turn off pointer events or the cursor will no longer be styled. return ( , +
, document.body )} diff --git a/packages/react-aria-components/test/Table.test.js b/packages/react-aria-components/test/Table.test.js index 1ab33d14ad9..5721d53039b 100644 --- a/packages/react-aria-components/test/Table.test.js +++ b/packages/react-aria-components/test/Table.test.js @@ -17,6 +17,7 @@ import { mockClickDefault, pointerMap, render, + screen, setupIntersectionObserverMock, triggerLongPress, within @@ -1837,6 +1838,26 @@ describe('Table', () => { let resizers = getAllByTestId('resizer'); expect(resizers).toHaveLength(5); }); + + describe('clicking directly on the resizer, no movement', () => { + installPointerEvent(); + it('should end resize when clicking directly on the resizer, no movement', async () => { + let {getAllByTestId, debug} = render(); + act(() => { + setInteractionModality('pointer'); + }); + let resizer = getAllByTestId('resizer')[0]; + fireEvent.pointerDown(resizer, {pointerType: 'mouse', pointerId: 1, pageX: 0, pageY: 30}); + expect(resizer).toHaveAttribute('data-resizing', 'true'); + // Fire events against the cursor overlay. It can't be pointer events none otherwise + // it will stop styling the cursor against the entire screen. + let cursorOverlay = screen.getByTestId('cursor-overlay'); + fireEvent.pointerUp(cursorOverlay, {pointerType: 'mouse', pointerId: 1, pageX: 0, pageY: 30}); + fireEvent.click(cursorOverlay); + act(() => jest.runAllTimers()); + expect(resizer).not.toHaveAttribute('data-resizing', 'true'); + }); + }); }); it('should support overriding table style', () => { diff --git a/packages/react-aria/src/table/useTableColumnResize.ts b/packages/react-aria/src/table/useTableColumnResize.ts index c74b6baf965..686f1d60221 100644 --- a/packages/react-aria/src/table/useTableColumnResize.ts +++ b/packages/react-aria/src/table/useTableColumnResize.ts @@ -294,6 +294,11 @@ export function useTableColumnResize( ) { endResize(item); } + }, + onPressEnd: e => { + if (state.resizingColumn != null) { + endResize(item); + } } }); let {visuallyHiddenProps} = useVisuallyHidden(); From f896a2cb7b0402071a8ecf36cc868ee3a55c39c2 Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Mon, 11 May 2026 14:58:34 +1000 Subject: [PATCH 3/8] fix formatting --- packages/react-aria-components/src/Table.tsx | 6 ++++-- packages/react-aria-components/test/Table.test.js | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index 1501347fa59..a4953a7eee0 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -1379,7 +1379,6 @@ export const ColumnResizer = forwardRef(function ColumnResizer( } let DOMProps = filterDOMProps(props, {global: true}); - // Cursor overlay is used to style the cursor against the entire screen. // Do not turn off pointer events or the cursor will no longer be styled. @@ -1398,7 +1397,10 @@ export const ColumnResizer = forwardRef(function ColumnResizer( {isResizing && isMouseDown && ReactDOM.createPortal( -
, +
, document.body )} diff --git a/packages/react-aria-components/test/Table.test.js b/packages/react-aria-components/test/Table.test.js index 5721d53039b..92132dd4f95 100644 --- a/packages/react-aria-components/test/Table.test.js +++ b/packages/react-aria-components/test/Table.test.js @@ -1852,7 +1852,12 @@ describe('Table', () => { // Fire events against the cursor overlay. It can't be pointer events none otherwise // it will stop styling the cursor against the entire screen. let cursorOverlay = screen.getByTestId('cursor-overlay'); - fireEvent.pointerUp(cursorOverlay, {pointerType: 'mouse', pointerId: 1, pageX: 0, pageY: 30}); + fireEvent.pointerUp(cursorOverlay, { + pointerType: 'mouse', + pointerId: 1, + pageX: 0, + pageY: 30 + }); fireEvent.click(cursorOverlay); act(() => jest.runAllTimers()); expect(resizer).not.toHaveAttribute('data-resizing', 'true'); From 609aec6e3db62b3f689a788f8900b4cabdad62d7 Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Mon, 11 May 2026 15:00:09 +1000 Subject: [PATCH 4/8] fix lint --- packages/react-aria-components/test/Table.test.js | 2 +- packages/react-aria/src/table/useTableColumnResize.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-aria-components/test/Table.test.js b/packages/react-aria-components/test/Table.test.js index 92132dd4f95..dde43b16b4f 100644 --- a/packages/react-aria-components/test/Table.test.js +++ b/packages/react-aria-components/test/Table.test.js @@ -1842,7 +1842,7 @@ describe('Table', () => { describe('clicking directly on the resizer, no movement', () => { installPointerEvent(); it('should end resize when clicking directly on the resizer, no movement', async () => { - let {getAllByTestId, debug} = render(); + let {getAllByTestId} = render(); act(() => { setInteractionModality('pointer'); }); diff --git a/packages/react-aria/src/table/useTableColumnResize.ts b/packages/react-aria/src/table/useTableColumnResize.ts index 686f1d60221..30f9d61a550 100644 --- a/packages/react-aria/src/table/useTableColumnResize.ts +++ b/packages/react-aria/src/table/useTableColumnResize.ts @@ -295,7 +295,7 @@ export function useTableColumnResize( endResize(item); } }, - onPressEnd: e => { + onPressEnd: () => { if (state.resizingColumn != null) { endResize(item); } From 626e7e1d8eda8f9abb8aacb28e418eb2e2c2b53d Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Thu, 25 Jun 2026 14:12:38 +1000 Subject: [PATCH 5/8] alternative approach following v3 --- .../react-spectrum/src/table/Resizer.tsx | 26 +++---------------- packages/react-aria-components/src/Table.tsx | 17 +++--------- .../react-aria-components/test/Table.test.js | 25 ------------------ .../src/table/useTableColumnResize.ts | 21 +++++++++------ 4 files changed, 19 insertions(+), 70 deletions(-) diff --git a/packages/@adobe/react-spectrum/src/table/Resizer.tsx b/packages/@adobe/react-spectrum/src/table/Resizer.tsx index 648e4720197..c3af2c5d954 100644 --- a/packages/@adobe/react-spectrum/src/table/Resizer.tsx +++ b/packages/@adobe/react-spectrum/src/table/Resizer.tsx @@ -8,7 +8,7 @@ import intlMessages from '../../intl/table/*.json'; import {isWebKit} from 'react-aria/private/utils/platform'; import {Key, RefObject} from '@react-types/shared'; import {mergeProps} from 'react-aria/mergeProps'; -import React, {createContext, ForwardedRef, useContext, useEffect, useState} from 'react'; +import React, {createContext, ForwardedRef, useContext} from 'react'; import ReactDOM from 'react-dom'; import styles from '@adobe/spectrum-css-temp/components/table/vars.css'; import {useLocale} from 'react-aria/I18nProvider'; @@ -63,27 +63,7 @@ export const Resizer = React.forwardRef(function Resizer( let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/table'); let {direction} = useLocale(); - let [isPointerDown, setIsPointerDown] = useState(false); - useEffect(() => { - let setDown = e => { - if (e.pointerType === 'mouse') { - setIsPointerDown(true); - } - }; - let setUp = e => { - if (e.pointerType === 'mouse') { - setIsPointerDown(false); - } - }; - document.addEventListener('pointerdown', setDown, {capture: true}); - document.addEventListener('pointerup', setUp, {capture: true}); - return () => { - document.removeEventListener('pointerdown', setDown, {capture: true}); - document.removeEventListener('pointerup', setUp, {capture: true}); - }; - }, []); - - let {inputProps, resizerProps} = useTableColumnResize( + let {inputProps, resizerProps, isMouseResizing} = useTableColumnResize( mergeProps(props, { 'aria-label': stringFormatter.format('columnResizer'), isDisabled: isEmpty @@ -128,7 +108,7 @@ export const Resizer = React.forwardRef(function Resizer( role="presentation" className={classNames(styles, 'spectrum-Table-columnResizerPlaceholder')} /> - +
diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index a779b20d5a7..45eb1d488bf 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -1374,7 +1374,7 @@ export const ColumnResizer = forwardRef(function ColumnResizer( let {onResizeStart, onResize, onResizeEnd} = useContext(ResizableTableContainerContext)!; let {column, triggerRef} = useContext(ColumnResizerContext)!; let inputRef = useRef(null); - let {resizerProps, inputProps, isResizing} = useTableColumnResize( + let {resizerProps, inputProps, isResizing, isMouseResizing} = useTableColumnResize( { column, 'aria-label': props['aria-label'] || stringFormatter.format('tableResizer'), @@ -1425,17 +1425,6 @@ export const ColumnResizer = forwardRef(function ColumnResizer( } }); - let [isMouseDown, setMouseDown] = useState(false); - let onPointerDown = (e: PointerEvent) => { - if (e.pointerType === 'mouse') { - setMouseDown(true); - } - }; - - if (!isResizing && isMouseDown) { - setMouseDown(false); - } - let DOMProps = filterDOMProps(props, {global: true}); // Cursor overlay is used to style the cursor against the entire screen. @@ -1444,7 +1433,7 @@ export const ColumnResizer = forwardRef(function ColumnResizer( {isResizing && - isMouseDown && + isMouseResizing && ReactDOM.createPortal(
{ let resizers = getAllByTestId('resizer'); expect(resizers).toHaveLength(5); }); - - describe('clicking directly on the resizer, no movement', () => { - installPointerEvent(); - it('should end resize when clicking directly on the resizer, no movement', async () => { - let {getAllByTestId} = render(); - act(() => { - setInteractionModality('pointer'); - }); - let resizer = getAllByTestId('resizer')[0]; - fireEvent.pointerDown(resizer, {pointerType: 'mouse', pointerId: 1, pageX: 0, pageY: 30}); - expect(resizer).toHaveAttribute('data-resizing', 'true'); - // Fire events against the cursor overlay. It can't be pointer events none otherwise - // it will stop styling the cursor against the entire screen. - let cursorOverlay = screen.getByTestId('cursor-overlay'); - fireEvent.pointerUp(cursorOverlay, { - pointerType: 'mouse', - pointerId: 1, - pageX: 0, - pageY: 30 - }); - fireEvent.click(cursorOverlay); - act(() => jest.runAllTimers()); - expect(resizer).not.toHaveAttribute('data-resizing', 'true'); - }); - }); }); it('should support overriding table style', () => { diff --git a/packages/react-aria/src/table/useTableColumnResize.ts b/packages/react-aria/src/table/useTableColumnResize.ts index 03ce283915d..e531fa65b16 100644 --- a/packages/react-aria/src/table/useTableColumnResize.ts +++ b/packages/react-aria/src/table/useTableColumnResize.ts @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {ChangeEvent, useCallback, useEffect, useRef} from 'react'; +import {ChangeEvent, useCallback, useEffect, useRef, useState} from 'react'; import {ColumnSize} from 'react-stately/useTableState'; import {DOMAttributes, FocusableElement, Key, RefObject} from '@react-types/shared'; import {focusSafely} from '../interactions/focusSafely'; @@ -38,6 +38,8 @@ export interface TableColumnResizeAria { resizerProps: DOMAttributes; /** Whether this column is currently being resized. */ isResizing: boolean; + /** Whether this column is currently being resized via a mouse drag (e.g. to render a cursor overlay). */ + isMouseResizing: boolean; } export interface AriaTableColumnResizeProps { @@ -94,6 +96,9 @@ export function useTableColumnResize( let lastSize = useRef | null>(null); let wasFocusedOnResizeStart = useRef(false); let editModeEnabled = state.tableState.isKeyboardNavigationDisabled; + // Whether a mouse drag-resize is active. Set on the first move (not on press) so a cursor + // overlay only mounts during an actual drag. See https://github.com/adobe/react-spectrum/issues/10032. + let [isMouseResizing, setMouseResizing] = useState(false); let {direction} = useLocale(); @@ -172,8 +177,11 @@ export function useTableColumnResize( const columnResizeWidthRef = useRef(0); const {moveProps} = useMove({ - onMoveStart() { + onMoveStart(e) { columnResizeWidthRef.current = state.getColumnWidth(item.key); + if (e.pointerType === 'mouse') { + setMouseResizing(true); + } startResize(item); }, onMove(e) { @@ -196,6 +204,7 @@ export function useTableColumnResize( onMoveEnd(e) { let {pointerType} = e; columnResizeWidthRef.current = 0; + setMouseResizing(false); if (pointerType === 'mouse' || (pointerType === 'touch' && wasFocusedOnResizeStart.current)) { endResize(item); } @@ -311,11 +320,6 @@ export function useTableColumnResize( ) { endResize(item); } - }, - onPressEnd: () => { - if (state.resizingColumn != null) { - endResize(item); - } } }); let {visuallyHiddenProps} = useVisuallyHidden(); @@ -337,6 +341,7 @@ export function useTableColumnResize( }, ariaProps ), - isResizing + isResizing, + isMouseResizing }; } From eb9e3e191ac2054cd96d84bea363eb5241930de9 Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Thu, 25 Jun 2026 14:14:34 +1000 Subject: [PATCH 6/8] lint --- packages/react-aria-components/test/Table.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-aria-components/test/Table.test.js b/packages/react-aria-components/test/Table.test.js index d3a0f81c314..70b65a09a37 100644 --- a/packages/react-aria-components/test/Table.test.js +++ b/packages/react-aria-components/test/Table.test.js @@ -17,7 +17,6 @@ import { mockClickDefault, pointerMap, render, - screen, setupIntersectionObserverMock, triggerLongPress, within From ff7431b584cdd558323cdc3142c6d64fc2dd3efe Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Thu, 25 Jun 2026 14:18:32 +1000 Subject: [PATCH 7/8] fix format --- packages/react-aria/src/table/useTableColumnResize.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react-aria/src/table/useTableColumnResize.ts b/packages/react-aria/src/table/useTableColumnResize.ts index e531fa65b16..a3c7413c454 100644 --- a/packages/react-aria/src/table/useTableColumnResize.ts +++ b/packages/react-aria/src/table/useTableColumnResize.ts @@ -38,7 +38,10 @@ export interface TableColumnResizeAria { resizerProps: DOMAttributes; /** Whether this column is currently being resized. */ isResizing: boolean; - /** Whether this column is currently being resized via a mouse drag (e.g. to render a cursor overlay). */ + /** + * Whether this column is currently being resized via a mouse drag (e.g. to render a cursor + * overlay). + */ isMouseResizing: boolean; } From f601f23c85428791225684077b9c8567b881fdea Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Thu, 25 Jun 2026 14:19:01 +1000 Subject: [PATCH 8/8] remove extra comment --- packages/react-aria/src/table/useTableColumnResize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-aria/src/table/useTableColumnResize.ts b/packages/react-aria/src/table/useTableColumnResize.ts index a3c7413c454..e3c1ae89334 100644 --- a/packages/react-aria/src/table/useTableColumnResize.ts +++ b/packages/react-aria/src/table/useTableColumnResize.ts @@ -100,7 +100,7 @@ export function useTableColumnResize( let wasFocusedOnResizeStart = useRef(false); let editModeEnabled = state.tableState.isKeyboardNavigationDisabled; // Whether a mouse drag-resize is active. Set on the first move (not on press) so a cursor - // overlay only mounts during an actual drag. See https://github.com/adobe/react-spectrum/issues/10032. + // overlay only mounts during an actual drag. let [isMouseResizing, setMouseResizing] = useState(false); let {direction} = useLocale();