Skip to content

Commit d64eaad

Browse files
authored
Prevent false positives in getScrollableParent() (#2626)
* Update domUtils.ts * tests * Update domUtils.ts * Additional test * Improve examples * More tests * cleanup
1 parent 2c8ddea commit d64eaad

File tree

10 files changed

+1486
-2
lines changed

10 files changed

+1486
-2
lines changed

packages/core/src/domUtils.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,60 @@ const elementInViewport = (el: HTMLElement) => {
99
}
1010

1111
export const getScrollableParent = (element: HTMLElement | null): HTMLElement | null => {
12+
const allowsVerticalScroll = (el: HTMLElement): boolean => {
13+
const computedStyle = window.getComputedStyle(el)
14+
15+
if (['scroll', 'overlay'].includes(computedStyle.overflowY)) {
16+
return true
17+
}
18+
19+
if (computedStyle.overflowY !== 'auto') {
20+
return false
21+
}
22+
23+
if (['visible', 'clip'].includes(computedStyle.overflowX)) {
24+
return true
25+
}
26+
27+
return hasDimensionConstraint(computedStyle.maxHeight, el.style.height)
28+
}
29+
30+
const allowsHorizontalScroll = (el: HTMLElement): boolean => {
31+
const computedStyle = window.getComputedStyle(el)
32+
33+
if (['scroll', 'overlay'].includes(computedStyle.overflowX)) {
34+
return true
35+
}
36+
37+
if (computedStyle.overflowX !== 'auto') {
38+
return false
39+
}
40+
41+
if (['visible', 'clip'].includes(computedStyle.overflowY)) {
42+
return true
43+
}
44+
45+
return hasDimensionConstraint(computedStyle.maxWidth, el.style.width)
46+
}
47+
48+
const hasDimensionConstraint = (computedMaxDimension: string, inlineStyleDimension: string): boolean => {
49+
if (computedMaxDimension && computedMaxDimension !== 'none' && computedMaxDimension !== '0px') {
50+
return true
51+
}
52+
53+
if (inlineStyleDimension && inlineStyleDimension !== 'auto' && inlineStyleDimension !== '0') {
54+
return true
55+
}
56+
57+
return false
58+
}
59+
1260
let parent = element?.parentElement
1361

1462
while (parent) {
15-
const overflowY = window.getComputedStyle(parent).overflowY
63+
const allowsScroll = allowsVerticalScroll(parent) || allowsHorizontalScroll(parent)
1664

17-
if (overflowY === 'auto' || overflowY === 'scroll') {
65+
if (window.getComputedStyle(parent).display !== 'contents' && allowsScroll) {
1866
return parent
1967
}
2068

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { InfiniteScroll } from '@inertiajs/react'
2+
import { User } from './UserCard'
3+
4+
export default ({ users }: { users: { data: User[] } }) => {
5+
return (
6+
<div style={{ overflowX: 'hidden' }}>
7+
<InfiniteScroll data="users">
8+
{users.data.map((user) => (
9+
<div key={user.id} data-user-id={user.id}>
10+
<div>{user.name}</div>
11+
</div>
12+
))}
13+
</InfiniteScroll>
14+
</div>
15+
)
16+
}

0 commit comments

Comments
 (0)