From 0aa59fb9a7a8f4d7192cc9ce3456c8ca39704738 Mon Sep 17 00:00:00 2001 From: Emil Hartz Date: Fri, 3 Jul 2020 16:26:03 -0600 Subject: [PATCH 1/4] start typescript overhaul --- .eslintignore | 1 + .eslintrc | 41 --- .eslintrc.js | 31 ++ .gitignore | 1 + .prettierignore | 6 + .prettierrc | 6 - .prettierrc.json | 1 + package.json | 18 +- src/__tests__/helpers/index.js | 22 +- src/__tests__/useSwipeable.spec.js | 571 +++++++++++++++-------------- src/index.js | 219 ----------- src/index.ts | 346 +++++++++++++++++ tsconfig.json | 23 ++ types/index.d.ts | 53 --- types/test.tsx | 84 ----- types/tsconfig.json | 16 - types/tslint.json | 6 - yarn.lock | 545 +++++++-------------------- 18 files changed, 870 insertions(+), 1120 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js create mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 .prettierrc.json delete mode 100644 src/index.js create mode 100644 src/index.ts create mode 100644 tsconfig.json delete mode 100644 types/index.d.ts delete mode 100644 types/test.tsx delete mode 100644 types/tsconfig.json delete mode 100644 types/tslint.json diff --git a/.eslintignore b/.eslintignore index df9377dd..37c5f348 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules dist +lib examples diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 9db6f125..00000000 --- a/.eslintrc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "parser": "babel-eslint", - "extends": [ - "eslint:recommended", - "plugin:import/recommended", - "plugin:react/recommended", - "plugin:prettier/recommended" - ], - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true, - "experimentalObjectRestSpread": true - } - }, - "env": { - "browser": true, - "mocha": true, - "node": true - }, - "rules": { - "prettier/prettier": [ - "error", - { - "singleQuote": true, - "semi": false, - "printWidth": 100 - } - ], - "valid-jsdoc": 2, - "react/jsx-uses-react": 1, - "react/jsx-no-undef": 2, - "react/jsx-wrap-multilines": 2, - "react/no-string-refs": 0, - "react/prop-types": 0, - "react-hooks/rules-of-hooks": 2, - "react-hooks/exhaustive-deps": 1 - }, - "plugins": ["import", "react", "react-hooks"] -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..40886920 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,31 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.json', + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react/recommended', + 'prettier', + 'prettier/@typescript-eslint', + ], + plugins: ['@typescript-eslint', 'react-hooks'], + settings: { + react: { + version: 'detect', + }, + }, + rules: { + '@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '_' }], + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-ignore': 'off', + 'react/no-unescaped-entities': 'off', + 'react/prop-types': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + }, +}; diff --git a/.gitignore b/.gitignore index 54c406b5..95a6ab69 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules TODO *.log .DS_Store +lib dist examples/static coverage diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..2a4e5441 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +package.json +node_modules +/lib +/dist +/coverage +/examples diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 46c2e539..00000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "printWidth": 100, - "semi": false, - "singleQuote": true, - "tabWidth": 2 -} \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/package.json b/package.json index 287fbb43..3a69b3fe 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,13 @@ "umd:main": "./dist/react-swipeable.umd.js", "jsnext:main": "./dist/react-swipeable.modern.js", "module": "./dist/react-swipeable.module.js", - "source": "./src/index.js", + "source": "./src/index.ts", "scripts": { "build": "microbundle --no-compress --name swipeable --output dist", "build:examples": "webpack -p --config ./examples/webpack.config.min.js", "build:publish:examples": "npm run build:examples && rimraf examples/node_modules && gh-pages -d examples", "clean": "rimraf dist", - "format": "prettier --write '{src,__{tests,mocks}__}/**/*.js'", + "format": "prettier --write src/", "lint": "eslint .", "prebuild": "npm run clean", "prepare": "npm run build", @@ -76,20 +76,17 @@ "@babel/preset-react": "^7.10.4", "@testing-library/react": "^10.4.3", "@types/react": "^16.8.12", - "babel-eslint": "^10.0.1", "babel-jest": "^26.1.0", "babel-loader": "^8.0.5", "coveralls": "^3.0.3", - "eslint": "^5.9.0", - "eslint-config-prettier": "^3.3.0", - "eslint-plugin-import": "^2.14.0", - "eslint-plugin-prettier": "^3.0.0", - "eslint-plugin-react": "^7.11.1", - "eslint-plugin-react-hooks": "^1.6.0", + "eslint": "^7.4.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-react": "^7.20.3", + "eslint-plugin-react-hooks": "^4.0.5", "gh-pages": "^1.0.0", "jest": "^26.1.0", "microbundle": "^0.12.2", - "prettier": "1.15.3", + "prettier": "^2.0.5", "react": "^16.13.0", "react-dom": "^16.13.0", "react-scroll-up": "^1.3.3", @@ -97,6 +94,7 @@ "rollup": "^1.1.2", "rollup-plugin-babel": "^4.3.2", "size-limit": "^1.3.5", + "typescript": "^3.9.6", "webpack": "^4.29.0", "webpack-cli": "^3.2.1", "webpack-dev-server": "^3.1.14" diff --git a/src/__tests__/helpers/index.js b/src/__tests__/helpers/index.js index 5b770a89..79fac421 100644 --- a/src/__tests__/helpers/index.js +++ b/src/__tests__/helpers/index.js @@ -1,17 +1,17 @@ /* global expect */ const expectSwipingDir = (fns, dir) => { - fns.mock.calls.forEach(call => { - expect(call[0].dir).toBe(dir) - }) -} + fns.mock.calls.forEach((call) => { + expect(call[0].dir).toBe(dir); + }); +}; export const expectSwipeFuncsDir = (sf, dir) => - Object.keys(sf).forEach(s => { - if (s.endsWith(dir) || s === 'onSwiped') { - expect(sf[s]).toHaveBeenCalled() - } else if (s === 'onSwiping') { - expectSwipingDir(sf[s], dir) + Object.keys(sf).forEach((s) => { + if (s.endsWith(dir) || s === "onSwiped") { + expect(sf[s]).toHaveBeenCalled(); + } else if (s === "onSwiping") { + expectSwipingDir(sf[s], dir); } else { - expect(sf[s]).not.toHaveBeenCalled() + expect(sf[s]).not.toHaveBeenCalled(); } - }) + }); diff --git a/src/__tests__/useSwipeable.spec.js b/src/__tests__/useSwipeable.spec.js index f1edcdbe..2d243445 100644 --- a/src/__tests__/useSwipeable.spec.js +++ b/src/__tests__/useSwipeable.spec.js @@ -1,186 +1,200 @@ /* global document, jest, expect, beforeAll */ -import React from 'react' -import { render, fireEvent, act } from '@testing-library/react' -import { useSwipeable, LEFT, RIGHT, UP, DOWN } from '../index' -import { expectSwipeFuncsDir } from './helpers' +import React from "react"; +import { render, fireEvent, act } from "@testing-library/react"; +import { useSwipeable, LEFT, RIGHT, UP, DOWN } from "../index"; +import { expectSwipeFuncsDir } from "./helpers"; -const DIRECTIONS = [LEFT, RIGHT, UP, DOWN] +const DIRECTIONS = [LEFT, RIGHT, UP, DOWN]; function getMockedSwipeFunctions() { - return DIRECTIONS.reduce((acc, dir) => ({ ...acc, [`onSwiped${dir}`]: jest.fn() }), { - onSwiping: jest.fn(), - onSwiped: jest.fn() - }) + return DIRECTIONS.reduce( + (acc, dir) => ({ ...acc, [`onSwiped${dir}`]: jest.fn() }), + { + onSwiping: jest.fn(), + onSwiped: jest.fn(), + } + ); } -const TESTING_TEXT = 'touch here' +const TESTING_TEXT = "touch here"; /* * Wrapping component for the hook testing */ -function SwipeableUsingHook({ nodeName = 'div', ...rest }) { - const eventHandlers = useSwipeable(rest) - const Elem = nodeName +function SwipeableUsingHook({ nodeName = "div", ...rest }) { + const eventHandlers = useSwipeable(rest); + const Elem = nodeName; return ( {TESTING_TEXT} - ) + ); } -const MD = 'mouseDown' -const MM = 'mouseMove' -const MU = 'mouseUp' -const TS = 'touchStart' -const TM = 'touchMove' -const TE = 'touchEnd' +const MD = "mouseDown"; +const MM = "mouseMove"; +const MU = "mouseUp"; +const TS = "touchStart"; +const TM = "touchMove"; +const TE = "touchEnd"; -const createClientXYObject = (x, y) => ({ clientX: x, clientY: y }) +const createClientXYObject = (x, y) => ({ clientX: x, clientY: y }); // Create touch event -const cte = ({ x, y }) => ({ touches: [createClientXYObject(x, y)] }) +const cte = ({ x, y }) => ({ touches: [createClientXYObject(x, y)] }); // Create Mouse Event -const cme = ({ x, y }) => ({ ...createClientXYObject(x, y) }) +const cme = ({ x, y }) => ({ ...createClientXYObject(x, y) }); -describe('useSwipeable', () => { - let defaultPrevented = 0 +describe("useSwipeable", () => { + let defaultPrevented = 0; beforeAll(() => { // listen on document for touchmove events, track if their default was prevented - document.addEventListener('touchmove', e => { + document.addEventListener("touchmove", (e) => { if (e.defaultPrevented) { - defaultPrevented += 1 + defaultPrevented += 1; } - }) - }) + }); + }); beforeEach(() => { - defaultPrevented = 0 - }) - - it('handles touch events and fires correct props', () => { - const swipeFuncs = getMockedSwipeFunctions() - const { getByText } = render() - - const touchArea = getByText(TESTING_TEXT) - - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 175 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 200 })) - fireEvent[TE](touchArea, cte({})) - - expect(swipeFuncs.onSwipedDown).toHaveBeenCalled() - expect(swipeFuncs.onSwipedUp).not.toHaveBeenCalled() - expect(swipeFuncs.onSwipedLeft).not.toHaveBeenCalled() - expect(swipeFuncs.onSwipedRight).not.toHaveBeenCalled() + defaultPrevented = 0; + }); + + it("handles touch events and fires correct props", () => { + const swipeFuncs = getMockedSwipeFunctions(); + const { getByText } = render(); + + const touchArea = getByText(TESTING_TEXT); + + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 175 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 200 })); + fireEvent[TE](touchArea, cte({})); + + expect(swipeFuncs.onSwipedDown).toHaveBeenCalled(); + expect(swipeFuncs.onSwipedUp).not.toHaveBeenCalled(); + expect(swipeFuncs.onSwipedLeft).not.toHaveBeenCalled(); + expect(swipeFuncs.onSwipedRight).not.toHaveBeenCalled(); expect(swipeFuncs.onSwiped.mock.calls[0][0]).toMatchSnapshot( { velocity: expect.any(Number) }, `useSwipeable onSwiped trackTouch` - ) + ); expect(swipeFuncs.onSwiping.mock.calls[0][0]).toMatchSnapshot( { velocity: expect.any(Number) }, `useSwipeable onSwiping trackTouch` - ) - }) + ); + }); - it('handles mouse events with trackMouse prop and fires correct props', () => { - const swipeFuncs = getMockedSwipeFunctions() + it("handles mouse events with trackMouse prop and fires correct props", () => { + const swipeFuncs = getMockedSwipeFunctions(); const { getByText } = render( - - ) - - const touchArea = getByText(TESTING_TEXT) - - fireEvent[MD](touchArea, cme({ x: 100, y: 100 })) - fireEvent[MM](touchArea, cme({ x: 125, y: 100 })) - fireEvent[MM](touchArea, cme({ x: 150, y: 100 })) - fireEvent[MM](touchArea, cme({ x: 175, y: 100 })) - fireEvent[MM](touchArea, cme({ x: 200, y: 100 })) - fireEvent[MU](document, cme({})) - - expect(swipeFuncs.onSwipedRight).toHaveBeenCalled() - expect(swipeFuncs.onSwipedUp).not.toHaveBeenCalled() - expect(swipeFuncs.onSwipedDown).not.toHaveBeenCalled() - expect(swipeFuncs.onSwipedLeft).not.toHaveBeenCalled() + + ); + + const touchArea = getByText(TESTING_TEXT); + + fireEvent[MD](touchArea, cme({ x: 100, y: 100 })); + fireEvent[MM](touchArea, cme({ x: 125, y: 100 })); + fireEvent[MM](touchArea, cme({ x: 150, y: 100 })); + fireEvent[MM](touchArea, cme({ x: 175, y: 100 })); + fireEvent[MM](touchArea, cme({ x: 200, y: 100 })); + fireEvent[MU](document, cme({})); + + expect(swipeFuncs.onSwipedRight).toHaveBeenCalled(); + expect(swipeFuncs.onSwipedUp).not.toHaveBeenCalled(); + expect(swipeFuncs.onSwipedDown).not.toHaveBeenCalled(); + expect(swipeFuncs.onSwipedLeft).not.toHaveBeenCalled(); expect(swipeFuncs.onSwiped.mock.calls[0][0]).toMatchSnapshot( { velocity: expect.any(Number) }, `useSwipeable onSwiped trackMouse` - ) + ); expect(swipeFuncs.onSwiping.mock.calls[0][0]).toMatchSnapshot( { velocity: expect.any(Number) }, `useSwipeable onSwiping trackMouse` - ) - }) + ); + }); - it('calls preventDefault when swiping in direction that has a callback', () => { - const onSwipedDown = jest.fn() + it("calls preventDefault when swiping in direction that has a callback", () => { + const onSwipedDown = jest.fn(); const { getByText } = render( - - ) + + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 175 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 200 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 175 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 200 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwipedDown).toHaveBeenCalled() - expect(defaultPrevented).toBe(4) - }) + expect(onSwipedDown).toHaveBeenCalled(); + expect(defaultPrevented).toBe(4); + }); - it('does not call preventDefault when false', () => { - const onSwipedUp = jest.fn() + it("does not call preventDefault when false", () => { + const onSwipedUp = jest.fn(); - const { getByText } = render() + const { getByText } = render( + + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 75 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 50 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 25 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 5 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 75 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 50 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 25 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 5 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwipedUp).toHaveBeenCalled() - expect(defaultPrevented).toBe(0) - }) + expect(onSwipedUp).toHaveBeenCalled(); + expect(defaultPrevented).toBe(0); + }); - it('calls preventDefault when onSwiping or onSwiped is present', () => { - const onSwiping = jest.fn() - const onSwiped = jest.fn() + it("calls preventDefault when onSwiping or onSwiped is present", () => { + const onSwiping = jest.fn(); + const onSwiped = jest.fn(); const { getByText, rerender } = render( - ) + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 50 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 50 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwiping).toHaveBeenCalled() - expect(defaultPrevented).toBe(1) + expect(onSwiping).toHaveBeenCalled(); + expect(defaultPrevented).toBe(1); - rerender() + rerender( + + ); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 50 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 50 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwiped).toHaveBeenCalled() - expect(defaultPrevented).toBe(2) - }) + expect(onSwiped).toHaveBeenCalled(); + expect(defaultPrevented).toBe(2); + }); - it('does not re-check delta when swiping already in progress', () => { - const onSwiping = jest.fn() - const onSwipedRight = jest.fn() - const onSwipedLeft = jest.fn() + it("does not re-check delta when swiping already in progress", () => { + const onSwiping = jest.fn(); + const onSwipedRight = jest.fn(); + const onSwipedLeft = jest.fn(); const { getByText } = render( { onSwipedLeft={onSwipedLeft} delta={40} /> - ) + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 145, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 80, y: 100 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 145, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 80, y: 100 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwiping).toHaveBeenCalledTimes(2) - expect(onSwiping.mock.calls[0][0].dir).toBe(RIGHT) - expect(onSwiping.mock.calls[1][0].dir).toBe(LEFT) - expect(onSwipedLeft).toHaveBeenCalledTimes(1) - expect(onSwipedRight).not.toHaveBeenCalled() - }) + expect(onSwiping).toHaveBeenCalledTimes(2); + expect(onSwiping.mock.calls[0][0].dir).toBe(RIGHT); + expect(onSwiping.mock.calls[1][0].dir).toBe(LEFT); + expect(onSwipedLeft).toHaveBeenCalledTimes(1); + expect(onSwipedRight).not.toHaveBeenCalled(); + }); - it('Handle Rotation by 90 degree', () => { - const swipeFuncsRight = getMockedSwipeFunctions() + it("Handle Rotation by 90 degree", () => { + const swipeFuncsRight = getMockedSwipeFunctions(); const { getByText, rerender } = render( - ) + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); // check right - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFuncsRight, RIGHT) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFuncsRight, RIGHT); // check left - const swipeFuncsLeft = getMockedSwipeFunctions() - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 75 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 50 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFuncsLeft, LEFT) + const swipeFuncsLeft = getMockedSwipeFunctions(); + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 75 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 50 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFuncsLeft, LEFT); // check up - const swipeFunsUp = getMockedSwipeFunctions() - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 125, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 150, y: 100 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFunsUp, UP) + const swipeFunsUp = getMockedSwipeFunctions(); + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 125, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 150, y: 100 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFunsUp, UP); // check down - const swipeFunsDown = getMockedSwipeFunctions() - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 75, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 50, y: 100 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFunsDown, DOWN) - }) + const swipeFunsDown = getMockedSwipeFunctions(); + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 75, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 50, y: 100 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFunsDown, DOWN); + }); it('Handle "odd" rotations', () => { - const swipeFuncsNegativeRotation = getMockedSwipeFunctions() + const swipeFuncsNegativeRotation = getMockedSwipeFunctions(); const { getByText, rerender } = render( - ) + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); // check -90 - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFuncsNegativeRotation, LEFT) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFuncsNegativeRotation, LEFT); // check 360 + 270 - const swipeFuncsLargeRotation = getMockedSwipeFunctions() - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TE](touchArea, cte({})) - expectSwipeFuncsDir(swipeFuncsLargeRotation, LEFT) - }) - - it('Handle Rotation that changes so keep the direction the same', () => { - const swipeFuncs = getMockedSwipeFunctions() - const { getByText, rerender } = render() + const swipeFuncsLargeRotation = getMockedSwipeFunctions(); + rerender( + + ); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TE](touchArea, cte({})); + expectSwipeFuncsDir(swipeFuncsLargeRotation, LEFT); + }); + + it("Handle Rotation that changes so keep the direction the same", () => { + const swipeFuncs = getMockedSwipeFunctions(); + const { getByText, rerender } = render( + + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); // check 0 - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 125, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 150, y: 100 })) - fireEvent[TE](touchArea, cte({})) - expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(1) - expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(1) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 125, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 150, y: 100 })); + fireEvent[TE](touchArea, cte({})); + expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(1); + expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(1); // check 90 - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 125 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 150 })) - fireEvent[TE](touchArea, cte({})) - expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(2) - expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(2) + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 125 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 150 })); + fireEvent[TE](touchArea, cte({})); + expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(2); + expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(2); // check 180 - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 75, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 50, y: 100 })) - fireEvent[TE](touchArea, cte({})) - expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(3) - expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(3) + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 75, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 50, y: 100 })); + fireEvent[TE](touchArea, cte({})); + expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(3); + expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(3); // check 270 - rerender() - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 75 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 50 })) - fireEvent[TE](touchArea, cte({})) - expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(4) - expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(4) - - expect(swipeFuncs.onSwiping).toHaveBeenCalledTimes(8) - ;[LEFT, UP, DOWN].forEach(dir => { - expect(swipeFuncs[`onSwiped${dir}`]).not.toHaveBeenCalled() - }) - }) - - it('Does not track touches when trackTouch is false', () => { - const onSwipedDown = jest.fn() + rerender(); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 75 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 50 })); + fireEvent[TE](touchArea, cte({})); + expect(swipeFuncs.onSwiped).toHaveBeenCalledTimes(4); + expect(swipeFuncs.onSwipedRight).toHaveBeenCalledTimes(4); + + expect(swipeFuncs.onSwiping).toHaveBeenCalledTimes(8); + [LEFT, UP, DOWN].forEach((dir) => { + expect(swipeFuncs[`onSwiped${dir}`]).not.toHaveBeenCalled(); + }); + }); + + it("Does not track touches when trackTouch is false", () => { + const onSwipedDown = jest.fn(); - const { getByText, rerender } = render() + const { getByText, rerender } = render( + + ); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); const doSwipe = () => { - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 200 })) - fireEvent[TE](touchArea, cte({})) - } - - doSwipe() - expect(onSwipedDown).toHaveBeenCalledTimes(1) - - rerender() - doSwipe() + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 200 })); + fireEvent[TE](touchArea, cte({})); + }; + + doSwipe(); + expect(onSwipedDown).toHaveBeenCalledTimes(1); + + rerender( + + ); + doSwipe(); // verify we did not trigger another swipe - expect(onSwipedDown).toHaveBeenCalledTimes(1) + expect(onSwipedDown).toHaveBeenCalledTimes(1); - rerender() - doSwipe() - expect(onSwipedDown).toHaveBeenCalledTimes(2) - }) + rerender( + + ); + doSwipe(); + expect(onSwipedDown).toHaveBeenCalledTimes(2); + }); - it('Cleans up and re-attaches touch event listeners if the DOM element changes', () => { - const onSwipedDown = jest.fn() + it("Cleans up and re-attaches touch event listeners if the DOM element changes", () => { + const onSwipedDown = jest.fn(); - const { getByText, rerender } = render() + const { getByText, rerender } = render( + + ); - let touchArea = getByText(TESTING_TEXT) + let touchArea = getByText(TESTING_TEXT); - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 200 })) - fireEvent[TE](touchArea, cte({})) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 200 })); + fireEvent[TE](touchArea, cte({})); - expect(onSwipedDown).toHaveBeenCalledTimes(1) + expect(onSwipedDown).toHaveBeenCalledTimes(1); - rerender() + rerender(); // re-get element since wrapping dom node changed - touchArea = getByText(TESTING_TEXT) - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 100, y: 200 })) - fireEvent[TE](touchArea, cte({})) + touchArea = getByText(TESTING_TEXT); + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 100, y: 200 })); + fireEvent[TE](touchArea, cte({})); // verify we triggered callbacks on new dom element - expect(onSwipedDown).toHaveBeenCalledTimes(2) - }) + expect(onSwipedDown).toHaveBeenCalledTimes(2); + }); it(`handles new prop swipe callbacks from rerenders`, () => { - const onSwipedSpy = jest.fn() + const onSwipedSpy = jest.fn(); function TestHookComponent({ next }) { - const handlers = useSwipeable({ onSwiped: next }) - return
{TESTING_TEXT}
+ const handlers = useSwipeable({ onSwiped: next }); + return
{TESTING_TEXT}
; } function TestComponent() { - const [page, setPage] = React.useState(0) + const [page, setPage] = React.useState(0); // Changing the callback on each re-render ON PURPOSE // In order to validate useSwipeable updates prop references - const next = () => (setPage(page + 1), onSwipedSpy(page + 1)) + const next = () => (setPage(page + 1), onSwipedSpy(page + 1)); - return + return ; } - const { getByText } = render() + const { getByText } = render(); - const touchArea = getByText(TESTING_TEXT) + const touchArea = getByText(TESTING_TEXT); - const pages = [1, 2, 3] + const pages = [1, 2, 3]; // swipe left 3 times pages.forEach(() => { act(() => { - fireEvent[TS](touchArea, cte({ x: 100, y: 100 })) - fireEvent[TM](touchArea, cte({ x: 75, y: 100 })) - fireEvent[TE](touchArea, cte({})) - }) - }) + fireEvent[TS](touchArea, cte({ x: 100, y: 100 })); + fireEvent[TM](touchArea, cte({ x: 75, y: 100 })); + fireEvent[TE](touchArea, cte({})); + }); + }); pages.forEach((page, idx) => { - expect(onSwipedSpy.mock.calls[idx][0]).toBe(page) - }) - }) -}) + expect(onSwipedSpy.mock.calls[idx][0]).toBe(page); + }); + }); +}); diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 5e5c7816..00000000 --- a/src/index.js +++ /dev/null @@ -1,219 +0,0 @@ -/* global document */ -import React from 'react' - -const defaultProps = { - preventDefaultTouchmoveEvent: false, - delta: 10, - rotationAngle: 0, - trackMouse: false, - trackTouch: true -} -const initialState = { - xy: [0, 0], - swiping: false, - eventData: undefined, - start: undefined -} -export const LEFT = 'Left' -export const RIGHT = 'Right' -export const UP = 'Up' -export const DOWN = 'Down' -const touchStart = 'touchstart' -const touchMove = 'touchmove' -const touchEnd = 'touchend' -const mouseMove = 'mousemove' -const mouseUp = 'mouseup' - -function getDirection(absX, absY, deltaX, deltaY) { - if (absX > absY) { - if (deltaX > 0) { - return LEFT - } - return RIGHT - } else if (deltaY > 0) { - return UP - } - return DOWN -} - -function rotateXYByAngle(pos, angle) { - if (angle === 0) return pos - const angleInRadians = (Math.PI / 180) * angle - const x = pos[0] * Math.cos(angleInRadians) + pos[1] * Math.sin(angleInRadians) - const y = pos[1] * Math.cos(angleInRadians) - pos[0] * Math.sin(angleInRadians) - return [x, y] -} - -function getHandlers(set, handlerProps) { - const onStart = event => { - // if more than a single touch don't track, for now... - if (event.touches && event.touches.length > 1) return - - set((state, props) => { - // setup mouse listeners on document to track swipe since swipe can leave container - if (props.trackMouse) { - document.addEventListener(mouseMove, onMove) - document.addEventListener(mouseUp, onUp) - } - const { clientX, clientY } = event.touches ? event.touches[0] : event - const xy = rotateXYByAngle([clientX, clientY], props.rotationAngle) - return { - ...state, - ...initialState, - eventData: { initial: [...xy], first: true }, - xy, - start: event.timeStamp || 0 - } - }) - } - - const onMove = event => { - set((state, props) => { - if (!state.xy[0] || !state.xy[1] || (event.touches && event.touches.length > 1)) { - return state - } - const { clientX, clientY } = event.touches ? event.touches[0] : event - const [x, y] = rotateXYByAngle([clientX, clientY], props.rotationAngle) - const deltaX = state.xy[0] - x - const deltaY = state.xy[1] - y - const absX = Math.abs(deltaX) - const absY = Math.abs(deltaY) - const time = (event.timeStamp || 0) - state.start - const velocity = Math.sqrt(absX * absX + absY * absY) / (time || 1) - - // if swipe is under delta and we have not started to track a swipe: skip update - if (absX < props.delta && absY < props.delta && !state.swiping) return state - - const dir = getDirection(absX, absY, deltaX, deltaY) - const eventData = { ...state.eventData, event, absX, absY, deltaX, deltaY, velocity, dir } - - props.onSwiping && props.onSwiping(eventData) - - // track if a swipe is cancelable(handler for swiping or swiped(dir) exists) - // so we can call preventDefault if needed - let cancelablePageSwipe = false - if (props.onSwiping || props.onSwiped || props[`onSwiped${dir}`]) { - cancelablePageSwipe = true - } - - if ( - cancelablePageSwipe && - props.preventDefaultTouchmoveEvent && - props.trackTouch && - event.cancelable - ) - event.preventDefault() - - // first is now always false - return { ...state, eventData: { ...eventData, first: false }, swiping: true } - }) - } - - const onEnd = event => { - set((state, props) => { - let eventData - if (state.swiping) { - eventData = { ...state.eventData, event } - - props.onSwiped && props.onSwiped(eventData) - - props[`onSwiped${eventData.dir}`] && props[`onSwiped${eventData.dir}`](eventData) - } - return { ...state, ...initialState, eventData } - }) - } - - const cleanUpMouse = () => { - // safe to just call removeEventListener - document.removeEventListener(mouseMove, onMove) - document.removeEventListener(mouseUp, onUp) - } - - const onUp = e => { - cleanUpMouse() - onEnd(e) - } - - const attachTouch = el => { - if (el && el.addEventListener) { - // attach touch event listeners and handlers - const tls = [[touchStart, onStart], [touchMove, onMove], [touchEnd, onEnd]] - tls.forEach(([e, h]) => el.addEventListener(e, h)) - // return properly scoped cleanup method for removing listeners - return () => tls.forEach(([e, h]) => el.removeEventListener(e, h)) - } - } - - const onRef = el => { - // "inline" ref functions are called twice on render, once with null then again with DOM element - // ignore null here - if (el === null) return - set((state, props) => { - // if the same DOM el as previous just return state - if (state.el === el) return state - - let addState = {} - // if new DOM el clean up old DOM and reset cleanUpTouch - if (state.el && state.el !== el && state.cleanUpTouch) { - state.cleanUpTouch() - addState.cleanUpTouch = null - } - // only attach if we want to track touch - if (props.trackTouch && el) { - addState.cleanUpTouch = attachTouch(el) - } - - // store event attached DOM el for comparison, clean up, and re-attachment - return { ...state, el, ...addState } - }) - } - - // set ref callback to attach touch event listeners - const output = { ref: onRef } - - // if track mouse attach mouse down listener - if (handlerProps.trackMouse) { - output.onMouseDown = onStart - } - - return [output, attachTouch] -} - -function updateTransientState(state, props, attachTouch) { - let addState = {} - // clean up touch handlers if no longer tracking touches - if (!props.trackTouch && state.cleanUpTouch) { - state.cleanUpTouch() - addState.cleanUpTouch = null - } else if (props.trackTouch && !state.cleanUpTouch) { - // attach/re-attach touch handlers - if (state.el) { - addState.cleanUpTouch = attachTouch(state.el) - } - } - return { ...state, ...addState } -} - -export function useSwipeable(props) { - const { trackMouse } = props - const transientState = React.useRef({ ...initialState, type: 'hook' }) - const transientProps = React.useRef() - transientProps.current = { ...defaultProps, ...props } - - const [handlers, attachTouch] = React.useMemo( - () => - getHandlers( - cb => (transientState.current = cb(transientState.current, transientProps.current)), - { trackMouse } - ), - [trackMouse] - ) - - transientState.current = updateTransientState( - transientState.current, - transientProps.current, - attachTouch - ) - - return handlers -} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..1ad0c6c8 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,346 @@ +/* global document */ +import * as React from "react"; + +export type HandledEvents = React.MouseEvent | React.TouchEvent; +export type Vector2 = [number, number]; +export type EventData = { + event: HandledEvents; + deltaX: number; + deltaY: number; + absX: number; + absY: number; + first: boolean; + initial: Vector2; + velocity: number; + dir: "Left" | "Right" | "Up" | "Down"; +}; + +export type SwipeCallback = (eventData: EventData) => void; + +export interface SwipeableOptions { + // Event handler/callbacks + onSwiped?: SwipeCallback; + onSwipedLeft?: SwipeCallback; + onSwipedRight?: SwipeCallback; + onSwipedUp?: SwipeCallback; + onSwipedDown?: SwipeCallback; + onSwiping?: SwipeCallback; + + // Configuration Props + delta?: number; + preventDefaultTouchmoveEvent?: boolean; + trackTouch?: boolean; + trackMouse?: boolean; + rotationAngle?: number; +} + +export interface SwipeableHandlers { + ref: (element: HTMLElement | null) => void; + onMouseDown?: React.MouseEventHandler; +} + +type StateEventData = { + event?: HandledEvents; + deltaX?: number; + deltaY?: number; + absX?: number; + absY?: number; + first: boolean; + initial: Vector2; + velocity?: number; + dir?: "Left" | "Right" | "Up" | "Down"; +}; + +type State = { + xy: Vector2; + swiping: boolean; + eventData?: StateEventData; + start?: number; + first?: boolean; + cleanUpTouch?(): void; + el?: React.DOMElement; +}; + +type Props = { + // Event handler/callbacks + onSwiped?: SwipeCallback; + onSwipedLeft?: SwipeCallback; + onSwipedRight?: SwipeCallback; + onSwipedUp?: SwipeCallback; + onSwipedDown?: SwipeCallback; + onSwiping?: SwipeCallback; + + // Configuration Props + delta: number; + preventDefaultTouchmoveEvent: boolean; + trackTouch: boolean; + trackMouse: boolean; + rotationAngle: number; +}; + +const defaultProps = { + preventDefaultTouchmoveEvent: false, + delta: 10, + rotationAngle: 0, + trackMouse: false, + trackTouch: true, +}; + +const initialState: State = { + xy: [0, 0], + swiping: false, + eventData: undefined, + start: undefined, +}; +export const LEFT = "Left"; +export const RIGHT = "Right"; +export const UP = "Up"; +export const DOWN = "Down"; +const touchStart = "touchstart"; +const touchMove = "touchmove"; +const touchEnd = "touchend"; +const mouseMove = "mousemove"; +const mouseUp = "mouseup"; + +function getDirection( + absX: number, + absY: number, + deltaX: number, + deltaY: number +) { + if (absX > absY) { + if (deltaX > 0) { + return LEFT; + } + return RIGHT; + } else if (deltaY > 0) { + return UP; + } + return DOWN; +} + +function rotateXYByAngle(pos: Vector2, angle: number): Vector2 { + if (angle === 0) return pos; + const angleInRadians = (Math.PI / 180) * angle; + const x = + pos[0] * Math.cos(angleInRadians) + pos[1] * Math.sin(angleInRadians); + const y = + pos[1] * Math.cos(angleInRadians) - pos[0] * Math.sin(angleInRadians); + return [x, y]; +} + +type Setter = (state: State, props: SwipeableOptions) => State; +type Set = (setter: Setter) => void; +function getHandlers( + set: Set, + handlerProps: { trackMouse: boolean | undefined } +): [ + { + ref: (element: HTMLElement | null) => void; + onMouseDown?: (event: HandledEvents) => void; + }, + (el: any) => (() => void) | undefined +] { + const onStart = (event: HandledEvents) => { + // if more than a single touch don't track, for now... + if (event && event.touches && event.touches.length > 1) return; + + set((state: State, props: SwipeableOptions) => { + // setup mouse listeners on document to track swipe since swipe can leave container + if (props.trackMouse) { + document.addEventListener(mouseMove, onMove); + document.addEventListener(mouseUp, onUp); + } + const { clientX, clientY } = event.touches ? event.touches[0] : event; + const xy = rotateXYByAngle([clientX, clientY], props.rotationAngle); + return { + ...state, + ...initialState, + eventData: { initial: [...xy], first: true }, + xy, + start: event.timeStamp || 0, + }; + }); + }; + + const onMove = (event: HandledEvents) => { + set((state, props) => { + if ( + !state.xy[0] || + !state.xy[1] || + (event.touches && event.touches.length > 1) + ) { + return state; + } + const { clientX, clientY } = event.touches ? event.touches[0] : event; + const [x, y] = rotateXYByAngle([clientX, clientY], props.rotationAngle); + const deltaX = state.xy[0] - x; + const deltaY = state.xy[1] - y; + const absX = Math.abs(deltaX); + const absY = Math.abs(deltaY); + const time = (event.timeStamp || 0) - state.start; + const velocity = Math.sqrt(absX * absX + absY * absY) / (time || 1); + + // if swipe is under delta and we have not started to track a swipe: skip update + if (absX < props.delta && absY < props.delta && !state.swiping) + return state; + + const dir = getDirection(absX, absY, deltaX, deltaY); + const eventData = { + ...state.eventData, + event, + absX, + absY, + deltaX, + deltaY, + velocity, + dir, + }; + + props.onSwiping && props.onSwiping(eventData); + + // track if a swipe is cancelable(handler for swiping or swiped(dir) exists) + // so we can call preventDefault if needed + let cancelablePageSwipe = false; + if (props.onSwiping || props.onSwiped || props[`onSwiped${dir}`]) { + cancelablePageSwipe = true; + } + + if ( + cancelablePageSwipe && + props.preventDefaultTouchmoveEvent && + props.trackTouch && + event.cancelable + ) + event.preventDefault(); + + // first is now always false + return { + ...state, + eventData: { ...eventData, first: false }, + swiping: true, + }; + }); + }; + + const onEnd = (event: HandledEvents) => { + set((state, props) => { + let eventData; + if (state.swiping) { + eventData = { ...state.eventData, event }; + + props.onSwiped && props.onSwiped(eventData); + + props[`onSwiped${eventData.dir}`] && + props[`onSwiped${eventData.dir}`](eventData); + } + return { ...state, ...initialState, eventData }; + }); + }; + + const cleanUpMouse = () => { + // safe to just call removeEventListener + document.removeEventListener(mouseMove, onMove); + document.removeEventListener(mouseUp, onUp); + }; + + const onUp = (e: HandledEvents) => { + cleanUpMouse(); + onEnd(e); + }; + + const attachTouch = (el: React.DOMElement) => { + if (el && el.addEventListener) { + // attach touch event listeners and handlers + const tls = [ + [touchStart, onStart], + [touchMove, onMove], + [touchEnd, onEnd], + ]; + tls.forEach(([e, h]) => el.addEventListener(e, h)); + // return properly scoped cleanup method for removing listeners + return () => tls.forEach(([e, h]) => el.removeEventListener(e, h)); + } + }; + + const onRef = (el: React.DOMElement) => { + // "inline" ref functions are called twice on render, once with null then again with DOM element + // ignore null here + if (el === null) return; + set((state, props) => { + // if the same DOM el as previous just return state + if (state.el === el) return state; + + let addState = {}; + // if new DOM el clean up old DOM and reset cleanUpTouch + if (state.el && state.el !== el && state.cleanUpTouch) { + state.cleanUpTouch(); + addState.cleanUpTouch = null; + } + // only attach if we want to track touch + if (props.trackTouch && el) { + addState.cleanUpTouch = attachTouch(el); + } + + // store event attached DOM el for comparison, clean up, and re-attachment + return { ...state, el, ...addState }; + }); + }; + + // set ref callback to attach touch event listeners + const output = { ref: onRef }; + + // if track mouse attach mouse down listener + if (handlerProps.trackMouse) { + output.onMouseDown = onStart; + } + + return [output, attachTouch]; +} + +function updateTransientState( + state: State, + props: Props, + attachTouch: (el: any) => (() => void) | undefined +) { + let addState: { cleanUpTouch?(): void } = {}; + // clean up touch handlers if no longer tracking touches + if (!props.trackTouch && state.cleanUpTouch) { + state.cleanUpTouch(); + addState.cleanUpTouch = undefined; + } else if (props.trackTouch && !state.cleanUpTouch) { + // attach/re-attach touch handlers + if (state.el) { + addState.cleanUpTouch = attachTouch(state.el); + } + } + return { ...state, ...addState }; +} + +export function useSwipeable(options: SwipeableOptions): SwipeableHandlers { + const { trackMouse } = options; + const transientState = React.useRef({ ...initialState }); + const transientProps = React.useRef({ ...defaultProps }); + transientProps.current = { ...defaultProps, ...options }; + + const [handlers, attachTouch] = React.useMemo( + () => + getHandlers( + (cb) => + (transientState.current = cb( + transientState.current, + transientProps.current + )), + { trackMouse } + ), + [trackMouse] + ); + + transientState.current = updateTransientState( + transientState.current, + transientProps.current, + attachTouch + ); + + return handlers; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..5acba3e3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "allowJs": true, + "baseUrl": ".", + "esModuleInterop": true, + "jsx": "react", + "lib": ["esnext", "dom"], + "module": "es2015", + "moduleResolution": "node", + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "lib/", + "pretty": true, + "rootDirs": ["./src", "./stories"], + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "esnext" + }, + "include": ["src/**/*"], + "exclude": ["examples/**/*"] +} diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index aae9b4c5..00000000 --- a/types/index.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -// TypeScript Version: 3.0 - -import * as React from 'react' - -export type Vector2 = [number, number] -export interface EventData { - event: MouseEvent | TouchEvent - deltaX: number - deltaY: number - absX: number - absY: number - first: boolean - initial: Vector2 - velocity: number - dir: 'Left' | 'Right' | 'Up' | 'Down' -} - -export type SwipeCallback = (eventData: EventData) => void - -export interface SwipeableOptions { - // Event handler/callbacks - onSwiped?: SwipeCallback - onSwipedLeft?: SwipeCallback - onSwipedRight?: SwipeCallback - onSwipedUp?: SwipeCallback - onSwipedDown?: SwipeCallback - onSwiping?: SwipeCallback - - // Configuration Props - delta?: number - preventDefaultTouchmoveEvent?: boolean - trackTouch?: boolean - trackMouse?: boolean - rotationAngle?: number -} - -// Component Specific Props -export interface SwipeableProps { - nodeName?: string - innerRef?: (element: HTMLElement | null) => void - children?: React.ReactNode - style?: React.CSSProperties - className?: string -} - -export interface SwipeableHandlers { - ref: (element: HTMLElement | null) => void - onMouseDown?: React.MouseEventHandler -} - -export function useSwipeable(options: SwipeableOptions): SwipeableHandlers - -export class Swipeable extends React.PureComponent {} diff --git a/types/test.tsx b/types/test.tsx deleted file mode 100644 index 9b3c17a9..00000000 --- a/types/test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import * as React from 'react' -import { Swipeable, SwipeableHandlers, SwipeableProps, SwipeCallback, useSwipeable } from 'react-swipeable' - -class SampleComponent extends React.PureComponent { - private readonly handleSwiped: SwipeCallback = () => {} - private readonly handleSwipedLeft: SwipeCallback = () => {} - private readonly handleSwipedRight: SwipeCallback = () => {} - private readonly handleSwipedUp: SwipeCallback = () => {} - private readonly handleSwipedDown: SwipeCallback = () => {} - private readonly handleSwiping: SwipeCallback = () => {} - - render() { - return ( - {}} - style={{ backgroundColor: 'blue' }} - className="classname" - > -
This element can be swiped
-
- ) - } -} - -class SwipeableDiv extends Swipeable {} - -const TestComponent: React.FunctionComponent = _ => { - const handleSwiped: SwipeCallback = () => {} - - return ( - -
this is sample code.
-
- ) -} - -const TestHook = () => { - const [swipeDir, setDir] = React.useState(''); - const handlers = useSwipeable({ onSwiped: ({ dir }) => setDir(dir) }) - return
{swipeDir}
-} - -const handlers: SwipeableHandlers = useSwipeable({ - onSwipedLeft: (data) => { - // verify EventData properties - const { - event, // $ExpectType MouseEvent | TouchEvent - deltaX, // $ExpectType number - deltaY, // $ExpectType number - absX, // $ExpectType number - absY, // $ExpectType number - first, // $ExpectType boolean - initial: [ - initialX, // $ExpectType number - initialY // $ExpectType number - ], - velocity, // $ExpectType number - dir, // $ExpectType "Left" | "Right" | "Up" | "Down" - ...rest // $ExpectType {} - } = data; - }, - preventDefaultTouchmoveEvent: true, - trackTouch: true, -}) - -handlers.ref(
) -handlers.ref(null) diff --git a/types/tsconfig.json b/types/tsconfig.json deleted file mode 100644 index 58de5e11..00000000 --- a/types/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "lib": ["es6"], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "noEmit": true, - "jsx": "react", - "baseUrl": ".", - "paths": { - "react-swipeable": ["."] - } - } -} diff --git a/types/tslint.json b/types/tslint.json deleted file mode 100644 index 29514206..00000000 --- a/types/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "dtslint/dtslint.json", - "rules": { - "semicolon": false - } -} diff --git a/yarn.lock b/yarn.lock index b460bc4a..a599f40d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -269,7 +269,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.3.3", "@babel/parser@^7.7.0": +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.3.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64" integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA== @@ -912,7 +912,7 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818" integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q== @@ -927,7 +927,7 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee" integrity sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg== @@ -1343,11 +1343,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -1591,7 +1586,7 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.0.0: +acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== @@ -1601,12 +1596,12 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^6.0.7, acorn@^6.4.1: +acorn@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.0, acorn@^7.1.1: +acorn@^7.1.0, acorn@^7.1.1, acorn@^7.2.0: version "7.3.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== @@ -1636,7 +1631,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.0.tgz#5c894537098785926d71e696114a53ce768ed773" integrity sha512-eyoaac3btgU8eJlvh01En8OCKzRqlLe2G5jDsCr3RiE2uLGMEEB1aaGwVVpwR8M95956tGH6R+9edC++OvzaVw== -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.5.5, ajv@^6.9.1: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.5.5: version "6.12.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== @@ -1656,10 +1651,10 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-escapes@^4.2.1: version "4.3.1" @@ -1678,11 +1673,6 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1805,14 +1795,6 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - array.prototype.flatmap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz#1c13f84a178566042dd63de4414440db9222e443" @@ -1923,18 +1905,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== -babel-eslint@^10.0.1: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - babel-jest@^26.1.0: version "26.1.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.1.0.tgz#b20751185fc7569a0f135730584044d1cb934328" @@ -2456,7 +2426,7 @@ chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2486,11 +2456,6 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - check-types@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" @@ -2575,18 +2540,6 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -2773,11 +2726,6 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -2916,7 +2864,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3209,7 +3157,7 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -3367,14 +3315,6 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -3526,6 +3466,13 @@ enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1: memory-fs "^0.5.0" tapable "^1.0.0" +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + entities@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" @@ -3538,7 +3485,7 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== @@ -3625,61 +3572,19 @@ escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^3.3.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz#8ca3ffac4bd6eeef623a0651f9d754900e3ec217" - integrity sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ== +eslint-config-prettier@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" + integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== dependencies: get-stdin "^6.0.0" -eslint-import-resolver-node@^0.3.3: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-import@^2.14.0: - version "2.22.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e" - integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg== - dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.3" - eslint-module-utils "^2.6.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" - -eslint-plugin-prettier@^3.0.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2" - integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-plugin-react-hooks@^1.6.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" - integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== +eslint-plugin-react-hooks@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.0.5.tgz#4879003aa38e5d05d0312175beb6e4a1f617bfcf" + integrity sha512-3YLSjoArsE2rUwL8li4Yxx1SUg3DQWp+78N3bcJQGWVZckcp+yeQGsap/MSq05+thJk57o+Ww4PtZukXGL02TQ== -eslint-plugin-react@^7.11.1: +eslint-plugin-react@^7.20.3: version "7.20.3" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.3.tgz#0590525e7eb83890ce71f73c2cf836284ad8c2f1" integrity sha512-txbo090buDeyV0ugF3YMWrzLIUqpYTsWSDZV9xLSmExE1P/Kmgg9++PD931r+KEWS66O1c9R4srLVVHmeHpoAg== @@ -3704,75 +3609,83 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@^5.9.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== +eslint@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.4.0.tgz#4e35a2697e6c1972f9d6ef2b690ad319f80f206f" + integrity sha512-gU+lxhlPHu45H3JkEGgYhWhkR9wLHHEXC9FbWFnTlEkbKyZKWgWRLgf61E8zWmBuI6g5xKBph9ltg3NtZMVF8g== dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" + enquirer "^2.3.5" + eslint-scope "^5.1.0" + eslint-utils "^2.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" + esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" + glob-parent "^5.0.0" + globals "^12.1.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" + levn "^0.4.1" + lodash "^4.17.14" minimatch "^3.0.4" - mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" + optionator "^0.9.1" progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" table "^5.2.3" text-table "^0.2.0" + v8-compile-cache "^2.0.3" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + acorn "^7.2.0" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.2.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: +esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -3977,15 +3890,6 @@ extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -4025,11 +3929,6 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - fast-glob@^3.0.3: version "3.2.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" @@ -4047,7 +3946,7 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -4105,13 +4004,6 @@ figures@^1.0.1: escape-string-regexp "^1.0.5" object-assign "^4.1.0" -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - file-entry-cache@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" @@ -4212,13 +4104,6 @@ find-cache-dir@^3.0.0: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -4452,7 +4337,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.1.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== @@ -4507,11 +4392,18 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^11.1.0, globals@^11.7.0: +globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + globalyzer@^0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.4.tgz#bc8e273afe1ac7c24eea8def5b802340c5cc534f" @@ -4846,7 +4738,7 @@ humanize-url@^1.0.0: normalize-url "^1.0.0" strip-url-auth "^1.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4993,25 +4885,6 @@ ini@^1.3.4, ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -5805,7 +5678,7 @@ jest@^26.1.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.0, js-yaml@^3.13.1: +js-yaml@^3.13.1: version "3.14.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== @@ -5988,7 +5861,15 @@ levenary@^1.1.1: dependencies: leven "^3.1.0" -levn@^0.3.0, levn@~0.3.0: +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -6001,16 +5882,6 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -6025,14 +5896,6 @@ loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: emojis-list "^3.0.0" json5 "^1.0.1" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -6073,7 +5936,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -6324,11 +6187,6 @@ mime@^2.0.3, mime@^2.4.4: resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -6465,11 +6323,6 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - nan@^2.12.1: version "2.14.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" @@ -6578,7 +6431,7 @@ node-releases@^1.1.58: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935" integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg== -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: +normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -6778,13 +6631,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - onetime@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" @@ -6812,7 +6658,7 @@ optimize-css-assets-webpack-plugin@^5.0.3: cssnano "^4.1.10" last-call-webpack-plugin "^3.0.0" -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -6824,6 +6670,18 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -6836,11 +6694,6 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - p-each-series@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" @@ -6851,13 +6704,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -6865,13 +6711,6 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -6920,11 +6759,6 @@ p-timeout@^3.1.0: dependencies: p-finally "^1.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -6963,13 +6797,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -7058,13 +6885,6 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -7130,13 +6950,6 @@ pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -7550,6 +7363,11 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.2 source-map "^0.6.1" supports-color "^6.1.0" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -7560,17 +7378,10 @@ prepend-http@^1.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@1.15.3: - version "1.15.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a" - integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg== +prettier@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" + integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== pretty-bytes@^3.0.0: version "3.0.1" @@ -7847,14 +7658,6 @@ react@^16.13.0: object-assign "^4.1.1" prop-types "^15.6.2" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-6.0.0.tgz#da75ce72762f2fa1f20c5a40d4dd80c77db969e3" @@ -7873,15 +7676,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^5.1.1, read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -7970,10 +7764,10 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== regexpu-core@^4.6.0, regexpu-core@^4.7.0: version "4.7.0" @@ -8120,21 +7914,13 @@ resolve@1.12.0: dependencies: path-parse "^1.0.6" -resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.16.0, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.16.0, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: path-parse "^1.0.6" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -8282,11 +8068,6 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" @@ -8299,13 +8080,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.4.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84" - integrity sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg== - dependencies: - tslib "^1.9.0" - sade@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.3.tgz#a217ccc4fb4abb2d271648bf48f6628b2636fa1b" @@ -8413,7 +8187,7 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -8897,14 +8671,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -8972,13 +8738,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -8993,11 +8752,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -9013,10 +8767,10 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" + integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== strip-outer@^1.0.0: version "1.0.1" @@ -9191,11 +8945,6 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -9221,13 +8970,6 @@ tiny-glob@^0.2.6: globalyzer "^0.1.0" globrex "^0.1.1" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -9323,16 +9065,6 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - tslib@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -9365,6 +9097,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -9417,7 +9156,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.9.5: +typescript@^3.9.5, typescript@^3.9.6: version "3.9.6" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a" integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw== @@ -9584,7 +9323,7 @@ uuid@^7.0.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -v8-compile-cache@^2.1.1: +v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== @@ -9883,7 +9622,7 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -word-wrap@~1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== From cdf5d93f27fc00e0af9ce27bd21232731d393993 Mon Sep 17 00:00:00 2001 From: Emil Hartz Date: Mon, 6 Jul 2020 16:31:24 -0600 Subject: [PATCH 2/4] fix, with air quotes, all type errors --- src/index.ts | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1ad0c6c8..1e00ce0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ /* global document */ import * as React from "react"; -export type HandledEvents = React.MouseEvent | React.TouchEvent; +export type HandledEvents = MouseEvent | TouchEvent; export type Vector2 = [number, number]; export type EventData = { event: HandledEvents; @@ -35,8 +35,8 @@ export interface SwipeableOptions { } export interface SwipeableHandlers { - ref: (element: HTMLElement | null) => void; - onMouseDown?: React.MouseEventHandler; + ref(element: HTMLElement | null): void; + onMouseDown?(event: HandledEvents): void; } type StateEventData = { @@ -55,10 +55,10 @@ type State = { xy: Vector2; swiping: boolean; eventData?: StateEventData; - start?: number; + start: number; first?: boolean; cleanUpTouch?(): void; - el?: React.DOMElement; + el?: HTMLElement; }; type Props = { @@ -90,7 +90,7 @@ const initialState: State = { xy: [0, 0], swiping: false, eventData: undefined, - start: undefined, + start: 0, }; export const LEFT = "Left"; export const RIGHT = "Right"; @@ -129,7 +129,7 @@ function rotateXYByAngle(pos: Vector2, angle: number): Vector2 { return [x, y]; } -type Setter = (state: State, props: SwipeableOptions) => State; +type Setter = (state: State, props: Props) => State; type Set = (setter: Setter) => void; function getHandlers( set: Set, @@ -143,15 +143,15 @@ function getHandlers( ] { const onStart = (event: HandledEvents) => { // if more than a single touch don't track, for now... - if (event && event.touches && event.touches.length > 1) return; + if (event && ('touches' in event) && event.touches.length > 1) return; - set((state: State, props: SwipeableOptions) => { + set((state, props) => { // setup mouse listeners on document to track swipe since swipe can leave container if (props.trackMouse) { document.addEventListener(mouseMove, onMove); document.addEventListener(mouseUp, onUp); } - const { clientX, clientY } = event.touches ? event.touches[0] : event; + const { clientX, clientY } = ('touches' in event) ? event.touches[0] : event; const xy = rotateXYByAngle([clientX, clientY], props.rotationAngle); return { ...state, @@ -168,11 +168,11 @@ function getHandlers( if ( !state.xy[0] || !state.xy[1] || - (event.touches && event.touches.length > 1) + (('touches' in event) && event.touches.length > 1) ) { return state; } - const { clientX, clientY } = event.touches ? event.touches[0] : event; + const { clientX, clientY } = ('touches' in event) ? event.touches[0] : event; const [x, y] = rotateXYByAngle([clientX, clientY], props.rotationAngle); const deltaX = state.xy[0] - x; const deltaY = state.xy[1] - y; @@ -186,7 +186,7 @@ function getHandlers( return state; const dir = getDirection(absX, absY, deltaX, deltaY); - const eventData = { + const eventData: EventData = { ...state.eventData, event, absX, @@ -195,14 +195,14 @@ function getHandlers( deltaY, velocity, dir, - }; + } as EventData; props.onSwiping && props.onSwiping(eventData); // track if a swipe is cancelable(handler for swiping or swiped(dir) exists) // so we can call preventDefault if needed let cancelablePageSwipe = false; - if (props.onSwiping || props.onSwiped || props[`onSwiped${dir}`]) { + if (props.onSwiping || props.onSwiped || (`onSwiped${dir}` in props)) { cancelablePageSwipe = true; } @@ -225,14 +225,16 @@ function getHandlers( const onEnd = (event: HandledEvents) => { set((state, props) => { - let eventData; + let eventData: EventData | undefined; if (state.swiping) { - eventData = { ...state.eventData, event }; + eventData = { ...state.eventData, event } as EventData; props.onSwiped && props.onSwiped(eventData); - props[`onSwiped${eventData.dir}`] && - props[`onSwiped${eventData.dir}`](eventData); + const onSwipedDir = `onSwiped${eventData.dir}`; + if ((onSwipedDir in props)) { + (props as any)[onSwipedDir](eventData); + } } return { ...state, ...initialState, eventData }; }); @@ -249,10 +251,10 @@ function getHandlers( onEnd(e); }; - const attachTouch = (el: React.DOMElement) => { + const attachTouch = (el: HTMLElement) => { if (el && el.addEventListener) { // attach touch event listeners and handlers - const tls = [ + const tls: [typeof touchStart | typeof touchMove | typeof touchEnd, (e: HandledEvents) => void][] = [ [touchStart, onStart], [touchMove, onMove], [touchEnd, onEnd], @@ -263,7 +265,7 @@ function getHandlers( } }; - const onRef = (el: React.DOMElement) => { + const onRef = (el: HTMLElement | null) => { // "inline" ref functions are called twice on render, once with null then again with DOM element // ignore null here if (el === null) return; @@ -271,7 +273,7 @@ function getHandlers( // if the same DOM el as previous just return state if (state.el === el) return state; - let addState = {}; + let addState: { cleanUpTouch?: (() => void) | null } = {}; // if new DOM el clean up old DOM and reset cleanUpTouch if (state.el && state.el !== el && state.cleanUpTouch) { state.cleanUpTouch(); @@ -283,12 +285,12 @@ function getHandlers( } // store event attached DOM el for comparison, clean up, and re-attachment - return { ...state, el, ...addState }; + return { ...state, el, ...addState } as State; }); }; // set ref callback to attach touch event listeners - const output = { ref: onRef }; + const output: { ref: typeof onRef, onMouseDown?: typeof onStart} = { ref: onRef }; // if track mouse attach mouse down listener if (handlerProps.trackMouse) { From 83ef4d2ea8e7b88154707b806df02d1d0c8ecdb9 Mon Sep 17 00:00:00 2001 From: Emil Hartz Date: Mon, 13 Jul 2020 17:06:43 -0700 Subject: [PATCH 3/4] overhaul tests to typescript, update ts configs --- .eslintrc.js | 2 +- .../__snapshots__/useSwipeable.spec.tsx.snap | 0 __tests__/helpers/index.ts | 19 ++ .../useSwipeable.spec.tsx | 52 +++-- package.json | 19 +- src/__tests__/helpers/index.js | 17 -- src/index.ts | 33 +-- tsconfig.all.json | 4 + tsconfig.base.json | 21 ++ tsconfig.json | 23 +-- tsconfig.test.json | 4 + yarn.lock | 193 +++++++++++++++--- 12 files changed, 283 insertions(+), 104 deletions(-) rename src/__tests__/__snapshots__/useSwipeable.spec.js.snap => __tests__/__snapshots__/useSwipeable.spec.tsx.snap (100%) create mode 100644 __tests__/helpers/index.ts rename src/__tests__/useSwipeable.spec.js => __tests__/useSwipeable.spec.tsx (92%) delete mode 100644 src/__tests__/helpers/index.js create mode 100644 tsconfig.all.json create mode 100644 tsconfig.base.json create mode 100644 tsconfig.test.json diff --git a/.eslintrc.js b/.eslintrc.js index 40886920..33923eff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { parser: '@typescript-eslint/parser', parserOptions: { - project: './tsconfig.json', + project: './tsconfig.all.json', }, extends: [ 'eslint:recommended', diff --git a/src/__tests__/__snapshots__/useSwipeable.spec.js.snap b/__tests__/__snapshots__/useSwipeable.spec.tsx.snap similarity index 100% rename from src/__tests__/__snapshots__/useSwipeable.spec.js.snap rename to __tests__/__snapshots__/useSwipeable.spec.tsx.snap diff --git a/__tests__/helpers/index.ts b/__tests__/helpers/index.ts new file mode 100644 index 00000000..e9de7b58 --- /dev/null +++ b/__tests__/helpers/index.ts @@ -0,0 +1,19 @@ +import {MockedSwipeFunctions} from '../useSwipeable.spec'; + +const expectSwipingDir = (fns: jest.Mock, dir: string) => { + fns.mock.calls.forEach((call) => { + expect(call[0].dir).toBe(dir); + }); +}; + +export const expectSwipeFuncsDir = (sf: MockedSwipeFunctions, dir: string): void => { + Object.keys(sf).forEach((s) => { + if (s.endsWith(dir) || s === "onSwiped") { + expect(sf[s as keyof MockedSwipeFunctions]).toHaveBeenCalled(); + } else if (s === "onSwiping") { + expectSwipingDir(sf[s], dir); + } else { + expect(sf[s as keyof MockedSwipeFunctions]).not.toHaveBeenCalled(); + } + }); +} diff --git a/src/__tests__/useSwipeable.spec.js b/__tests__/useSwipeable.spec.tsx similarity index 92% rename from src/__tests__/useSwipeable.spec.js rename to __tests__/useSwipeable.spec.tsx index 2d243445..9f79b56d 100644 --- a/src/__tests__/useSwipeable.spec.js +++ b/__tests__/useSwipeable.spec.tsx @@ -1,18 +1,31 @@ -/* global document, jest, expect, beforeAll */ -import React from "react"; +import * as React from "react"; import { render, fireEvent, act } from "@testing-library/react"; -import { useSwipeable, LEFT, RIGHT, UP, DOWN } from "../index"; +import { useSwipeable, LEFT, RIGHT, UP, DOWN } from "../src/index"; import { expectSwipeFuncsDir } from "./helpers"; -const DIRECTIONS = [LEFT, RIGHT, UP, DOWN]; - -function getMockedSwipeFunctions() { +const DIRECTIONS: [typeof LEFT, typeof RIGHT, typeof UP, typeof DOWN] = [ + LEFT, + RIGHT, + UP, + DOWN, +]; + +export type MockedSwipeFunctions = { + onSwiping: jest.Mock; + onSwiped: jest.Mock; + onSwipedLeft: jest.Mock; + onSwipedRight: jest.Mock; + onSwipedUp: jest.Mock; + onSwipedDown: jest.Mock; +}; +function getMockedSwipeFunctions(): MockedSwipeFunctions { + const onSwiped = "onSwiped"; return DIRECTIONS.reduce( - (acc, dir) => ({ ...acc, [`onSwiped${dir}`]: jest.fn() }), + (acc, dir) => ({ ...acc, [onSwiped + dir]: jest.fn() }), { onSwiping: jest.fn(), onSwiped: jest.fn(), - } + } as MockedSwipeFunctions ); } @@ -22,7 +35,7 @@ const TESTING_TEXT = "touch here"; */ function SwipeableUsingHook({ nodeName = "div", ...rest }) { const eventHandlers = useSwipeable(rest); - const Elem = nodeName; + const Elem = nodeName as React.ElementType; return ( {TESTING_TEXT} @@ -37,11 +50,18 @@ const TS = "touchStart"; const TM = "touchMove"; const TE = "touchEnd"; -const createClientXYObject = (x, y) => ({ clientX: x, clientY: y }); +const createClientXYObject = (x?: number, y?: number) => ({ + clientX: x, + clientY: y, +}); // Create touch event -const cte = ({ x, y }) => ({ touches: [createClientXYObject(x, y)] }); +const cte = ({ x, y }: { x?: number; y?: number }) => ({ + touches: [createClientXYObject(x, y)], +}); // Create Mouse Event -const cme = ({ x, y }) => ({ ...createClientXYObject(x, y) }); +const cme = ({ x, y }: { x?: number; y?: number }) => ({ + ...createClientXYObject(x, y), +}); describe("useSwipeable", () => { let defaultPrevented = 0; @@ -336,7 +356,9 @@ describe("useSwipeable", () => { expect(swipeFuncs.onSwiping).toHaveBeenCalledTimes(8); [LEFT, UP, DOWN].forEach((dir) => { - expect(swipeFuncs[`onSwiped${dir}`]).not.toHaveBeenCalled(); + expect( + swipeFuncs[`onSwiped${dir}` as keyof MockedSwipeFunctions] + ).not.toHaveBeenCalled(); }); }); @@ -397,10 +419,10 @@ describe("useSwipeable", () => { expect(onSwipedDown).toHaveBeenCalledTimes(2); }); - it(`handles new prop swipe callbacks from rerenders`, () => { + it(`handles new prop swipe callbacks from re-renders`, () => { const onSwipedSpy = jest.fn(); - function TestHookComponent({ next }) { + function TestHookComponent({ next }: { next: () => void }) { const handlers = useSwipeable({ onSwiped: next }); return
{TESTING_TEXT}
; } diff --git a/package.json b/package.json index 3a69b3fe..20769855 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,15 @@ "jsnext:main": "./dist/react-swipeable.modern.js", "module": "./dist/react-swipeable.module.js", "source": "./src/index.ts", + "types": "./dist/index.d.ts", + "typings": "./dist/index.d.ts", "scripts": { "build": "microbundle --no-compress --name swipeable --output dist", "build:examples": "webpack -p --config ./examples/webpack.config.min.js", "build:publish:examples": "npm run build:examples && rimraf examples/node_modules && gh-pages -d examples", "clean": "rimraf dist", - "format": "prettier --write src/", - "lint": "eslint .", + "format": "prettier --write src __tests__", + "lint": "eslint . --ext .ts,.tsx", "prebuild": "npm run clean", "prepare": "npm run build", "pretest": "npm run lint", @@ -32,10 +34,9 @@ } ], "jest": { - "testPathIgnorePatterns": [ - "/node_modules/", - "/types/", - "/__tests__/helpers/" + "preset": "ts-jest", + "testMatch": [ + "/__tests__/**/*.(test|spec).ts?(x)" ] }, "keywords": [ @@ -68,14 +69,16 @@ "types/index.d.ts" ], "license": "MIT", - "types": "types", "devDependencies": { "@babel/plugin-proposal-class-properties": "^7.2.0", "@babel/plugin-proposal-object-rest-spread": "^7.2.0", "@babel/preset-env": "^7.2.0", "@babel/preset-react": "^7.10.4", "@testing-library/react": "^10.4.3", + "@types/jest": "^26.0.4", "@types/react": "^16.8.12", + "@typescript-eslint/eslint-plugin": "^3.6.1", + "@typescript-eslint/parser": "^3.6.1", "babel-jest": "^26.1.0", "babel-loader": "^8.0.5", "coveralls": "^3.0.3", @@ -94,11 +97,13 @@ "rollup": "^1.1.2", "rollup-plugin-babel": "^4.3.2", "size-limit": "^1.3.5", + "ts-jest": "^26.1.2", "typescript": "^3.9.6", "webpack": "^4.29.0", "webpack-cli": "^3.2.1", "webpack-dev-server": "^3.1.14" }, + "dependencies": {}, "peerDependencies": { "react": ">= 16.8.0" } diff --git a/src/__tests__/helpers/index.js b/src/__tests__/helpers/index.js deleted file mode 100644 index 79fac421..00000000 --- a/src/__tests__/helpers/index.js +++ /dev/null @@ -1,17 +0,0 @@ -/* global expect */ -const expectSwipingDir = (fns, dir) => { - fns.mock.calls.forEach((call) => { - expect(call[0].dir).toBe(dir); - }); -}; - -export const expectSwipeFuncsDir = (sf, dir) => - Object.keys(sf).forEach((s) => { - if (s.endsWith(dir) || s === "onSwiped") { - expect(sf[s]).toHaveBeenCalled(); - } else if (s === "onSwiping") { - expectSwipingDir(sf[s], dir); - } else { - expect(sf[s]).not.toHaveBeenCalled(); - } - }); diff --git a/src/index.ts b/src/index.ts index 1e00ce0c..f7a67baa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ /* global document */ import * as React from "react"; -export type HandledEvents = MouseEvent | TouchEvent; +export type HandledEvents = React.MouseEvent | TouchEvent | MouseEvent; export type Vector2 = [number, number]; export type EventData = { event: HandledEvents; @@ -36,7 +36,7 @@ export interface SwipeableOptions { export interface SwipeableHandlers { ref(element: HTMLElement | null): void; - onMouseDown?(event: HandledEvents): void; + onMouseDown?(event: React.MouseEvent): void; } type StateEventData = { @@ -137,13 +137,13 @@ function getHandlers( ): [ { ref: (element: HTMLElement | null) => void; - onMouseDown?: (event: HandledEvents) => void; + onMouseDown?: (event: React.MouseEvent) => void; }, (el: any) => (() => void) | undefined ] { const onStart = (event: HandledEvents) => { // if more than a single touch don't track, for now... - if (event && ('touches' in event) && event.touches.length > 1) return; + if (event && "touches" in event && event.touches.length > 1) return; set((state, props) => { // setup mouse listeners on document to track swipe since swipe can leave container @@ -151,7 +151,8 @@ function getHandlers( document.addEventListener(mouseMove, onMove); document.addEventListener(mouseUp, onUp); } - const { clientX, clientY } = ('touches' in event) ? event.touches[0] : event; + const { clientX, clientY } = + "touches" in event ? event.touches[0] : event; const xy = rotateXYByAngle([clientX, clientY], props.rotationAngle); return { ...state, @@ -168,11 +169,12 @@ function getHandlers( if ( !state.xy[0] || !state.xy[1] || - (('touches' in event) && event.touches.length > 1) + ("touches" in event && event.touches.length > 1) ) { return state; } - const { clientX, clientY } = ('touches' in event) ? event.touches[0] : event; + const { clientX, clientY } = + "touches" in event ? event.touches[0] : event; const [x, y] = rotateXYByAngle([clientX, clientY], props.rotationAngle); const deltaX = state.xy[0] - x; const deltaY = state.xy[1] - y; @@ -202,7 +204,7 @@ function getHandlers( // track if a swipe is cancelable(handler for swiping or swiped(dir) exists) // so we can call preventDefault if needed let cancelablePageSwipe = false; - if (props.onSwiping || props.onSwiped || (`onSwiped${dir}` in props)) { + if (props.onSwiping || props.onSwiped || `onSwiped${dir}` in props) { cancelablePageSwipe = true; } @@ -232,7 +234,7 @@ function getHandlers( props.onSwiped && props.onSwiped(eventData); const onSwipedDir = `onSwiped${eventData.dir}`; - if ((onSwipedDir in props)) { + if (onSwipedDir in props) { (props as any)[onSwipedDir](eventData); } } @@ -254,7 +256,10 @@ function getHandlers( const attachTouch = (el: HTMLElement) => { if (el && el.addEventListener) { // attach touch event listeners and handlers - const tls: [typeof touchStart | typeof touchMove | typeof touchEnd, (e: HandledEvents) => void][] = [ + const tls: [ + typeof touchStart | typeof touchMove | typeof touchEnd, + (e: HandledEvents) => void + ][] = [ [touchStart, onStart], [touchMove, onMove], [touchEnd, onEnd], @@ -273,7 +278,7 @@ function getHandlers( // if the same DOM el as previous just return state if (state.el === el) return state; - let addState: { cleanUpTouch?: (() => void) | null } = {}; + const addState: { cleanUpTouch?: (() => void) | null } = {}; // if new DOM el clean up old DOM and reset cleanUpTouch if (state.el && state.el !== el && state.cleanUpTouch) { state.cleanUpTouch(); @@ -290,7 +295,9 @@ function getHandlers( }; // set ref callback to attach touch event listeners - const output: { ref: typeof onRef, onMouseDown?: typeof onStart} = { ref: onRef }; + const output: { ref: typeof onRef; onMouseDown?: typeof onStart } = { + ref: onRef, + }; // if track mouse attach mouse down listener if (handlerProps.trackMouse) { @@ -305,7 +312,7 @@ function updateTransientState( props: Props, attachTouch: (el: any) => (() => void) | undefined ) { - let addState: { cleanUpTouch?(): void } = {}; + const addState: { cleanUpTouch?(): void } = {}; // clean up touch handlers if no longer tracking touches if (!props.trackTouch && state.cleanUpTouch) { state.cleanUpTouch(); diff --git a/tsconfig.all.json b/tsconfig.all.json new file mode 100644 index 00000000..e7ee30b2 --- /dev/null +++ b/tsconfig.all.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["src/**/*", "__tests__"], + } diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000..1f7cea10 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "allowJs": true, + "baseUrl": ".", + "esModuleInterop": true, + "jsx": "react", + "lib": ["ESNext", "dom"], + "module": "ESNext", + "moduleResolution": "node", + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "lib/", + "pretty": true, + "rootDirs": ["./src", "./stories"], + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "ESNext" + } +} diff --git a/tsconfig.json b/tsconfig.json index 5acba3e3..8bb85fb0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,4 @@ { - "compilerOptions": { - "allowJs": true, - "baseUrl": ".", - "esModuleInterop": true, - "jsx": "react", - "lib": ["esnext", "dom"], - "module": "es2015", - "moduleResolution": "node", - "noImplicitAny": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "outDir": "lib/", - "pretty": true, - "rootDirs": ["./src", "./stories"], - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "target": "esnext" - }, + "extends": "./tsconfig.base.json", "include": ["src/**/*"], - "exclude": ["examples/**/*"] -} + } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..52e9e1a7 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.base.json", + "include": ["__tests__"], + } diff --git a/yarn.lock b/yarn.lock index a599f40d..0f1bbad9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1293,6 +1293,11 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/eslint-visitor-keys@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" + integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== + "@types/estree@*": version "0.0.45" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" @@ -1338,7 +1343,15 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/json-schema@^7.0.4": +"@types/jest@^26.0.4": + version "26.0.4" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.4.tgz#d2e513e85aca16992816f192582b5e67b0b15efb" + integrity sha512-4fQNItvelbNA9+sFgU+fhJo8ZFF+AS4Egk3GWwCW2jFtViukXbnztccafAdLhzE/0EiCogljtQQXP8aQ9J7sFg== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + +"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4": version "7.0.5" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== @@ -1410,6 +1423,66 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.6.1.tgz#5ced8fd2087fbb83a76973dea4a0d39d9cb4a642" + integrity sha512-06lfjo76naNeOMDl+mWG9Fh/a0UHKLGhin+mGaIw72FUMbMGBkdi/FEJmgEDzh4eE73KIYzHWvOCYJ0ak7nrJQ== + dependencies: + "@typescript-eslint/experimental-utils" "3.6.1" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.6.1.tgz#b5a2738ebbceb3fa90c5b07d50bb1225403c4a54" + integrity sha512-oS+hihzQE5M84ewXrTlVx7eTgc52eu+sVmG7ayLfOhyZmJ8Unvf3osyFQNADHP26yoThFfbxcibbO0d2FjnYhg== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/types" "3.6.1" + "@typescript-eslint/typescript-estree" "3.6.1" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.6.1.tgz#216e8adf4ee9c629f77c985476a2ea07fb80e1dc" + integrity sha512-SLihQU8RMe77YJ/jGTqOt0lMq7k3hlPVfp7v/cxMnXA9T0bQYoMDfTsNgHXpwSJM1Iq2aAJ8WqekxUwGv5F67Q== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "3.6.1" + "@typescript-eslint/types" "3.6.1" + "@typescript-eslint/typescript-estree" "3.6.1" + eslint-visitor-keys "^1.1.0" + +"@typescript-eslint/types@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.6.1.tgz#87600fe79a1874235d3cc1cf5c7e1a12eea69eee" + integrity sha512-NPxd5yXG63gx57WDTW1rp0cF3XlNuuFFB5G+Kc48zZ+51ZnQn9yjDEsjTPQ+aWM+V+Z0I4kuTFKjKvgcT1F7xQ== + +"@typescript-eslint/typescript-estree@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.6.1.tgz#a5c91fcc5497cce7922ff86bc37d5e5891dcdefa" + integrity sha512-G4XRe/ZbCZkL1fy09DPN3U0mR6SayIv1zSeBNquRFRk7CnVLgkC2ZPj8llEMJg5Y8dJ3T76SvTGtceytniaztQ== + dependencies: + "@typescript-eslint/types" "3.6.1" + "@typescript-eslint/visitor-keys" "3.6.1" + debug "^4.1.1" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.6.1.tgz#5c57a7772f4dd623cfeacc219303e7d46f963b37" + integrity sha512-qC8Olwz5ZyMTZrh4Wl3K4U6tfms0R/mzU4/5W3XeUZptVraGVmbptJbn6h2Ey6Rb3hOs3zWoAUebZk8t47KGiQ== + dependencies: + eslint-visitor-keys "^1.1.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2238,6 +2311,13 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5: escalade "^3.0.1" node-releases "^1.1.58" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -2250,7 +2330,7 @@ buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer-from@^1.0.0: +buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -3274,6 +3354,11 @@ detect-passive-events@^1.0.0: resolved "https://registry.yarnpkg.com/detect-passive-events/-/detect-passive-events-1.0.4.tgz#6ed477e6e5bceb79079735dcd357789d37f9a91a" integrity sha1-btR35uW863kHlzXc01d4nTf5qRo= +diff-sequences@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" + integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== + diff-sequences@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" @@ -3609,7 +3694,7 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.1.0: +eslint-scope@^5.0.0, eslint-scope@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== @@ -3941,7 +4026,7 @@ fast-glob@^3.0.3: micromatch "^4.0.2" picomatch "^2.2.1" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -4344,7 +4429,7 @@ glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: +glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -5357,6 +5442,16 @@ jest-config@^26.1.0: micromatch "^4.0.2" pretty-format "^26.1.0" +jest-diff@^25.2.1: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" + integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.6" + jest-get-type "^25.2.6" + pretty-format "^25.5.0" + jest-diff@^26.1.0: version "26.1.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.1.0.tgz#00a549bdc936c9691eb4dc25d1fbd78bf456abb2" @@ -5408,6 +5503,11 @@ jest-environment-node@^26.1.0: jest-mock "^26.1.0" jest-util "^26.1.0" +jest-get-type@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" + integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== + jest-get-type@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" @@ -5613,7 +5713,7 @@ jest-snapshot@^26.1.0: pretty-format "^26.1.0" semver "^7.3.2" -jest-util@^26.1.0: +jest-util@26.x, jest-util@^26.1.0: version "26.1.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.1.0.tgz#80e85d4ba820decacf41a691c2042d5276e5d8d8" integrity sha512-rNMOwFQevljfNGvbzNQAxdmXQ+NawW/J72dmddsK0E8vgxXCMtwQ/EH0BiWEIxh0hhMcTsxwAxINt7Lh46Uzbg== @@ -5763,6 +5863,13 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== +json5@2.x, json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -5770,13 +5877,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -5916,7 +6016,7 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.memoize@^4.1.2: +lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= @@ -5994,6 +6094,11 @@ make-dir@^3.0.0, make-dir@^3.0.2: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -6266,6 +6371,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -7395,7 +7505,7 @@ pretty-bytes@^5.3.0: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== -pretty-format@^25.5.0: +pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== @@ -7764,7 +7874,7 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" -regexpp@^3.1.0: +regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== @@ -8197,16 +8307,16 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== +semver@7.x, semver@^7.2.1, semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== - send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -9065,16 +9175,39 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-jest@^26.1.2: + version "26.1.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.2.tgz#dd2e832ffae9cb803361483b6a3010a6413dc475" + integrity sha512-V4SyBDO9gOdEh+AF4KtXJeP+EeI4PkOrxcA8ptl4o8nCXUVM5Gg/8ngGKneS5BsZaR9DXVQNqj9k+iqGAnpGow== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "26.x" + json5 "2.x" + lodash.memoize "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "18.x" + tslib@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -tslib@^1.13.0, tslib@^1.9.0: +tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -9728,6 +9861,14 @@ yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== +yargs-parser@18.x, yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -9744,14 +9885,6 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" From fc4e0afc5933cd5c61694e0388822a2bed19ff1c Mon Sep 17 00:00:00 2001 From: Emil Hartz Date: Sat, 18 Jul 2020 16:16:06 -0700 Subject: [PATCH 4/4] remove eslintrc js extension --- .eslintrc | 31 +++++++++++++++++++++++++++++++ .eslintrc.js | 31 ------------------------------- package.json | 8 +++----- 3 files changed, 34 insertions(+), 36 deletions(-) create mode 100644 .eslintrc delete mode 100644 .eslintrc.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..d86f478d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,31 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.all.json" + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + "plugins": ["@typescript-eslint", "react-hooks"], + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "_" }], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-ignore": "off", + "react/no-unescaped-entities": "off", + "react/prop-types": "off", + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" + } +} diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 33923eff..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - project: './tsconfig.all.json', - }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react/recommended', - 'prettier', - 'prettier/@typescript-eslint', - ], - plugins: ['@typescript-eslint', 'react-hooks'], - settings: { - react: { - version: 'detect', - }, - }, - rules: { - '@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '_' }], - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-ignore': 'off', - 'react/no-unescaped-entities': 'off', - 'react/prop-types': 'off', - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - }, -}; diff --git a/package.json b/package.json index 20769855..802cf252 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-swipeable", "version": "5.5.1", - "description": "React Swipe event handler component & hook", + "description": "React Swipe event handler hook", "main": "./dist/react-swipeable.js", "browser": "./dist/react-swipeable.umd.js", "umd:main": "./dist/react-swipeable.umd.js", @@ -63,10 +63,8 @@ }, "homepage": "https://github.com/FormidableLabs/react-swipeable", "files": [ - "lib", - "es", - "src", - "types/index.d.ts" + "dist", + "src" ], "license": "MIT", "devDependencies": {