Skip to content

Commit

Permalink
fix: Fire Touch end on unmount
Browse files Browse the repository at this point in the history
  • Loading branch information
thoughtspile committed Oct 20, 2021
1 parent 6f5ebeb commit 62af7af
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
13 changes: 10 additions & 3 deletions src/components/Touch/Touch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import { createElement } from 'react';
// Настоящего Touch нет в jsdom: https://github.com/jsdom/jsdom/issues/1508
const asClientPos = ([clientX = 0, clientY = 0] = []): Touch & MouseEvent => ({ clientX, clientY }) as any;

function fireMouseSwipe(e: HTMLElement, [start, ...move]: any[], ops: { startEl?: HTMLElement } = {}) {
function fireMouseSwipe(e: HTMLElement, [start, ...move]: any[], ops: { startEl?: HTMLElement; end?: boolean } = {}) {
fireEvent.mouseDown(ops.startEl || e, asClientPos(start));
move.forEach((p) => fireEvent.mouseMove(e, asClientPos(p)));
fireEvent.mouseUp(e, asClientPos(move[move.length - 1]));
return fireEvent.click(e, asClientPos(move[move.length - 1]));
}

function fireTouchSwipe(e: HTMLElement, [start, ...move]: any[]) {
function fireTouchSwipe(e: HTMLElement, [start, ...move]: any[], { end = true } = {}) {
let prevTouches: number[][] = [];
const eventProps = (p: any) => {
const touches: number[][] = Array.isArray(p[0]) ? p : [p];
Expand All @@ -30,7 +30,7 @@ function fireTouchSwipe(e: HTMLElement, [start, ...move]: any[]) {
};
fireEvent.touchStart(e, eventProps(start));
move.forEach((p) => fireEvent.touchMove(e, eventProps(p)));
fireEvent.touchEnd(e, eventProps([]));
end && fireEvent.touchEnd(e, eventProps([]));
};

const threshold = 10;
Expand Down Expand Up @@ -139,6 +139,13 @@ describe('Touch', () => {
isSlideX: false,
}));
});
it('calls onEnd when unmounting', () => {
const handlers = makeHandlers();
const h = render(<Touch {...handlers} data-testid="__t__" />);
fireGesture(screen.getByTestId('__t__'), [[20, 20], [20, 30]], { end: false });
h.unmount();
expect(handlers.onEnd).toBeCalledTimes(1);
});
if (input === 'touch') {
it('stops gesture if multitouch', () => {
const handlers = makeHandlers();
Expand Down
11 changes: 11 additions & 0 deletions src/components/Touch/Touch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export const Touch: React.FC<TouchProps> = ({
}: TouchProps) => {
const { document } = useDOM();
const events = React.useMemo(getSupportedEvents, []);
// Save last event to trigger end* on unmount
const lastEvent = React.useRef<VKUITouchEvent>();
const didSlide = React.useRef(false);
const gesture = React.useRef<Partial<Gesture>>({});
const handle = (e: VKUITouchEvent, handers: TouchEventHandler[]) => {
Expand All @@ -92,6 +94,7 @@ export const Touch: React.FC<TouchProps> = ({
const enterHandler = useEventListener(usePointerHover ? 'pointerenter' : 'mouseenter', onEnter);
const leaveHandler = useEventListener(usePointerHover ? 'pointerleave' : 'mouseleave', onLeave);
const startHandler = useEventListener(events[0], (e: VKUITouchEvent) => {
lastEvent.current = e;
gesture.current = {
startX: coordX(e),
startY: coordY(e),
Expand All @@ -112,7 +115,14 @@ export const Touch: React.FC<TouchProps> = ({
touchEnabled() && subscribe(el);
}, [Component]);

useIsomorphicLayoutEffect(() => () => {
if (gesture.current.isPressed) {
onEnd(lastEvent.current);
}
}, []);

function onMove(e: VKUITouchEvent) {
lastEvent.current = e;
const { isPressed, isX, isY, startX, startY } = gesture.current;

if (isPressed) {
Expand Down Expand Up @@ -167,6 +177,7 @@ export const Touch: React.FC<TouchProps> = ({

didSlide.current = isSlide;
gesture.current = {};
lastEvent.current = null;

// Если это был тач-евент, симулируем отмену hover
if (e.type === 'touchend' || e.type === 'touchcancel') {
Expand Down

0 comments on commit 62af7af

Please sign in to comment.