fix: Prevent content scrolling behind main menu (part 1) (#35173)
This commit is contained in:
parent
c52848b444
commit
c6dddbb66e
7 changed files with 83 additions and 41 deletions
|
|
@ -0,0 +1,71 @@
|
|||
import { useLayoutEffect, useEffect, useState } from 'react';
|
||||
|
||||
import { createAppSelector, useAppSelector } from 'mastodon/store';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
const getShouldLockBodyScroll = createAppSelector(
|
||||
[
|
||||
(state) => state.navigation.open,
|
||||
(state) => state.modal.get('stack').size > 0,
|
||||
],
|
||||
(isMobileMenuOpen: boolean, isModalOpen: boolean) => {
|
||||
return isMobileMenuOpen || isModalOpen;
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* This component locks scrolling on the `body` element when
|
||||
* `getShouldLockBodyScroll` returns true.
|
||||
*
|
||||
* The scrollbar width is taken into account and written to
|
||||
* a CSS custom property `--root-scrollbar-width`
|
||||
*/
|
||||
|
||||
export const BodyScrollLock: React.FC = () => {
|
||||
const shouldLockBodyScroll = useAppSelector(getShouldLockBodyScroll);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
document.body.classList.toggle('with-modals--active', shouldLockBodyScroll);
|
||||
}, [shouldLockBodyScroll]);
|
||||
|
||||
const [scrollbarWidth, setScrollbarWidth] = useState(() =>
|
||||
getScrollbarWidth(),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setScrollbarWidth(getScrollbarWidth());
|
||||
};
|
||||
window.addEventListener('resize', handleResize, { passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Inject style element to make scrollbar width available
|
||||
// as CSS custom property
|
||||
useLayoutEffect(() => {
|
||||
const nonce = document
|
||||
.querySelector('meta[name=style-nonce]')
|
||||
?.getAttribute('content');
|
||||
|
||||
if (nonce) {
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.nonce = nonce;
|
||||
styleEl.innerHTML = `
|
||||
:root {
|
||||
--root-scrollbar-width: ${scrollbarWidth}px;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(styleEl);
|
||||
|
||||
return () => {
|
||||
document.head.removeChild(styleEl);
|
||||
};
|
||||
}
|
||||
|
||||
return () => '';
|
||||
}, [scrollbarWidth]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
@ -20,7 +20,6 @@ import {
|
|||
IgnoreNotificationsModal,
|
||||
AnnualReportModal,
|
||||
} from 'mastodon/features/ui/util/async-components';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
import BundleContainer from '../containers/bundle_container';
|
||||
|
||||
|
|
@ -90,20 +89,6 @@ export default class ModalRoot extends PureComponent {
|
|||
backgroundColor: null,
|
||||
};
|
||||
|
||||
getSnapshotBeforeUpdate () {
|
||||
return { visible: !!this.props.type };
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState, { visible }) {
|
||||
if (visible) {
|
||||
document.body.classList.add('with-modals--active');
|
||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||
} else {
|
||||
document.body.classList.remove('with-modals--active');
|
||||
document.documentElement.style.marginRight = '0';
|
||||
}
|
||||
}
|
||||
|
||||
setBackgroundColor = color => {
|
||||
this.setState({ backgroundColor: color });
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue