Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // @flow
- import { useState, useLayoutEffect } from 'react';
- import type { ElementRef } from 'react';
- /**
- * This react hook allows you to detect dragging and swiping
- * @param ref HTML Element ref (react ref)
- * @param handler Function Callback
- * @param config Object
- * @return Function remove listeners
- * TODO: Realtime tracking
- * */
- export function useGestures(
- ref: ElementRef<Object>,
- handler: Function,
- config: { realTime: boolean, delay: number, axis: 'x' | 'y' | 'both' },
- ): Object {
- const [startX, setStartX] = useState(0);
- const [endX, setEndX] = useState(0);
- const [startY, setStartY] = useState(0);
- const [endY, setEndY] = useState(0);
- const [currentX, setCurrentX] = useState(0);
- const [currentY, setCurrentY] = useState(0);
- const [isMoving, setIsMoving] = useState(false);
- const [throttled, setThrottled] = useState(false);
- const hasMouseEvent = 'onmousedown' in document;
- const hasTouchEvent = 'ontouchstart' in document;
- const cfg = {
- realTime: (config && config.realTime) || false, // realtime dragging callback
- delay: config && config.delay >= 0 && config.delay < 10000 ? config.delay : 100, // delay between calls in realtime dragging
- axis: config && ['x', 'y', 'both'].includes(config.axis) ? config.axis : 'both',
- };
- const onDragStart = e => {
- if (e.cancelable) e.preventDefault();
- if (cfg.axis === 'x' || cfg.axis === 'both')
- setStartX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
- if (cfg.axis === 'y' || cfg.axis === 'both')
- setStartY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
- };
- const onDrag = e => {
- if (e.cancelable) e.preventDefault();
- if (cfg.realTime) {
- if (!throttled) {
- // actual callback action
- if (cfg.axis === 'x' || cfg.axis === 'both')
- setCurrentX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
- if (cfg.axis === 'y' || cfg.axis === 'both')
- setCurrentY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
- // we're throttled!
- setThrottled(true);
- // set a timeout to un-throttle
- setTimeout(() => {
- setThrottled(false);
- }, cfg.delay);
- }
- }
- setIsMoving(true);
- };
- const onDragEnd = e => {
- if (e.cancelable) e.preventDefault();
- if (cfg.axis === 'x' || cfg.axis === 'both')
- setEndX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
- if (cfg.axis === 'y' || cfg.axis === 'both')
- setEndY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
- setIsMoving(false);
- };
- const onMouseLeave = e => {
- if (e.cancelable) e.preventDefault();
- setIsMoving(false);
- };
- const addListeners = gesuredZone => {
- if (hasMouseEvent) {
- gesuredZone.addEventListener('mousedown', onDragStart, false);
- gesuredZone.addEventListener('mousemove', onDrag);
- gesuredZone.addEventListener('mouseup', onDragEnd);
- gesuredZone.addEventListener('mouseleave', onMouseLeave);
- }
- if (hasTouchEvent) {
- gesuredZone.addEventListener('touchstart', onDragStart, false);
- gesuredZone.addEventListener('touchmove', onDrag);
- gesuredZone.addEventListener('touchend', onDragEnd);
- }
- };
- const removeListeners = gesuredZone => {
- if (hasMouseEvent) {
- gesuredZone.removeEventListener('mousedown', onDragStart);
- gesuredZone.removeEventListener('mousemove', onDrag);
- gesuredZone.removeEventListener('mouseup', onDragEnd);
- gesuredZone.removeEventListener('mouseleave', onMouseLeave);
- }
- if (hasTouchEvent) {
- gesuredZone.removeEventListener('touchstart', onDragStart);
- gesuredZone.removeEventListener('touchmove', onDrag);
- gesuredZone.removeEventListener('touchend', onDragEnd);
- }
- };
- useEffect(() => {
- addListeners(ref.current);
- // TODO: Direction on real time
- let direction = 'same';
- if (cfg.realTime) {
- if (currentX > startX) direction = 'right';
- if (currentX < startX) direction = 'left';
- } else {
- if (startX > endX) direction = 'left';
- if (startX < endX) direction = 'right';
- }
- let res = { isMoving, direction };
- if (cfg.axis === 'x' || cfg.axis === 'both') res = { startX, endX, ...res };
- if (cfg.axis === 'y' || cfg.axis === 'both') res = { startY, endY, ...res };
- if (cfg.realTime && (cfg.axis === 'x' || cfg.axis === 'both')) res = { currentX, ...res };
- if (cfg.realTime && (cfg.axis === 'y' || cfg.axis === 'both')) res = { currentY, ...res };
- if (startX || startY || endX || endY) handler(res);
- return () => removeListeners(ref.current);
- }, [endX, endY, throttled]);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement