diff --git a/packages/@react-aria/utils/src/scrollIntoView.ts b/packages/@react-aria/utils/src/scrollIntoView.ts index bf4623b2ade..5f140037a1a 100644 --- a/packages/@react-aria/utils/src/scrollIntoView.ts +++ b/packages/@react-aria/utils/src/scrollIntoView.ts @@ -73,23 +73,18 @@ export function scrollIntoView(scrollView: HTMLElement, element: HTMLElement) { * offsetLeft or offsetTop through intervening offsetParents. */ function relativeOffset(ancestor: HTMLElement, child: HTMLElement, axis: 'left'|'top') { - const prop = axis === 'left' ? 'offsetLeft' : 'offsetTop'; - let sum = 0; - while (child.offsetParent) { - sum += child[prop]; - if (child.offsetParent === ancestor) { - // Stop once we have found the ancestor we are interested in. - break; - } else if (child.offsetParent.contains(ancestor)) { - // If the ancestor is not `position:relative`, then we stop at - // _its_ offset parent, and we subtract off _its_ offset, so that - // we end up with the proper offset from child to ancestor. - sum -= ancestor[prop]; - break; - } - child = child.offsetParent as HTMLElement; - } - return sum; + let childRect = child.getBoundingClientRect(); + let ancestorRect = ancestor.getBoundingClientRect(); + + let viewportOffset = axis === 'left' + ? childRect.left - ancestorRect.left + : childRect.top - ancestorRect.top; + + let scrollAdjustment = axis === 'left' + ? ancestor.scrollLeft + : ancestor.scrollTop; + + return viewportOffset + scrollAdjustment; } /** diff --git a/packages/react-aria-components/stories/GridList.stories.tsx b/packages/react-aria-components/stories/GridList.stories.tsx index d896c5d882b..bd38cfee3b5 100644 --- a/packages/react-aria-components/stories/GridList.stories.tsx +++ b/packages/react-aria-components/stories/GridList.stories.tsx @@ -199,3 +199,57 @@ export function TagGroupInsideGridList() { ); } + +export function GridListScrollIntoView() { + let items: {id: number, name: string}[] = []; + for (let i = 0; i < 100; i++) { + items.push({id: i, name: `Item ${i}`}); + } + + let list = useListData({ + initialItems: items + }); + + const getElement = (id: number) => document.querySelector(`[data-key="${id}"]`) as HTMLElement; + + const rowHeight = 25; + + return ( + <> +
+ + {item => ( + + {item.name} + )} + +
+ + + + ); +}