Skip to content

Commit

Permalink
feat: add useLockBodyScroll hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Mar 24, 2019
2 parents c170f1e + 9bb7047 commit d990db4
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -72,6 +72,7 @@
- [`useCss`](./docs/useCss.md) — dynamically adjusts CSS.
- [`useFavicon`](./docs/useFavicon.md) — sets favicon of the page.
- [`useLocalStorage`](./docs/useLocalStorage.md) — manages a value in `localStorage`.
- [`useLockBodyScroll`](./docs/useLockBodyScroll.md) — lock scrolling of the body element.
- [`useSessionStorage`](./docs/useSessionStorage.md) — manages a value in `sessionStorage`.
- [`useTitle`](./docs/useTitle.md) — sets title of the page.
- [`useDebounce`](./docs/useDebounce.md) — debounces a function.
Expand Down
31 changes: 31 additions & 0 deletions docs/useLockBodyScroll.md
@@ -0,0 +1,31 @@
# `useLockBodyScroll`

React side-effect hook that locks scrolling on the body element. Useful for modal and other overlay components.

## Usage

```jsx
import {useLockBodyScroll, useToggle} from 'react-use';

const Demo = () => {
const [locked, toggleLocked] = useToggle(false)

useLockBodyScroll(locked);

return (
<div>
<button onClick={() => toggleLocked()}>
{locked ? 'Unlock' : 'Lock'}
</button>
</div>
);
};
```

## Reference

```ts
useToggle(enabled?: boolean = true);
```

- `enabled` &mdash; Hook will lock scrolling on the body element if `true`, defaults to `true`
38 changes: 38 additions & 0 deletions src/__stories__/useLockBodyScroll.story.tsx
@@ -0,0 +1,38 @@
import {storiesOf} from '@storybook/react';
import * as React from 'react';
import {useLockBodyScroll, useToggle} from '..';
import ShowDocs from '../util/ShowDocs';

const Demo = () => {
const [locked, toggleLocked] = useToggle(false)
useLockBodyScroll(locked);

return (
<div style={{height: '200vh'}}>
<button onClick={() => toggleLocked()} style={{position: 'fixed', left: 0}}>
{locked ? 'Unlock' : 'Lock'}
</button>
</div>
);
};

const AnotherComponent = () => {
const [locked, toggleLocked] = useToggle(false)
useLockBodyScroll(locked);

return (
<button onClick={() => toggleLocked()} style={{position: 'fixed', left: 0, top: 40}}>
{locked ? 'Unlock' : 'Lock'}
</button>
);
};

storiesOf('Side effects|useLockBodyScroll', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useLockBodyScroll.md')} />)
.add('Demo', () => <Demo/>)
.add('Two hooks on page', () =>
<>
<AnotherComponent />
<Demo />
</>
)
2 changes: 2 additions & 0 deletions src/index.ts
Expand Up @@ -21,6 +21,7 @@ import useLifecycles from './useLifecycles';
import useList from './useList';
import useLocalStorage from './useLocalStorage';
import useLocation from './useLocation';
import useLockBodyScroll from './useLockBodyScroll';
import useLogger from './useLogger';
import useMap from './useMap';
import useMedia from './useMedia';
Expand Down Expand Up @@ -77,6 +78,7 @@ export {
useList,
useLocalStorage,
useLocation,
useLockBodyScroll,
useLogger,
useMap,
useMedia,
Expand Down
30 changes: 30 additions & 0 deletions src/useLockBodyScroll.ts
@@ -0,0 +1,30 @@
import {useEffect} from 'react';

let counter = 0;
let originalOverflow: string | null = null;

const lock = () => {
originalOverflow = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = 'hidden';
};

const unlock = () => {
document.body.style.overflow = originalOverflow;
originalOverflow = null;
};

const increment = () => {
counter++;
if (counter === 1) lock();
};

const decrement = () => {
counter--;
if (counter === 0) unlock();
};

const useLockBodyScroll = (enabled: boolean = true) => {
useEffect(() => enabled ? (increment(), decrement) : undefined, [enabled]);
}

export default useLockBodyScroll;

0 comments on commit d990db4

Please sign in to comment.