@redocly/theme
Version:
Shared UI components lib
57 lines (45 loc) • 1.78 kB
text/typescript
import { useEffect, useRef } from 'react';
export function useModalScrollLock(isOpen: boolean): void {
const originalBodyStylesRef = useRef<{
overflow: string;
paddingRight: string;
scrollbarWidth: string | null;
} | null>(null);
useEffect(() => {
if (typeof window === 'undefined' || typeof document === 'undefined') {
return;
}
const { body, documentElement } = document;
const restoreOriginalBodyStyles = () => {
if (!originalBodyStylesRef.current) return;
const { overflow, paddingRight, scrollbarWidth } = originalBodyStylesRef.current;
body.style.overflow = overflow;
body.style.paddingRight = paddingRight;
if (scrollbarWidth) {
documentElement.style.setProperty('--modal-scrollbar-width', scrollbarWidth);
} else {
documentElement.style.removeProperty('--modal-scrollbar-width');
}
originalBodyStylesRef.current = null;
};
if (isOpen && !originalBodyStylesRef.current) {
originalBodyStylesRef.current = {
overflow: body.style.overflow,
paddingRight: body.style.paddingRight,
scrollbarWidth: documentElement.style.getPropertyValue('--modal-scrollbar-width') || null,
};
const scrollbarWidth = window.innerWidth - documentElement.clientWidth;
body.style.overflow = 'hidden';
if (scrollbarWidth > 0) {
body.style.paddingRight = `${scrollbarWidth}px`;
documentElement.style.setProperty('--modal-scrollbar-width', `${scrollbarWidth}px`);
}
} else if (!isOpen && originalBodyStylesRef.current) {
restoreOriginalBodyStyles();
}
// Cleanup only if component unmounts while modal is open
return () => {
restoreOriginalBodyStyles();
};
}, [isOpen]);
}