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..4d5daa4c184 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: () => undefined,
+ 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 = indicatorRow.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);
+});