├── .gitignore ├── .vscode └── settings.json ├── src ├── helper.ts ├── index.ts ├── types.ts ├── useSwipe.ts ├── useSwipeVector.ts └── useSwipePosition.ts ├── .prettierrc ├── package.json ├── .github └── workflows │ └── npm-publish.yml ├── rollup.config.js ├── tsconfig.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /lib 2 | /node_modules 3 | /umd -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /src/helper.ts: -------------------------------------------------------------------------------- 1 | export function square(x: number) { 2 | return x * x; 3 | } 4 | 5 | export function radToDeg(x: number) { 6 | return (x * 180) / Math.PI; 7 | } 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useSwipe, SWIPE_DIRECTION } from './useSwipe'; 2 | export { default as useSwipePosition } from './useSwipePosition'; 3 | export { default as useSwipeVector } from './useSwipeVector'; 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "all", 8 | "arrowParens": "always", 9 | "jsxBracketSameLine": true 10 | } -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { RefObject } from 'react'; 2 | export interface UseSwipeOptions { 3 | // ref of the container where you want to attach swipe event 4 | ref: RefObject; 5 | // (optional) no of pixels to move your finger to trigger a swipe event. 6 | // Larger this value means less sensitivity. Default value is 5 (5px) 7 | thresholdPX?: number; 8 | unit?: 'rad' | 'deg'; // unit of direction for useSwipeVector hook 9 | // whether to use position units based relative to canvas rather than with respect to window 10 | useRelativeUnits?: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /src/useSwipe.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { UseSwipeOptions } from './types'; 3 | import useSwipePosition from './useSwipePosition'; 4 | 5 | // SWIPE_DIRECTION can be imported & used for comparison 6 | export enum SWIPE_DIRECTION { 7 | RIGHT = 'right', 8 | LEFT = 'left', 9 | UP = 'up', 10 | DOWN = 'down', 11 | } 12 | 13 | const useSwipe = ({ ref, thresholdPX = 5 }: UseSwipeOptions) => { 14 | const { x1, y1, x2, y2 } = useSwipePosition({ ref }); 15 | const [direction, setDirection] = useState(null); 16 | 17 | useEffect(() => { 18 | if (Math.abs(x2 - x1) > Math.abs(y2 - y1) && Math.abs(x2 - x1) > thresholdPX) { 19 | setDirection(x2 > x1 ? SWIPE_DIRECTION.RIGHT : SWIPE_DIRECTION.LEFT); 20 | } else if (Math.abs(y2 - y1) > thresholdPX) { 21 | setDirection(y2 > y1 ? SWIPE_DIRECTION.DOWN : SWIPE_DIRECTION.UP); 22 | } 23 | // eslint-disable-next-line react-hooks/exhaustive-deps 24 | }, [y2]); 25 | 26 | return direction; 27 | }; 28 | 29 | export default useSwipe; 30 | -------------------------------------------------------------------------------- /src/useSwipeVector.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { radToDeg, square } from './helper'; 3 | import { UseSwipeOptions } from './types'; 4 | import useSwipePosition from './useSwipePosition'; 5 | 6 | const useSwipeVector = ({ ref, thresholdPX = 5, unit = 'rad', useRelativeUnits = false }: UseSwipeOptions) => { 7 | const { x1, y1, x2, y2 } = useSwipePosition({ ref, useRelativeUnits }); 8 | const [direction, setDirection] = useState(0); 9 | const [magnitude, setMagnitude] = useState(0); 10 | 11 | useEffect(() => { 12 | const mag = Math.sqrt(square(x2 - x1) + square(y2 - y1)); 13 | 14 | if (mag > thresholdPX) { 15 | // Rounding up to 0 to 2 * PI 16 | const angleRad = (2 * Math.PI + Math.atan2(y2 - y1, x2 - x1)) % (2 * Math.PI); 17 | 18 | setMagnitude(mag); 19 | setDirection(unit === 'rad' ? angleRad : radToDeg(angleRad)); 20 | } 21 | // eslint-disable-next-line react-hooks/exhaustive-deps 22 | }, [y2]); 23 | 24 | return { direction, magnitude, origin: { x: x1, y: y1 } }; 25 | }; 26 | 27 | export default useSwipeVector; 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-swipe-hook", 3 | "version": "2.0.0", 4 | "description": "A simple and easy to use tiny library that provides useSwipe hook to use with React that enables swipe gestures for touch screens", 5 | "main": "lib/umd/index.js", 6 | "browser": "lib/umd/index.js", 7 | "module": "lib/esm/index.js", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "build": "rollup -c", 11 | "start": "rollup --config ./rollup.config.js -w", 12 | "prepublishOnly": "rm -rf lib && npm run build", 13 | "postbuild": "npm pack && tar -xvzf *.tgz && rm -rf package *.tgz" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/rajatkantinandi/useSwipe.git" 18 | }, 19 | "files": [ 20 | "/lib" 21 | ], 22 | "keywords": [ 23 | "touch", 24 | "swipe", 25 | "drag", 26 | "react", 27 | "hooks" 28 | ], 29 | "author": "Rajat Kanti Nandi", 30 | "license": "ISC", 31 | "bugs": { 32 | "url": "https://github.com/rajatkantinandi/useSwipe/issues" 33 | }, 34 | "homepage": "https://github.com/rajatkantinandi/useSwipe#readme", 35 | "devDependencies": { 36 | "@rollup/plugin-commonjs": "^17.1.0", 37 | "@rollup/plugin-node-resolve": "^11.2.0", 38 | "@types/react": "^16.9.2", 39 | "@types/react-dom": "^16.9.0", 40 | "react": "^16.8.0", 41 | "react-dom": "^16.8.0", 42 | "rollup": "^2.79.2", 43 | "rollup-plugin-peer-deps-external": "^2.2.0", 44 | "rollup-plugin-terser": "^5.1.3", 45 | "rollup-plugin-typescript2": "^0.36.0", 46 | "tslib": "^2.8.1", 47 | "typescript": "^4.2.3" 48 | }, 49 | "peerDependencies": { 50 | "react": "^16.8.0", 51 | "react-dom": "^16.8.0" 52 | } 53 | } -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created or push to master with code change in src folder or manual trigger 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | push: 8 | paths: 9 | - 'src/**' 10 | - '.github/workflows/npm-publish.yml' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | if: github.event_name == 'push' && !(github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, '[publish')) 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: actions/setup-node@v2 20 | with: 21 | node-version: 12 22 | - name: Install 23 | run: npm ci 24 | - name: Build 25 | run: npm run build 26 | 27 | publish-npm: 28 | runs-on: ubuntu-latest 29 | if: github.ref == 'refs/heads/master' && (github.event_name != 'push' || contains(github.event.head_commit.message, '[publish]')) 30 | steps: 31 | - uses: actions/checkout@v2 32 | - uses: actions/setup-node@v2 33 | with: 34 | node-version: 12 35 | registry-url: https://registry.npmjs.org/ 36 | - name: Install 37 | run: npm ci 38 | - name: Publish 39 | run: npm publish 40 | env: 41 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 42 | 43 | publish-npm-beta: 44 | runs-on: ubuntu-latest 45 | if: github.ref == 'refs/heads/master' && github.event_name == 'push' && contains(github.event.head_commit.message, '[publish-beta]') 46 | steps: 47 | - uses: actions/checkout@v2 48 | - uses: actions/setup-node@v2 49 | with: 50 | node-version: 12 51 | registry-url: https://registry.npmjs.org/ 52 | - name: Install 53 | run: npm ci 54 | - name: Publish 55 | run: npm publish --tag beta 56 | env: 57 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 58 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from "@rollup/plugin-commonjs"; 2 | import resolve from "@rollup/plugin-node-resolve"; 3 | import external from "rollup-plugin-peer-deps-external"; 4 | import { terser } from "rollup-plugin-terser"; 5 | import typescript from 'rollup-plugin-typescript2'; 6 | import packageJSON from "./package.json"; 7 | 8 | const input = "./src/index.ts"; 9 | const inputDir = [ 10 | "./src/index.ts", 11 | "./src/helper.ts", 12 | "./src/useSwipe.ts", 13 | "./src/useSwipePosition.ts", 14 | "./src/useSwipeVector.ts", 15 | "./src/types.ts", 16 | ]; 17 | const minifyExtension = pathToFile => pathToFile.replace(/\.js$/, ".min.js"); 18 | const outputDir = "./lib/esm/"; 19 | 20 | export default [ 21 | // umd un-minified 22 | { 23 | input, 24 | output: { 25 | file: packageJSON.browser, 26 | format: "umd", 27 | name: "use-swipe-hook", 28 | globals: { 29 | react: "React", 30 | "@emotion/styled": "styled", 31 | "@emotion/core": "core" 32 | }, 33 | sourcemap: true 34 | }, 35 | plugins: [ 36 | typescript({ 37 | exclude: ["node_modules/**", "lib/**"] 38 | }), 39 | external(), 40 | resolve(), 41 | commonjs() 42 | ], 43 | }, 44 | // umd minified 45 | { 46 | input, 47 | output: { 48 | file: minifyExtension(packageJSON.browser), 49 | format: "umd", 50 | name: "use-swipe-hook", 51 | globals: { 52 | react: "React", 53 | "@emotion/styled": "styled", 54 | "@emotion/core": "core" 55 | } 56 | }, 57 | plugins: [ 58 | typescript({ 59 | exclude: ["node_modules/**", "lib/**"] 60 | }), 61 | external(), 62 | resolve(), 63 | commonjs(), 64 | terser() 65 | ], 66 | }, 67 | // esm minified + code-splitting 68 | { 69 | input: inputDir, 70 | output: { 71 | dir: outputDir, 72 | format: "esm", 73 | name: "use-swipe-hook", 74 | globals: { 75 | react: "React", 76 | "@emotion/styled": "styled", 77 | "@emotion/core": "core" 78 | } 79 | }, 80 | plugins: [ 81 | typescript({ 82 | exclude: ["node_modules/**", "lib/**"] 83 | }), 84 | external(), 85 | resolve(), 86 | commonjs(), 87 | terser() 88 | ], 89 | }, 90 | ]; 91 | -------------------------------------------------------------------------------- /src/useSwipePosition.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { UseSwipeOptions } from './types'; 3 | 4 | const useSwipePosition = ({ ref, useRelativeUnits = false }: UseSwipeOptions) => { 5 | const [x1, setX1] = useState(0); 6 | const [y1, setY1] = useState(0); 7 | const [x2, setX2] = useState(0); 8 | const [y2, setY2] = useState(0); 9 | 10 | useEffect(() => { 11 | const currentElement = ref.current; 12 | 13 | if (currentElement) { 14 | if (isTouchDevice()) { 15 | currentElement.addEventListener('touchstart', handleTouchStart); 16 | currentElement.addEventListener('touchend', handleTouchEnd); 17 | } else { 18 | currentElement.addEventListener('mousedown', handleMouseDown); 19 | currentElement.addEventListener('mouseup', handleMouseUp); 20 | } 21 | } 22 | 23 | return () => { 24 | if (currentElement) { 25 | if (isTouchDevice()) { 26 | currentElement.removeEventListener('touchstart', handleTouchStart); 27 | currentElement.removeEventListener('touchend', handleTouchEnd); 28 | } else { 29 | currentElement.removeEventListener('mousedown', handleMouseDown); 30 | currentElement.removeEventListener('mouseup', handleMouseUp); 31 | } 32 | } 33 | }; 34 | }, [ref]); 35 | 36 | function handleTouchStart(event: TouchEvent) { 37 | setX1(event.changedTouches[0].clientX); 38 | setY1(event.changedTouches[0].clientY); 39 | } 40 | 41 | function handleTouchEnd(event: TouchEvent) { 42 | if (event.changedTouches && event.changedTouches.length > 0) { 43 | setX2(event.changedTouches[0].clientX); 44 | setY2(event.changedTouches[0].clientY); 45 | } 46 | } 47 | 48 | function handleMouseDown(event: MouseEvent) { 49 | const { x, y } = getDimensionsFromEvent(event); 50 | setX1(x); 51 | setY1(y); 52 | } 53 | 54 | function handleMouseUp(event: MouseEvent) { 55 | const { x, y } = getDimensionsFromEvent(event); 56 | setX2(x); 57 | setY2(y); 58 | } 59 | 60 | function getDimensionsFromEvent(event: MouseEvent) { 61 | let x = event.clientX, 62 | y = event.clientY; 63 | 64 | if (useRelativeUnits && ref.current) { 65 | const { top, left } = ref.current.getBoundingClientRect(); 66 | x -= left; 67 | y -= top; 68 | } 69 | 70 | return { x, y }; 71 | } 72 | 73 | return { x1, y1, x2, y2 }; 74 | }; 75 | 76 | const isTouchDevice = () => 'ontouchstart' in window; 77 | 78 | export default useSwipePosition; 79 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "ES2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | "jsx": "react", // process JSX 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./lib", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | "removeComments": true, /* Do not emit comments to output. */ 22 | "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 44 | 45 | /* Module Resolution Options */ 46 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 47 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 48 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 49 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 50 | // "typeRoots": [], /* List of folders to include type definitions from. */ 51 | // "types": [], /* Type declaration files to be included in compilation. */ 52 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 53 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 54 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 55 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 56 | 57 | /* Source Map Options */ 58 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 59 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 60 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 61 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 62 | 63 | /* Experimental Options */ 64 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 65 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 66 | 67 | /* Advanced Options */ 68 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 69 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # useSwipe hook 2 | 3 | [![NPM](https://img.shields.io/npm/v/use-swipe-hook.svg)](https://www.npmjs.com/package/use-swipe-hook) 4 | 5 | > A simple and easy to use tiny library that provides useSwipe hook to use with React that enables swipe gestures for touch screens & non-touch screens via mouse events 6 | 7 | ## Install 8 | 9 | ```bash 10 | npm i use-swipe-hook 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```tsx 16 | import React, { useRef } from 'react'; 17 | import ReactDOM from 'react-dom'; 18 | import './styles.css'; 19 | import { useSwipe } from 'use-swipe-hook'; 20 | 21 | function App() { 22 | const swipeContainerRef = useRef(null); 23 | const direction = useSwipe({ ref: swipeContainerRef, thresholdPX: 5 }); 24 | 25 | return ( 26 |
27 |

use-swipe-hook demo

28 |

Works on both touch & non touch devices (by dragging mouse over the container)

29 |
30 | {direction ? `You have swiped ${direction}` : 'Swipe here to see swipe direction'} 31 |
32 |
33 | ); 34 | } 35 | 36 | const rootElement = document.getElementById('root'); 37 | ReactDOM.render(, rootElement); 38 | ``` 39 | 40 | ## Advanced Usage 41 | 42 | Version 2 introduces 2 new hooks for advanced usage. 43 | 44 | ### useSwipeVector - Get magnitude & direction of your swipe along with origin 45 | 46 | ```tsx 47 | import React, { useRef } from 'react'; 48 | import ReactDOM from 'react-dom'; 49 | import './styles.css'; 50 | import { useSwipeVector } from 'use-swipe-hook'; 51 | 52 | function UseSwipeVector() { 53 | const swipeContainerRef = useRef(null); 54 | const { 55 | magnitude, 56 | direction, 57 | origin: { x, y }, 58 | } = useSwipeVector({ 59 | ref: swipeContainerRef, 60 | thresholdPX: 5, 61 | unit: 'deg', 62 | useRelativeUnits: true, 63 | }); 64 | 65 | return ( 66 |
67 | {magnitude ? ( 68 | <> 69 | You have swiped {magnitude.toFixed(2)}px towards {direction.toFixed(0)}° starting from ({x.toFixed(0)},{' '} 70 | {y.toFixed(0)}) 71 | 72 | ) : ( 73 | 'Swipe here to see swipe direction' 74 | )} 75 |
76 | ); 77 | } 78 | 79 | const rootElement = document.getElementById('root'); 80 | ReactDOM.render(, rootElement); 81 | ``` 82 | 83 | ### useSwipePosition - Get raw co-ordinates of your swipe including start & end position 84 | 85 | ```tsx 86 | import React, { useRef } from 'react'; 87 | import ReactDOM from 'react-dom'; 88 | import './styles.css'; 89 | import { useSwipePosition } from 'use-swipe-hook'; 90 | 91 | function UseSwipePosition() { 92 | const swipeContainerRef = useRef(null); 93 | const { x1, y1, x2, y2 } = useSwipePosition({ 94 | ref: swipeContainerRef, 95 | thresholdPX: 5, 96 | useRelativeUnits: true, 97 | }); 98 | 99 | return ( 100 |
101 | {x1 ? ( 102 | <> 103 | You have swiped from ({x1.toFixed(0)}, {y1.toFixed(0)}) to ({x2.toFixed(0)}, {y2.toFixed(0)}) 104 | 105 | ) : ( 106 | 'Swipe here to see swipe direction' 107 | )} 108 |
109 | ); 110 | } 111 | 112 | const rootElement = document.getElementById('root'); 113 | ReactDOM.render(, rootElement); 114 | ``` 115 | 116 | ## Code splitting 117 | 118 | The library uses code splitting, so even though 2 new hooks are introduced in version 2 and the overall bundle size is slightly increased, the individual hook bundle size remains small when you use a single hook on you application. 119 | This means more features but still leaner & tiny bundle size. 120 | 121 | ## Structure 122 | 123 | ```ts 124 | // SWIPE_DIRECTION can be imported & used for comparison 125 | enum SWIPE_DIRECTION { 126 | RIGHT = 'right', 127 | LEFT = 'left', 128 | UP = 'up', 129 | DOWN = 'down', 130 | } 131 | 132 | interface UseSwipeOptions { 133 | // ref of the container where you want to attach swipe event 134 | ref: RefObject; 135 | // (optional) no of pixels to move your finger to trigger a swipe event. 136 | // Larger this value means less sensitivity. Default value is 5 (5px) 137 | thresholdPX?: number; 138 | } 139 | 140 | const useSwipe: ({ ref, thresholdPX }: UseSwipeOptions) => SWIPE_DIRECTION | null; 141 | 142 | interface UseSwipeVectorOptions { 143 | // ref of the container where you want to attach swipe event 144 | ref: RefObject; 145 | // (optional) no of pixels to move your finger to trigger a swipe event. 146 | // Larger this value means less sensitivity. Default value is 5 (5px) 147 | thresholdPX?: number; 148 | unit?: 'rad' | 'deg'; // unit of direction for useSwipeVector hook 149 | // whether to use position units based relative to canvas rather than with respect to window 150 | useRelativeUnits?: boolean; 151 | } 152 | 153 | const useSwipeVector: ({ ref, thresholdPX, unit, useRelativeUnits }: UseSwipeVectorOptions) => SWIPE_DIRECTION | null; 154 | 155 | interface UseSwipePositionOptions { 156 | // ref of the container where you want to attach swipe event 157 | ref: RefObject; 158 | // (optional) no of pixels to move your finger to trigger a swipe event. 159 | // Larger this value means less sensitivity. Default value is 5 (5px) 160 | thresholdPX?: number; 161 | // whether to use position units based relative to canvas rather than with respect to window 162 | useRelativeUnits?: boolean; 163 | } 164 | 165 | const useSwipePosition: ({ ref, thresholdPX, useRelativeUnits }: UseSwipePositionOptions) => SWIPE_DIRECTION | null; 166 | ``` 167 | 168 | ## Demo 169 | 170 | [Codesandbox demo](https://codesandbox.io/s/use-swipe-hook-demo-271g4?file=/src/App.tsx&fontsize=14&theme=dark) 171 | 172 | ## GitHub actions for type-checking, building & auto-publish 173 | 174 | This repo uses github actions to publish a package when: 175 | 176 | - a new pull request is merged to master 177 | - When a pull request is merged or something is pushed to master then if src folder has file changes then only it will publish a version. 178 | - Additionally the merge commit message should contain `[publish]` keyword otherwise it will not publish on merge & just do build time checks. 179 | - Also while running the action one needs to increment the version number in package.json before merging the PR otherwise the `npm publish` command will fail. 180 | - can be triggered manually. 181 | 182 | On any other branch commits it will run type-check & build checks if src folder files are changed. 183 | 184 | © [rajatkantinandi](https://github.com/rajatkantinandi) 185 | --------------------------------------------------------------------------------