Use hard scroll lock only for ios

This commit is contained in:
Tanya Fomina 2022-05-01 18:02:45 +08:00
parent 1d26770880
commit 662a7a1c44
4 changed files with 82 additions and 33 deletions

View file

@ -769,3 +769,13 @@ export function cacheable<Target, Value, Arguments extends unknown[] = unknown[]
export function isMobileScreen(): boolean {
return window.matchMedia('(max-width: 650px)').matches;
}
/**
* True if current device runs iOS
*/
export const isIosDevice =
typeof window !== 'undefined' &&
window.navigator &&
window.navigator.platform &&
(/iP(ad|hone|od)/.test(window.navigator.platform) ||
(window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1));

View file

@ -4,7 +4,7 @@ import Flipper from '../flipper';
import SearchInput from './search-input';
import EventsDispatcher from './events';
import { isMobileScreen, keyCodes, cacheable } from '../utils';
import * as scrollLocker from './scroll-locker';
import ScrollLocker from './scroll-locker';
/**
* Describe parameters for rendering the single item of Popover
@ -147,6 +147,11 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
};
}
/**
* ScrollLocker instance
*/
private scrollLocker = new ScrollLocker()
/**
* Creates the Popover
*
@ -198,7 +203,7 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
}
if (isMobileScreen()) {
scrollLocker.lock();
this.scrollLocker.lock();
}
}
@ -212,7 +217,7 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
this.flipper.deactivate();
if (isMobileScreen()) {
scrollLocker.unlock();
this.scrollLocker.unlock();
}
}

View file

@ -1,34 +1,64 @@
import { isIosDevice } from '../utils';
/**
* Stores last scroll offset
* Utility allowing to lock body scroll on demand
*/
let scrollPosition = null;
/**
* Name of the class applied to body element to lock scroll
*/
const scrollLockedClassName = 'ce-scroll-locked';
/**
* Lock body element scroll
*/
export function lock(): void {
scrollPosition = window.pageYOffset;
document.documentElement.style.setProperty(
'--window-scroll-offset',
`${scrollPosition}px`
);
document.body.classList.add(scrollLockedClassName);
}
/**
* Unlocks body element scroll
*/
export function unlock(): void {
document.body.classList.remove(scrollLockedClassName);
if (scrollPosition !== null) {
window.scrollTo(0, scrollPosition);
export default class ScrollLocker {
/**
* Style classes
*/
private static CSS = {
scrollLocked: 'ce-scroll-locked',
scrollLockedHard: 'ce-scroll-locked--hard',
}
scrollPosition = null;
}
/**
* Stores scroll position, used for hard scroll lock
*/
private scrollPosition: null|number
/**
* Locks body element scroll
*/
public lock(): void {
if (isIosDevice) {
this.lockHard();
} else {
document.body.classList.add(ScrollLocker.CSS.scrollLocked);
}
}
/**
* Unlocks body element scroll
*/
public unlock(): void {
if (isIosDevice) {
this.unlockHard();
} else {
document.body.classList.remove(ScrollLocker.CSS.scrollLocked);
}
}
/**
* Locks scroll in a hard way (via setting fixed position to body element)
*/
private lockHard(): void {
this.scrollPosition = window.pageYOffset;
document.documentElement.style.setProperty(
'--window-scroll-offset',
`${this.scrollPosition}px`
);
document.body.classList.add(ScrollLocker.CSS.scrollLockedHard);
}
/**
* Unlocks hard scroll lock
*/
private unlockHard(): void {
document.body.classList.remove(ScrollLocker.CSS.scrollLockedHard);
if (this.scrollPosition !== null) {
window.scrollTo(0, this.scrollPosition);
}
this.scrollPosition = null;
}
}

View file

@ -130,6 +130,10 @@
.ce-scroll-locked {
overflow: hidden;
}
.ce-scroll-locked--hard {
overflow: hidden;
top: calc(-1 * var(--window-scroll-offset));
position: fixed;
width: 100%;