Skip to content

Commit

Permalink
Add Swiper utility function for touch swipe events (#85)
Browse files Browse the repository at this point in the history
* feat: Add Swiper utility function for touch swipe events

* test: Add swipe tests

* refactor: eslint configuration and refactor based on a review

* fix: update the method to assign the mock to event target

* feat: allow configure deadZone

* feat: add destroy method

---------

Co-authored-by: Alecell <[email protected]>
Co-authored-by: Diogo Ferreira Reis <[email protected]>
  • Loading branch information
3 people authored Mar 10, 2024
1 parent fe864ac commit b4039ec
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"rules": {
"no-console": "warn",
"object-curly-newline": "off"
"object-curly-newline": "off",
"import/prefer-default-export": "off"
}
}
73 changes: 73 additions & 0 deletions src/utils/swiper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
export function initializeSwiper({ deadZone = 50 } = {}) {
const coordinates = {
$element: null,
xDown: null,
yDown: null,
xUp: null,
yUp: null,
};

const dispatchSwipeLeft = () => {
const event = new Event('swipe-left');
coordinates.$element.dispatchEvent(event);
};

const dispatchSwipeRight = () => {
const event = new Event('swipe-right');
coordinates.$element.dispatchEvent(event);
};

const dispatchSwipeUp = () => {
const event = new Event('swipe-up');
coordinates.$element.dispatchEvent(event);
};

const dispatchSwipeDown = () => {
const event = new Event('swipe-down');
coordinates.$element.dispatchEvent(event);
};

function swipeDirection() {
const xDiff = coordinates.xUp - coordinates.xDown;
const yDiff = coordinates.yUp - coordinates.yDown;

const isHorizontal = Math.abs(xDiff) > Math.abs(yDiff);
const isLeft = xDiff < 0;
const isRight = xDiff > 0;
const isUp = yDiff < 0;
const isDown = yDiff > 0;

if (isHorizontal && isLeft) dispatchSwipeLeft();
if (isHorizontal && isRight) dispatchSwipeRight();
if (!isHorizontal && isUp) dispatchSwipeUp();
if (!isHorizontal && isDown) dispatchSwipeDown();
}

function handleTouchStart(event) {
coordinates.$element = event.target;

coordinates.xDown = event.touches[0].clientX;
coordinates.yDown = event.touches[0].clientY;
}

function handleTouchEnd(event) {
coordinates.xUp = event.changedTouches[0].clientX;
coordinates.yUp = event.changedTouches[0].clientY;

const xDiff = coordinates.xUp - coordinates.xDown;
const yDiff = coordinates.yUp - coordinates.yDown;


const didSwipe = Math.abs(xDiff) > deadZone || Math.abs(yDiff) > deadZone;

if (didSwipe) swipeDirection();
}

window.addEventListener('touchstart', handleTouchStart, false);
window.addEventListener('touchend', handleTouchEnd, false);

return function destroy() {
window.removeEventListener('touchstart', handleTouchStart);
window.removeEventListener('touchend', handleTouchEnd);
}
}
133 changes: 133 additions & 0 deletions src/utils/swiper.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { describe, expect, it, beforeEach } from 'vitest';
import { initializeSwiper } from './swiper';

describe('Swiper', () => {
initializeSwiper();
const mockElement = document.createElement('div');
const touchStartEvent = new Event('touchstart');
const touchEndEvent = new Event('touchend');
Object.defineProperty(touchStartEvent, 'target', {
writable: false,
value: mockElement,
});

let eventFired = {
swipeLeft: false,
swipeRight: false,
swipeUp: false,
swipeDown: false,
};

mockElement.addEventListener('swipe-left', () => {
eventFired.swipeLeft = true;
});
mockElement.addEventListener('swipe-right', () => {
eventFired.swipeRight = true;
});
mockElement.addEventListener('swipe-up', () => {
eventFired.swipeUp = true;
});
mockElement.addEventListener('swipe-down', () => {
eventFired.swipeDown = true;
});

beforeEach(() => {
eventFired = {
swipeLeft: false,
swipeRight: false,
swipeUp: false,
swipeDown: false,
};
});

it('dispatches swipe-left event', () => {
touchStartEvent.touches = [{ clientX: 200, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 0, clientY: 100 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(true);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(false);
});

it('dispatches swipe-right event', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 200, clientY: 100 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(true);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(false);
});

it('dispatches swipe-up event', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 200 }];
touchEndEvent.changedTouches = [{ clientX: 100, clientY: 0 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(true);
expect(eventFired.swipeDown).toBe(false);
});

it('dispatches swipe-down event', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 100, clientY: 200 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(true);
});

it('does not dispatch any event when swipe is not detected', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 0, clientY: 0 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(false);
});

it('does not dispatch any event when swipe is not long enough', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 50, clientY: 50 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(false);
});

it('dispatches vertical event when direction is esqual', () => {
touchStartEvent.touches = [{ clientX: 0, clientY: 0 }];
touchEndEvent.changedTouches = [{ clientX: 51, clientY: 51 }];

window.dispatchEvent(touchStartEvent);
window.dispatchEvent(touchEndEvent);

expect(eventFired.swipeLeft).toBe(false);
expect(eventFired.swipeRight).toBe(false);
expect(eventFired.swipeUp).toBe(false);
expect(eventFired.swipeDown).toBe(true);
});
});

0 comments on commit b4039ec

Please sign in to comment.