Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ModalRoot/ModalPage/PullToRefresh): Disable native pull-to-refresh #6004

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/vkui/src/components/ModalRoot/ModalRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,29 @@ describe.each([
clickFade();
expect(onClose).toBeCalledTimes(1);
});

it('disables native pull-to-refresh when modal is open', () => {
const modals = [<ModalPage id="m" key="m" />, <ModalPage id="other" key="o" />];

const component = render(<ModalRoot activeModal={null}>{modals}</ModalRoot>, {
baseElement: document.documentElement,
});
runAllTimers();

expect(document.querySelector('.vkui--modal-overscroll-behavior')).toBeFalsy();

component.rerender(<ModalRoot activeModal="m">{modals}</ModalRoot>);
runAllTimers();

if (name === 'ModalRootTouch') {
expect(document.querySelector('.vkui--modal-overscroll-behavior')).toBeTruthy();
} else {
expect(document.querySelector('.vkui--modal-overscroll-behavior')).toBeFalsy();
}

component.rerender(<ModalRoot activeModal={null}>{modals}</ModalRoot>);
runAllTimers();

expect(document.querySelector('.vkui--modal-overscroll-behavior')).toBeFalsy();
});
});
10 changes: 9 additions & 1 deletion packages/vkui/src/components/ModalRoot/ModalRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,22 @@ class ModalRootTouchComponent extends React.Component<
this.documentScrolling = enabled;

if (enabled) {
// Здесь нужен последний аргумент с такими же параметрами, потому что
// восстанавливаем значение overscroll behavior
// eslint-disable-next-line no-restricted-properties
this.document.documentElement.classList.remove('vkui--modal-overscroll-behavior');

// некоторые браузеры на странных вендорах типа Meizu не удаляют обработчик.
// https://github.com/VKCOM/VKUI/issues/444
this.window.removeEventListener('touchmove', this.preventTouch, {
// @ts-expect-error: TS2769 В интерфейсе EventListenerOptions нет поля passive
passive: false,
});
} else {
// отключаем нативный pull-to-refresh при открытом модальном окне
// чтобы он не срабатывал при закрытии модалки смахиванием вниз
// eslint-disable-next-line no-restricted-properties
this.document.documentElement.classList.add('vkui--modal-overscroll-behavior');

this.window.addEventListener('touchmove', this.preventTouch, {
passive: false,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,23 @@ describe('PullToRefresh', () => {
expect(hasSpinner()).toBe(false);
});
});

test('disables native pull-to-refresh while pulling', () => {
const component = render(
<ConfigProvider platform={Platform.IOS}>
<PullToRefresh onRefresh={noop} data-testid="xxx" />
</ConfigProvider>,
{ baseElement: document.documentElement },
);

expect(document.querySelector('.vkui--disable-overscroll-behavior')).toBeFalsy();

// класс присутствует пока пуллим
firePull(component.getByTestId('xxx'), { end: false });
expect(document.querySelector('.vkui--disable-overscroll-behavior')).toBeTruthy();

// класс удаляется когда отпускаем
fireEvent.mouseUp(component.getByTestId('xxx'), { clientY: 500 });
expect(document.querySelector('.vkui--disable-overscroll-behavior')).toBeFalsy();
});
});
29 changes: 11 additions & 18 deletions packages/vkui/src/components/PullToRefresh/PullToRefresh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useTimeout } from '../../hooks/useTimeout';
import { DOMProps, useDOM } from '../../lib/dom';
import { Platform } from '../../lib/platform';
import { runTapticImpactOccurred } from '../../lib/taptic';
import { coordY, VKUITouchEvent } from '../../lib/touch';
import { VKUITouchEvent } from '../../lib/touch';
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
import { AnyFunction, HasChildren } from '../../types';
import { ScrollContextInterface, useScroll } from '../AppRoot/ScrollContext';
Expand Down Expand Up @@ -191,33 +191,20 @@ export const PullToRefresh = ({
runRefreshing,
]);

const startYRef = React.useRef(0);

const onTouchStart = (e: TouchEvent) => {
if (refreshing) {
cancelEvent(e);
}
setTouchDown(true);
startYRef.current = e.startY;
};

const shouldPreventTouchMove = (event: VKUITouchEvent) => {
if (watching || refreshing) {
return true;
if (document) {
// eslint-disable-next-line no-restricted-properties
document.documentElement.classList.add('vkui--disable-overscroll-behavior');
}

/* Нам нужно запретить touchmove у документа как только стало понятно, что
* начинается pull.
* состояния watching и refreshing устанавливаются слишком поздно и браузер
* может успеть начать нативный pull to refresh. */
const shiftY = coordY(event) - startYRef.current;
const pageYOffset = scroll?.getScroll().y;
const isRefreshGestureStarted = pageYOffset === 0 && shiftY > 0 && touchDown;
return isRefreshGestureStarted;
};

const onWindowTouchMove = (event: VKUITouchEvent) => {
if (shouldPreventTouchMove(event)) {
if (refreshing) {
event.preventDefault();
event.stopPropagation();
}
Expand Down Expand Up @@ -261,6 +248,12 @@ export const PullToRefresh = ({
const onTouchEnd = () => {
setWatching(false);
setTouchDown(false);

// восстанавливаем overscroll behavior
if (document) {
// eslint-disable-next-line no-restricted-properties
document.documentElement.classList.remove('vkui--disable-overscroll-behavior');
}
};

const spinnerTransform = `translate3d(0, ${spinnerY}px, 0)`;
Expand Down
10 changes: 10 additions & 0 deletions packages/vkui/src/styles/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,13 @@
.vkui--layout-plain {
background: var(--vkui--color_background_content);
}

/* отключаем нативный pull-to-refresh при закрывании модалки */
mendrew marked this conversation as resolved.
Show resolved Hide resolved
.vkui--modal-overscroll-behavior {
overscroll-behavior-y: contain;
}

/* отключаем нативный pull-to-refresh в PullToRefresh компоненте */
mendrew marked this conversation as resolved.
Show resolved Hide resolved
.vkui--disable-overscroll-behavior {
overscroll-behavior-y: none;
}