From 71e2309841170959f7d501032fd53daaa02e7bba Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:53:51 -0700 Subject: [PATCH 1/3] fix: Scroll GridList to focused drop indicators Fixes #6492 --- .../react-aria-components/src/GridList.tsx | 1 + .../test/GridList.browser.test.tsx | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/packages/react-aria-components/src/GridList.tsx b/packages/react-aria-components/src/GridList.tsx index 22ea560aef6..f78c9c574be 100644 --- a/packages/react-aria-components/src/GridList.tsx +++ b/packages/react-aria-components/src/GridList.tsx @@ -769,6 +769,7 @@ function GridListDropIndicator(props: GridListDropIndicatorProps, ref: Forwarded let renderProps = useRenderProps({ ...otherProps, defaultClassName: 'react-aria-DropIndicator', + defaultStyle: {position: 'relative'}, values: { isDropTarget } diff --git a/packages/react-aria-components/test/GridList.browser.test.tsx b/packages/react-aria-components/test/GridList.browser.test.tsx index a8f13c11242..8cc6a88d062 100644 --- a/packages/react-aria-components/test/GridList.browser.test.tsx +++ b/packages/react-aria-components/test/GridList.browser.test.tsx @@ -10,6 +10,8 @@ * governing permissions and limitations under the License. */ +import {Button} from '../src/Button'; +import {DropIndicator, useDragAndDrop} from '../src/useDragAndDrop'; import {expect, it} from 'vitest'; import {GridLayout} from '../src/GridLayout'; import {GridList, GridListItem} from '../src/GridList'; @@ -17,8 +19,36 @@ import React, {useState} from 'react'; import {render} from 'vitest-browser-react'; import {Size} from 'react-stately/useVirtualizerState'; import {User} from '@react-aria/test-utils'; +import {userEvent} from 'vitest/browser'; import {Virtualizer} from '../src/Virtualizer'; +const reorderableItems = Array.from({length: 10}, (_, i) => ({id: i, name: `Item ${i}`})); + +function ReorderableGridList() { + let {dragAndDropHooks} = useDragAndDrop({ + getItems: keys => [...keys].map(key => ({'text/plain': String(key)})), + onReorder() {}, + renderDropIndicator: target => ( + + ) + }); + + return ( + + {item => ( + + + {item.name} + + )} + + ); +} + function Grid() { return ( { await button.click(); await expect(tester.getRows().length).toBeGreaterThan(0); }); + +it('scrolls focused drop indicators into view during keyboard reordering', async () => { + let {container} = await render(); + let gridlist = container.querySelector('[role=grid]') as HTMLElement; + let dragButton = container.querySelector('[aria-label="Drag Item 0"]') as HTMLElement; + dragButton.focus(); + + await userEvent.keyboard('{Enter}'); + + for (let i = 1; i <= 4; i++) { + await userEvent.keyboard('{ArrowDown}'); + let dropIndicator = document.activeElement as HTMLElement; + let indicatorRow = dropIndicator.closest('[role=row]') as HTMLElement; + let gridRect = gridlist.getBoundingClientRect(); + let indicatorRect = dropIndicator.getBoundingClientRect(); + + expect(dropIndicator).toHaveAttribute( + 'aria-label', + `Insert between Item ${i} and Item ${i + 1}` + ); + expect(dropIndicator).toHaveAttribute('role', 'button'); + expect(indicatorRow).toHaveStyle({ + backgroundColor: 'rgb(255, 0, 0)', + position: 'relative' + }); + expect(indicatorRect.top).toBeGreaterThanOrEqual(gridRect.top); + expect(indicatorRect.bottom).toBeLessThanOrEqual(gridRect.bottom); + } + + expect(gridlist.scrollTop).toBeGreaterThan(0); +}); From fdcfc121caaa0c8ce45a0af6283fbb8746949348 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sat, 8 Aug 2026 07:32:12 -0700 Subject: [PATCH 2/3] test: fix lint violation and measure the indicator row in scroll assertion --- packages/react-aria-components/test/GridList.browser.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-aria-components/test/GridList.browser.test.tsx b/packages/react-aria-components/test/GridList.browser.test.tsx index 8cc6a88d062..4d5daa4c184 100644 --- a/packages/react-aria-components/test/GridList.browser.test.tsx +++ b/packages/react-aria-components/test/GridList.browser.test.tsx @@ -27,7 +27,7 @@ const reorderableItems = Array.from({length: 10}, (_, i) => ({id: i, name: `Item function ReorderableGridList() { let {dragAndDropHooks} = useDragAndDrop({ getItems: keys => [...keys].map(key => ({'text/plain': String(key)})), - onReorder() {}, + onReorder: () => undefined, renderDropIndicator: target => ( ) @@ -164,7 +164,7 @@ it('scrolls focused drop indicators into view during keyboard reordering', async let dropIndicator = document.activeElement as HTMLElement; let indicatorRow = dropIndicator.closest('[role=row]') as HTMLElement; let gridRect = gridlist.getBoundingClientRect(); - let indicatorRect = dropIndicator.getBoundingClientRect(); + let indicatorRect = indicatorRow.getBoundingClientRect(); expect(dropIndicator).toHaveAttribute( 'aria-label', From 0621269918c363196a26dc496e75653093a70dcd Mon Sep 17 00:00:00 2001 From: mvanhorn Date: Thu, 13 Aug 2026 09:39:28 -0700 Subject: [PATCH 3/3] fix: addressed the remaining lint failure in GridList.browser.test.tsx b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addressed the remaining lint failure in [GridList.browser.test.tsx](/Users/mvanhorn/.osc/workspaces/adobe-react-spectrum-pr10437/packages/react-aria-components/test/GridList.browser.test.tsx:18) by wrapping programmatic focus in React’s `act()`. === CODEX STATUS === STATUS: PASS_WITH_ENV_BLOCKED CHANGES: - 1 file changed, 2 insertions, 2 deletions. - No upstream files materialized and no rebase attempted. VERIFICATION: - PASS: `yarn lint` --- packages/react-aria-components/test/GridList.browser.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-aria-components/test/GridList.browser.test.tsx b/packages/react-aria-components/test/GridList.browser.test.tsx index 4d5daa4c184..301b42a5697 100644 --- a/packages/react-aria-components/test/GridList.browser.test.tsx +++ b/packages/react-aria-components/test/GridList.browser.test.tsx @@ -15,7 +15,7 @@ import {DropIndicator, useDragAndDrop} from '../src/useDragAndDrop'; import {expect, it} from 'vitest'; import {GridLayout} from '../src/GridLayout'; import {GridList, GridListItem} from '../src/GridList'; -import React, {useState} from 'react'; +import React, {act, useState} from 'react'; import {render} from 'vitest-browser-react'; import {Size} from 'react-stately/useVirtualizerState'; import {User} from '@react-aria/test-utils'; @@ -155,7 +155,7 @@ it('scrolls focused drop indicators into view during keyboard reordering', async let {container} = await render(); let gridlist = container.querySelector('[role=grid]') as HTMLElement; let dragButton = container.querySelector('[aria-label="Drag Item 0"]') as HTMLElement; - dragButton.focus(); + act(() => dragButton.focus()); await userEvent.keyboard('{Enter}');