Skip to content

Commit 6d66d6e

Browse files
authored
Add body overflow hidden to useScrollLock (#832)
1 parent 9c17114 commit 6d66d6e

File tree

4 files changed

+49
-16
lines changed

4 files changed

+49
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
- `ActionListItem` no longer have shadow and cursor: pointer without an onClick
1818
- `ActionListItemColumn` aligns with header columns
19+
- `useScrollLock` no longer jitters on attempted scroll (used in modals and overlays)
1920

2021
## [0.7.28] - 2020-04-20
2122

packages/components/src/utils/useScrollLock.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@
2424
2525
*/
2626

27-
import { useContext, useEffect } from 'react'
27+
import once from 'lodash/once'
28+
import { useContext, useEffect, useRef } from 'react'
2829
import { ModalContext } from '../Modal/ModalContext'
2930
import { useToggle } from './useToggle'
3031
import { useCallbackRef } from './useCallbackRef'
3132

33+
function setBodyOverflowHidden() {
34+
document.body.style.overflow = 'hidden'
35+
}
36+
3237
export function useScrollLock(
3338
enabled = false,
3439
useCapture = false,
@@ -41,11 +46,20 @@ export function useScrollLock(
4146
const { disableScrollLock, enableScrollLock } = useContext(ModalContext)
4247
const { value, setOn, setOff } = useToggle(enabled)
4348

49+
// save the existing body overflow value
50+
const bodyOverflowRef = useRef(document.body.style.overflow)
51+
4452
useEffect(() => {
4553
let scrollTop = window.scrollY
4654
let scrollTarget: EventTarget | HTMLElement | null = document
4755

56+
const bodyOverflowCurrent = bodyOverflowRef.current
57+
const setBodyOverflowOnce = once(setBodyOverflowHidden)
58+
4859
function stopScroll(e: Event) {
60+
// setting overflow: hidden again here avoids conflicting enable / disable with nested scroll locks
61+
setBodyOverflowOnce()
62+
4963
if (e.target !== null && e.target !== scrollTarget) {
5064
scrollTarget = e.target
5165
scrollTop =
@@ -66,13 +80,16 @@ export function useScrollLock(
6680
if (element && value) {
6781
window.addEventListener('scroll', stopScroll, true)
6882
disableScrollLock && disableScrollLock()
83+
setBodyOverflowHidden()
6984
} else {
7085
window.removeEventListener('scroll', stopScroll, true)
7186
enableScrollLock && enableScrollLock()
87+
document.body.style.overflow = bodyOverflowCurrent
7288
}
7389

7490
return () => {
7591
window.removeEventListener('scroll', stopScroll, true)
92+
document.body.style.overflow = bodyOverflowCurrent
7693
}
7794
}, [value, element, useCapture, disableScrollLock, enableScrollLock])
7895

packages/playground/src/Popovers/Testing.tsx

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,19 @@ function PopoverFocusTrap() {
110110
aria-label="Fruits"
111111
defaultValue="1"
112112
/>
113+
<Paragraph>Long text</Paragraph>
114+
<Paragraph>Long text</Paragraph>
115+
<Paragraph>Long text</Paragraph>
116+
<Paragraph>Long text</Paragraph>
117+
<Paragraph>Long text</Paragraph>
118+
<Paragraph>Long text</Paragraph>
119+
<Paragraph>Long text</Paragraph>
120+
<Paragraph>Long text</Paragraph>
121+
<Paragraph>Long text</Paragraph>
122+
<Paragraph>Long text</Paragraph>
123+
<Paragraph>Long text</Paragraph>
124+
<Paragraph>Long text</Paragraph>
125+
<Paragraph>Long text</Paragraph>
113126
</PopoverContent>
114127
}
115128
>
@@ -136,18 +149,20 @@ function MenuOpenDialog() {
136149
Open Menu
137150
</Button>
138151
</MenuDisclosure>
139-
<MenuList>
140-
<DialogManager
141-
content={
142-
<ModalContent>
143-
<Paragraph>Some content inside the Dialog</Paragraph>
144-
<Button onClick={openAlert}>Open Alert</Button>
145-
</ModalContent>
146-
}
147-
>
148-
{(onClick) => <MenuItem onClick={onClick}>Open Modal</MenuItem>}
149-
</DialogManager>
150-
</MenuList>
152+
<DialogManager
153+
content={
154+
<ModalContent>
155+
<Paragraph>Some content inside the Dialog</Paragraph>
156+
<Button onClick={openAlert}>Open Alert</Button>
157+
</ModalContent>
158+
}
159+
>
160+
{(onClick) => (
161+
<MenuList>
162+
<MenuItem onClick={onClick}>Open Modal</MenuItem>
163+
</MenuList>
164+
)}
165+
</DialogManager>
151166
</Menu>
152167
</Box>
153168
)
@@ -343,7 +358,7 @@ function MovingTarget() {
343358

344359
export function TestPopovers() {
345360
return (
346-
<Box m="large" display="flex">
361+
<Box m="large" display="flex" height={1500}>
347362
<Box>
348363
<MenuOpenDialog />
349364
<Divider my="large" />

packages/playground/src/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
2727
import React from 'react'
2828
import ReactDOM from 'react-dom'
2929
import { ComponentsProvider } from '@looker/components'
30-
import { ActionListDemo } from './ActionList/ActionListDemo'
30+
import { TestPopovers } from './Popovers/Testing'
3131

3232
const App: React.FC = () => {
3333
return (
3434
<ComponentsProvider>
35-
<ActionListDemo />
35+
<TestPopovers />
3636
</ComponentsProvider>
3737
)
3838
}

0 commit comments

Comments
 (0)