Skip to content

Commit

Permalink
fix: #550
Browse files Browse the repository at this point in the history
  • Loading branch information
xobotyi committed Aug 23, 2019
1 parent 8c2658f commit c9bb418
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/useLockBodyScroll.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

## Usage
## Usage

```jsx
import {useLockBodyScroll, useToggle} from 'react-use';
Expand Down
78 changes: 51 additions & 27 deletions src/useLockBodyScroll.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,58 @@
import { useEffect } from 'react';
import { RefObject, useEffect, useRef } from 'react';

let counter = 0;
let originalOverflow: string | null = null;
export function getClosestBody(el: Element | HTMLElement | HTMLIFrameElement | null): HTMLElement | null {
if (!el) {
return null;
} else if (el.tagName === 'BODY') {
return el as HTMLElement;
} else if (el.tagName === 'IFRAME') {
const document = (el as HTMLIFrameElement).contentDocument;
return document ? document.body : null;
} else if (!(el as HTMLElement).offsetParent) {
return null;
}

const lock = () => {
originalOverflow = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = 'hidden';
};
return getClosestBody((el as HTMLElement).offsetParent!);
}

const unlock = () => {
document.body.style.overflow = originalOverflow;
originalOverflow = null;
};
export interface BodyInfoItem {
counter: number;
initialOverflow: string | null;
}

const increment = () => {
counter++;
if (counter === 1) {
lock();
}
};
const bodies: Map<HTMLElement, BodyInfoItem> = new Map();

const decrement = () => {
counter--;
if (counter === 0) {
unlock();
}
};
const doc: Document | undefined = typeof document === 'object' ? document : undefined;

export default doc
? function useLockBodyMock(_locked: boolean, _elementRef?: RefObject<HTMLElement>) {}
: function useLockBody(locked: boolean, elementRef?: RefObject<HTMLElement>) {
elementRef = elementRef || useRef(doc!.body);

useEffect(() => {
const body = getClosestBody(elementRef!.current);
if (!body) {
return;
}

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

export default useLockBodyScroll;
if (locked) {
if (!bodyInfo) {
bodies.set(body, { counter: 1, initialOverflow: body.style.overflow });
body.style.overflow = 'hidden';
} else {
bodies.set(body, { counter: bodyInfo.counter + 1, initialOverflow: bodyInfo.initialOverflow });
}
} else {
if (bodyInfo) {
if (bodyInfo.counter === 1) {
bodies.delete(body);
body.style.overflow = bodyInfo.initialOverflow;
} else {
bodies.set(body, { counter: bodyInfo.counter - 1, initialOverflow: bodyInfo.initialOverflow });
}
}
}
}, [locked, elementRef.current]);
};

0 comments on commit c9bb418

Please sign in to comment.