├── .changeset ├── README.md └── config.json ├── .codesandbox └── ci.json ├── .eslintignore ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml └── workflows │ ├── documentation.yml │ ├── main.yml │ └── release.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── babel.config.js ├── demo ├── index.html ├── package.json ├── src │ ├── App.jsx │ ├── index.css │ ├── index.tsx │ ├── sandboxes │ │ ├── action-sheet │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── card-zoom │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── cards-stack │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── dots-connect │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── draggable-image │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── draggable-list-prevent-scroll │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ ├── styles.module.css │ │ │ │ └── types.d.ts │ │ │ └── tsconfig.json │ │ ├── draggable-list │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ ├── styles.module.css │ │ │ │ └── types.d.ts │ │ │ └── tsconfig.json │ │ ├── gesture-drag-target │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-drag-vanilla │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── gesture-drag │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-move │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── gesture-nested │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-pinch-multiple │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-pinch │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-scroll │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-simplest │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── gesture-three-prevent-scroll │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── gesture-three │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── gesture-vanilla │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── gesture-wheel │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ └── styles.module.css │ │ ├── infinite-slideshow │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ └── src │ │ │ │ ├── App.jsx │ │ │ │ ├── Slider.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ ├── items.js │ │ │ │ └── styles.module.css │ │ ├── native-vs-lib │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.jsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ ├── slide │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ │ └── viewpager │ │ │ ├── .prettierrc │ │ │ ├── package.json │ │ │ ├── public │ │ │ └── index.html │ │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ │ │ └── tsconfig.json │ ├── styles.module.css │ └── vite.env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.js ├── documentation ├── .gitignore ├── LICENSE ├── README.md ├── gatsby-browser.js ├── gatsby-config.js ├── images │ ├── 404.png │ ├── compass.svg │ ├── game.svg │ ├── logo-manifest.png │ ├── logo-nav-dark.png │ ├── logo-nav-light.png │ └── tools.svg ├── package.json ├── pages │ ├── 404.mdx │ ├── HeroSandbox │ │ ├── Title.js │ │ ├── data.js │ │ ├── hero.module.css │ │ └── index.js │ ├── docs │ │ ├── CodeSnippet.js │ │ ├── Video.js │ │ ├── changelog.mdx │ │ ├── code │ │ │ ├── Specs.js │ │ │ ├── examples.js │ │ │ ├── index.js │ │ │ ├── rug.js │ │ │ └── styles.module.css │ │ ├── examples.mdx │ │ ├── extras.mdx │ │ ├── faq.mdx │ │ ├── gestures.mdx │ │ ├── introduction.mdx │ │ ├── motivation.mdx │ │ ├── options.mdx │ │ ├── state.mdx │ │ ├── upgrading.mdx │ │ ├── utilities.mdx │ │ └── video.module.css │ ├── index.mdx │ └── partials │ │ └── shields.mdx ├── src │ └── smooth-doc │ │ ├── components │ │ ├── Code.js │ │ └── SiblingNav.js │ │ ├── styles.css │ │ └── theme.js └── static │ ├── equirectangular.png │ ├── piz_compressed.exr │ ├── studio.hdr │ └── videos │ ├── actionsheet.mp4 │ ├── cards.mp4 │ ├── draggable.mp4 │ ├── infinitescroll.mp4 │ ├── multi.mp4 │ ├── rocket.mp4 │ ├── simple.mp4 │ └── viewpager.mp4 ├── package.json ├── packages ├── core │ ├── CHANGELOG.md │ ├── actions │ │ └── package.json │ ├── package.json │ ├── src │ │ ├── Controller.ts │ │ ├── EventStore.ts │ │ ├── TimeoutStore.ts │ │ ├── actions.ts │ │ ├── config │ │ │ ├── commonConfigResolver.ts │ │ │ ├── coordinatesConfigResolver.ts │ │ │ ├── dragConfigResolver.ts │ │ │ ├── hoverConfigResolver.ts │ │ │ ├── moveConfigResolver.ts │ │ │ ├── pinchConfigResolver.ts │ │ │ ├── resolver.ts │ │ │ ├── scrollConfigResolver.ts │ │ │ ├── sharedConfigResolver.ts │ │ │ ├── support.ts │ │ │ └── wheelConfigResolver.ts │ │ ├── engines │ │ │ ├── CoordinatesEngine.ts │ │ │ ├── DragEngine.ts │ │ │ ├── Engine.ts │ │ │ ├── HoverEngine.ts │ │ │ ├── MoveEngine.ts │ │ │ ├── PinchEngine.ts │ │ │ ├── ScrollEngine.ts │ │ │ └── WheelEngine.ts │ │ ├── index.ts │ │ ├── parser.ts │ │ ├── types.ts │ │ ├── types │ │ │ ├── action.ts │ │ │ ├── config.ts │ │ │ ├── handlers.ts │ │ │ ├── index.ts │ │ │ ├── internalConfig.ts │ │ │ ├── state.ts │ │ │ └── utils.ts │ │ ├── utils.ts │ │ └── utils │ │ │ ├── events.ts │ │ │ ├── fn.ts │ │ │ ├── maths.ts │ │ │ └── state.ts │ ├── types │ │ └── package.json │ └── utils │ │ └── package.json ├── react │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ │ ├── createUseGesture.ts │ │ ├── index.ts │ │ ├── types.test.ts │ │ ├── types.ts │ │ ├── useDrag.ts │ │ ├── useGesture.ts │ │ ├── useHover.ts │ │ ├── useMove.ts │ │ ├── usePinch.ts │ │ ├── useRecognizers.ts │ │ ├── useScroll.ts │ │ └── useWheel.ts └── vanilla │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ └── src │ ├── DragGesture.ts │ ├── Gesture.ts │ ├── HoverGesture.ts │ ├── MoveGesture.ts │ ├── PinchGesture.ts │ ├── Recognizer.ts │ ├── ScrollGesture.ts │ ├── WheelGesture.ts │ ├── createGesture.ts │ ├── index.ts │ └── types.test.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── setupPointerEvent.js ├── test ├── api.test.tsx ├── components │ ├── Api.tsx │ ├── Common.tsx │ ├── Interactive.tsx │ ├── InteractiveDom.tsx │ └── types.ts ├── config.test.tsx ├── drag.test.tsx ├── global.d.ts ├── hover.test.tsx ├── move.test.tsx ├── pinch.test.tsx ├── scroll.test.tsx ├── utils.tsx └── wheel.test.tsx └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [["@use-gesture/*"]], 6 | "access": "public", 7 | "baseBranch": "main", 8 | "updateInternalDependencies": "patch", 9 | "ignore": ["demo", "documentation"] 10 | } 11 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "sandboxes": [ 4 | "/demo/src/sandboxes/gesture-drag", 5 | "/demo/src/sandboxes/gesture-drag-target", 6 | "/demo/src/sandboxes/gesture-nested", 7 | "/demo/src/sandboxes/gesture-drag-vanilla", 8 | "/demo/src/sandboxes/gesture-move", 9 | "/demo/src/sandboxes/gesture-pinch", 10 | "/demo/src/sandboxes/gesture-pinch-multiple", 11 | "/demo/src/sandboxes/gesture-three", 12 | "/demo/src/sandboxes/card-zoom", 13 | "/demo/src/sandboxes/viewpager" 14 | ], 15 | "node": "16" 16 | } 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .* 2 | dist/ 3 | node_modules/ 4 | public/ 5 | pnpm-lock.yaml -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["react-app", "prettier"], 3 | "plugins": ["testing-library", "jest-dom"], 4 | "rules": { 5 | "no-console": "warn", 6 | "default-case": "off", 7 | "@typescript-eslint/no-redeclare": "off" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: dbismut 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | > A clear and concise description of what the bug is. 12 | 13 | **Sandbox or Video** 14 | > If applicable, please provide a minimal reproduction sandbox on code sandbox. Or a video / screenshots that could help. 15 | 16 | **Information:** 17 | - Use Gesture version: [e.g. v10.2.10] 18 | - Device: [e.g. iPhone6] 19 | - OS: [e.g. iOS8.1] 20 | - Browser [e.g. stock browser, safari] 21 | 22 | **Checklist:** 23 | - [ ] I've read the [documentation](https://use-gesture.netlify.app/). 24 | - [ ] If this is an issue with drag, I've tried setting `touch-action: none` to the draggable element. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/pmndrs/use-gesture/discussions 5 | about: Ask questions and discuss with other community members 6 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - 'documentation/**' 8 | - '.github/workflows/documentation.yml' 9 | env: 10 | CI: true 11 | PNPM_CACHE_FOLDER: .pnpm-store 12 | jobs: 13 | publish_documentation: 14 | name: Publish documentation 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repo 19 | uses: actions/checkout@v4 20 | 21 | - name: Use Node 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: '18' 25 | 26 | - uses: pnpm/action-setup@v2 27 | with: 28 | version: 8 29 | run_install: true 30 | 31 | - name: Build documentation 32 | run: pnpm docs:build 33 | 34 | - name: Publish 35 | uses: netlify/actions/cli@master 36 | with: 37 | args: deploy --dir=documentation/public --prod 38 | env: 39 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 40 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 41 | NETLIFY_LIVE_URL: https://use-gesture.netlify.app/ 42 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | paths: 5 | - '.github/workflows/main.yml' 6 | - 'packages/**' 7 | - 'package.json' 8 | - 'pnpm-lock.yaml' 9 | - 'test/**' 10 | - '!documentation/**' 11 | - '!demo/**' 12 | - '!**.md' 13 | - '!.changeset/**' 14 | env: 15 | CI: true 16 | jobs: 17 | build: 18 | name: Build, lint, and test 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repo 23 | uses: actions/checkout@v4 24 | 25 | - name: Use Node 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: '18' 29 | 30 | - name: Cache pnpm modules 31 | uses: actions/cache@v3 32 | with: 33 | path: ~/.pnpm-store 34 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} 35 | restore-keys: | 36 | ${{ runner.os }}- 37 | 38 | - uses: pnpm/action-setup@v2 39 | with: 40 | version: 8 41 | run_install: | 42 | args: [--filter "@use-gesture/*"] 43 | 44 | - name: Check types 45 | run: pnpm tsc 46 | 47 | - name: Setup build cache 48 | uses: actions/cache@v3 49 | id: build-cache 50 | with: 51 | path: packages/**/dist 52 | key: ${{ runner.os }}-build-${{ hashFiles('packages/') }} 53 | restore-keys: | 54 | ${{ runner.os }}-build- 55 | 56 | - name: Build without cache 57 | if: steps.build-cache.outputs.cache-hit != 'true' 58 | run: pnpm build 59 | 60 | - name: Run tests 61 | run: pnpm test 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | .cache 5 | .rts2_cache_cjs 6 | .rts2_cache_esm 7 | .rts2_cache_umd 8 | dist 9 | 10 | # Local Netlify folder 11 | .netlify -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run lint && npm run tsc 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | /assets/ 4 | Thumbs.db 5 | ehthumbs.db 6 | Desktop.ini 7 | $RECYCLE.BIN/ 8 | .DS_Store -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .* 2 | dist/ 3 | node_modules/ 4 | public/ 5 | pnpm-lock.yaml -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "bracketSameLine": false 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-present Paul Henschel 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | comments: false, 3 | presets: [ 4 | [ 5 | '@babel/preset-env', 6 | { 7 | bugfixes: true, 8 | targets: { 9 | esmodules: true 10 | } 11 | } 12 | ], 13 | '@babel/preset-react', 14 | '@babel/preset-typescript' 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sandboxes Use Gesture 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite --port 4000 --host", 7 | "build": "tsc && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@leva-ui/plugin-spring": "*", 12 | "@react-spring/web": "^9.4.5", 13 | "@react-three/drei": "^9.8.1", 14 | "@react-three/fiber": "^8.0.15", 15 | "@use-gesture/react": "*", 16 | "@use-gesture/vanilla": "*", 17 | "leva": "*", 18 | "lodash-move": "^1.1.1", 19 | "lodash.clamp": "^4.0.3", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-use-measure": "^2.1.1", 23 | "screenlog": "^0.3.0", 24 | "three": "^0.140.2", 25 | "wouter": "^2.7.4" 26 | }, 27 | "devDependencies": { 28 | "@types/lodash.clamp": "^4.0.7", 29 | "@types/react": "^18.2.21", 30 | "@types/react-dom": "^18.2.7", 31 | "@types/three": "^0.140.0", 32 | "@vitejs/plugin-react": "^3.1.0", 33 | "typescript": "^5.2.2", 34 | "typescript-plugin-css-modules": "^5.0.1", 35 | "vite": "^4.4.9" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | margin: 0; 11 | } 12 | 13 | *, 14 | *:after, 15 | *:before { 16 | box-sizing: border-box; 17 | } 18 | 19 | .flex { 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .flex.fill { 25 | height: 100%; 26 | } 27 | 28 | .flex.center { 29 | justify-content: center; 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | // window.screenLog.init() 8 | 9 | const rootElement = document.getElementById('root') 10 | const root = createRoot(rootElement!) 11 | root.render( 12 | 13 | 14 | 15 | ) 16 | -------------------------------------------------------------------------------- /demo/src/sandboxes/action-sheet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "action-sheet", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/action-sheet/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/action-sheet/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/action-sheet/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/action-sheet/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .actionBtn { 2 | position: fixed; 3 | z-index: 100; 4 | bottom: 80px; 5 | right: 40px; 6 | height: 48px; 7 | width: 48px; 8 | border-radius: 24px; 9 | background: coral; 10 | box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.14), 11 | 0px 1px 18px 0px rgba(0, 0, 0, 0); 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | } 16 | 17 | .actionBtn:after { 18 | content: ' '; 19 | display: block; 20 | background: #fff; 21 | height: 20%; 22 | width: 20%; 23 | border-radius: 50%; 24 | } 25 | 26 | .bg { 27 | width: 100%; 28 | } 29 | 30 | .bg > img { 31 | width: 100%; 32 | margin: 0; 33 | display: block; 34 | } 35 | 36 | .sheet { 37 | z-index: 100; 38 | position: fixed; 39 | left: 2vw; 40 | height: calc(100vh + 100px); 41 | width: 96vw; 42 | border-radius: 12px 12px 0px; 43 | background: #fff; 44 | touch-action: none; 45 | } 46 | 47 | .sheet > div { 48 | height: 60px; 49 | border-bottom: 1px solid #eee; 50 | display: flex; 51 | align-items: center; 52 | justify-content: center; 53 | padding: 0 20px; 54 | text-transform: capitalize; 55 | } 56 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-card-zoom", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "devDependencies": { 13 | "@types/lodash-es": "^4.17.4", 14 | "@types/react": "^18.0.3", 15 | "@types/react-dom": "^18.0.0", 16 | "typescript": "^4.9.4", 17 | "typescript-plugin-css-modules": "^4.1.1" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test --env=jsdom", 23 | "eject": "react-scripts eject" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | background: indianred; 3 | } 4 | 5 | .card { 6 | position: relative; 7 | width: 300px; 8 | height: 300px; 9 | background: url(https://images.pexels.com/photos/1030963/pexels-photo-1030963.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500); 10 | background-size: cover; 11 | border-radius: 5px; 12 | box-shadow: 0px 10px 30px -5px rgba(0, 0, 0, 0.3); 13 | will-change: transform; 14 | border: 10px solid white; 15 | cursor: grab; 16 | touch-action: none; 17 | user-select: none; 18 | -webkit-user-select: none; 19 | overflow: hidden; 20 | display: flex; 21 | flex-direction: column; 22 | justify-content: center; 23 | align-items: center; 24 | font-weight: 500; 25 | font-size: 22px; 26 | padding: 20px; 27 | text-align: center; 28 | color: #ffffffaa; 29 | } 30 | -------------------------------------------------------------------------------- /demo/src/sandboxes/card-zoom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-cards-stack", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ], 24 | "devDependencies": { 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | background: lightblue; 3 | cursor: url('https://uploads.codesandbox.io/uploads/user/b3e56831-8b98-4fee-b941-0e27f39883ab/Ad1_-cursor.png') 39 39, 4 | auto; 5 | } 6 | 7 | .deck { 8 | position: absolute; 9 | width: 300px; 10 | height: 200px; 11 | will-change: transform; 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | touch-action: none; 16 | } 17 | 18 | .deck > div { 19 | touch-action: none; 20 | background-color: white; 21 | background-size: auto 85%; 22 | background-repeat: no-repeat; 23 | background-position: center center; 24 | width: 45vh; 25 | max-width: 300px; 26 | height: 85vh; 27 | max-height: 570px; 28 | will-change: transform; 29 | border-radius: 10px; 30 | box-shadow: 0 12.5px 100px -10px rgba(50, 50, 73, 0.4), 0 10px 10px -10px rgba(50, 50, 73, 0.3); 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/cards-stack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-dots-connect", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ], 24 | "devDependencies": { 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useRef } from 'react' 2 | import { useSpring, animated } from '@react-spring/web' 3 | import { useDrag } from '@use-gesture/react' 4 | 5 | import styles from './styles.module.css' 6 | 7 | export default function App() { 8 | const targetRef = useRef(null) 9 | const [{ x2, y2 }, api] = useSpring(() => ({ x2: 0, y2: 0 })) 10 | const [dragging, setDragging] = useState(false) 11 | const [attached, setAttached] = useState(false) 12 | 13 | const bind = useDrag(({ xy: [x, y], active, last, movement: [mx, my] }) => { 14 | setDragging(active) 15 | setAttached(document.elementFromPoint(x, y) === targetRef.current) 16 | if (last) { 17 | api.start({ x2: attached ? 300 : 0, y2: 0 }) 18 | } else { 19 | api.start({ x2: mx, y2: my, immediate: true }) 20 | } 21 | }) 22 | 23 | return ( 24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 | {attached 32 | ? dragging 33 | ? 'You can release the pointer' 34 | : 'Dots are connected!' 35 | : 'Connect the pink dot to the blue dot'} 36 |
37 |
38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .svg { 2 | position: relative; 3 | min-width: 328px; 4 | max-width: 328px; 5 | overflow: visible; 6 | touch-action: none; 7 | } 8 | 9 | .from { 10 | cursor: pointer; 11 | touch-action: none; 12 | } 13 | 14 | .status { 15 | position: absolute; 16 | font-size: 0.8em; 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/sandboxes/dots-connect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "draggable-image", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ], 24 | "devDependencies": { 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useSpring, animated } from '@react-spring/web' 2 | import { useDrag } from '@use-gesture/react' 3 | import styles from './styles.module.css' 4 | 5 | function Image() { 6 | const [props, api] = useSpring(() => ({ x: 0, y: 0, scale: 1 })) 7 | const bind = useDrag(({ event, active, movement: [x, y] }) => { 8 | event.preventDefault() 9 | api.start({ 10 | x: active ? x : 0, 11 | y: active ? y : 0, 12 | scale: active ? 1.2 : 1, 13 | immediate: (k) => k !== 'scale' && active 14 | }) 15 | }) 16 | return ( 17 | 23 | ) 24 | } 25 | 26 | function Link() { 27 | const [props, api] = useSpring(() => ({ x: 0, y: 0, scale: 1 })) 28 | const bind = useDrag( 29 | ({ active, offset: [x, y] }) => { 30 | api.start({ 31 | x, 32 | y, 33 | scale: active ? 1.2 : 1, 34 | immediate: (k) => k !== 'scale' && active 35 | }) 36 | }, 37 | { filterTaps: true, preventDefault: true } 38 | ) 39 | return ( 40 | 48 | This is a link 49 | 50 | ) 51 | } 52 | 53 | export default function App() { 54 | return ( 55 |
56 | 57 | 58 |
59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | touch-action: none; 3 | -moz-user-select: none; 4 | -webkit-user-drag: none; 5 | user-select: none; 6 | cursor: grab; 7 | } 8 | 9 | .img { 10 | width: 400px; 11 | height: 400px; 12 | background: hotpink; 13 | border-radius: 16px; 14 | } 15 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-image/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spring-draggable-list-scroll", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "lodash.clamp": "4.0.3", 9 | "lodash-move": "1.1.1", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ], 26 | "devDependencies": { 27 | "@types/lodash-es": "^4.17.4", 28 | "@types/react": "^18.0.3", 29 | "@types/react-dom": "^18.0.0", 30 | "typescript": "^4.9.4", 31 | "typescript-plugin-css-modules": "^4.1.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | margin: 0; 11 | } 12 | 13 | *, 14 | *:after, 15 | *:before { 16 | box-sizing: border-box; 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 100px 0; 3 | width: 320px; 4 | margin: 0 auto; 5 | } 6 | 7 | .content { 8 | width: 320px; 9 | } 10 | 11 | .content > div { 12 | position: absolute; 13 | width: 320px; 14 | height: 80px; 15 | transform-origin: 50% 50% 0px; 16 | border-radius: 5px; 17 | color: white; 18 | line-height: 40px; 19 | padding-left: 32px; 20 | font-size: 14.5px; 21 | background: lightblue; 22 | text-transform: uppercase; 23 | letter-spacing: 2px; 24 | touch-action: pan-y; 25 | -webkit-user-drag: none; 26 | -webkit-user-select: none; 27 | user-select: none; 28 | } 29 | 30 | .content > div:nth-child(1) { 31 | background: linear-gradient(135deg, #f6d365 0%, #fda085 100%); 32 | } 33 | .content > div:nth-child(2) { 34 | background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); 35 | } 36 | .content > div:nth-child(3) { 37 | background: linear-gradient(135deg, #5ee7df 0%, #b490ca 100%); 38 | } 39 | .content > div:nth-child(4) { 40 | background: linear-gradient(135deg, #c3cfe2 0%, #c3cfe2 100%); 41 | } 42 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'lodash-move' { 2 | const fn: (list: number[], b: number, c: number) => number[] 3 | export default fn 4 | } 5 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list-prevent-scroll/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spring-draggable-list", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "lodash.clamp": "4.0.3", 9 | "lodash-move": "1.1.1", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ], 26 | "devDependencies": { 27 | "@types/lodash.clamp": "^4.0.6", 28 | "@types/lodash-es": "^4.17.4", 29 | "@types/react": "^18.0.3", 30 | "@types/react-dom": "^18.0.0", 31 | "typescript": "^4.9.4", 32 | "typescript-plugin-css-modules": "^4.1.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .content { 2 | width: 320px; 3 | } 4 | 5 | .content > div { 6 | position: absolute; 7 | width: 320px; 8 | height: 80px; 9 | transform-origin: 50% 50% 0px; 10 | border-radius: 5px; 11 | color: white; 12 | line-height: 40px; 13 | padding-left: 32px; 14 | font-size: 14.5px; 15 | background: lightblue; 16 | text-transform: uppercase; 17 | letter-spacing: 2px; 18 | touch-action: none; 19 | } 20 | 21 | .content > div:nth-child(1) { 22 | background: linear-gradient(135deg, #f6d365 0%, #fda085 100%); 23 | } 24 | .content > div:nth-child(2) { 25 | background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); 26 | } 27 | .content > div:nth-child(3) { 28 | background: linear-gradient(135deg, #5ee7df 0%, #b490ca 100%); 29 | } 30 | .content > div:nth-child(4) { 31 | background: linear-gradient(135deg, #c3cfe2 0%, #c3cfe2 100%); 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'lodash-move' { 2 | const fn: (list: number[], b: number, c: number) => number[] 3 | export default fn 4 | } 5 | -------------------------------------------------------------------------------- /demo/src/sandboxes/draggable-list/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-target/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-drag-target", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-target/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-target/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-target/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-target/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-drag-vanilla", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/vanilla": "*", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ], 26 | "devDependencies": { 27 | "@types/lodash-es": "^4.17.4", 28 | "@types/react": "^18.0.3", 29 | "@types/react-dom": "^18.0.0", 30 | "typescript": "^4.9.4", 31 | "typescript-plugin-css-modules": "^4.1.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag-vanilla/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-drag", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-drag/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-move", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ], 24 | "devDependencies": { 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react' 2 | import { useGesture } from '@use-gesture/react' 3 | import { a, useSpring } from '@react-spring/web' 4 | 5 | import styles from './styles.module.css' 6 | 7 | const data: [string, [number, number]][] = [ 8 | ['steelblue', [0.5, 1]], 9 | ['hotpink', [1, 0.8]], 10 | ['coral', [1, 1]] 11 | ] 12 | 13 | export default function App() { 14 | const hovering = useRef(false) 15 | const [props, api] = useSpring(() => ({ 16 | x: 0, 17 | y: 0, 18 | backgroundColor: '#ffffff00', 19 | opacity: 1, 20 | scale: [1, 1] 21 | })) 22 | 23 | const bind = useGesture({ 24 | onMove: ({ xy: [x, y] }) => api.start({ x, y }), 25 | onHover: ({ active, xy: [x, y], args: [backgroundColor, scale] }) => { 26 | if (active) { 27 | if (!hovering.current) { 28 | props.x.set(x) 29 | props.y.set(y) 30 | } 31 | hovering.current = true 32 | api.start({ opacity: 1, backgroundColor, scale }) 33 | } else api.start({ opacity: 0, onRest: () => (hovering.current = false) }) 34 | } 35 | }) 36 | 37 | return ( 38 |
39 | {/* @ts-ignore */} 40 | 41 | {data.map(([color, scale], i) => ( 42 | 43 | This link is {color} 44 | 45 | ))} 46 |
47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | flex-direction: column; 3 | font-size: 20px; 4 | background-color: antiquewhite; 5 | } 6 | 7 | .container a { 8 | color: palevioletred; 9 | position: relative; 10 | text-decoration: none; 11 | padding: 10px 0; 12 | font-weight: bold; 13 | } 14 | 15 | .container > div { 16 | top: 0; 17 | left: 0; 18 | position: fixed; 19 | width: 180px; 20 | height: 120px; 21 | pointer-events: none; 22 | transform-origin: top left; 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-move/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-nested/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-nested", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-nested/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-nested/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-nested/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-nested/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | cursor: grab; 28 | touch-action: none; 29 | display: flex; 30 | align-items: center; 31 | justify-content: center; 32 | height: 200px; 33 | width: 200px; 34 | background-color: royalblue; 35 | } 36 | 37 | .hover:hover { 38 | background-color: darkblue; 39 | } 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-multiple-pinch", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { useGesture } from '@use-gesture/react' 3 | import { a, useSpring } from '@react-spring/web' 4 | 5 | import styles from './styles.module.css' 6 | 7 | export default function Two() { 8 | useEffect(() => { 9 | const handler = (e) => e.preventDefault() 10 | document.addEventListener('gesturestart', handler) 11 | document.addEventListener('gesturechange', handler) 12 | document.addEventListener('gestureend', handler) 13 | return () => { 14 | document.removeEventListener('gesturestart', handler) 15 | document.removeEventListener('gesturechange', handler) 16 | document.removeEventListener('gestureend', handler) 17 | } 18 | }, []) 19 | 20 | const [style1, api1] = useSpring(() => ({ x: 0, y: 0, scale: 1, rotate: 0 })) 21 | const [style2, api2] = useSpring(() => ({ x: 0, y: 0, scale: 1, rotate: 0 })) 22 | 23 | const bind1 = useGesture({ 24 | onDrag: ({ offset: [x, y] }) => { 25 | api1.start({ x, y }) 26 | }, 27 | onPinch: ({ offset: [s, a] }) => { 28 | api1.start({ scale: s, rotate: a }) 29 | } 30 | }) 31 | 32 | const bind2 = useGesture({ 33 | onDrag: ({ offset: [x, y] }) => { 34 | api2.start({ x, y }) 35 | }, 36 | onPinch: ({ offset: [s, a] }) => { 37 | api2.start({ scale: s, rotate: a }) 38 | } 39 | }) 40 | 41 | return ( 42 |
43 | 44 | 45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch-multiple/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | height: 150px; 3 | width: 150px; 4 | margin: 10px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-pinch", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "leva": "*", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "^5.0.1" 13 | }, 14 | "scripts": { 15 | "start": "react-scripts start", 16 | "build": "react-scripts build", 17 | "test": "react-scripts test --env=jsdom", 18 | "eject": "react-scripts eject" 19 | }, 20 | "browserslist": [ 21 | ">0.2%", 22 | "not dead", 23 | "not ie <= 11", 24 | "not op_mini all" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-pinch/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 300px; 4 | width: 300px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | display: grid; 11 | padding: 50px; 12 | grid-gap: 10px; 13 | font-family: monospace; 14 | } 15 | 16 | .drag div { 17 | display: flex; 18 | align-items: center; 19 | justify-content: center; 20 | } 21 | 22 | .drag > div { 23 | flex: 1; 24 | background-color: #000; 25 | color: #fff; 26 | padding: 30px; 27 | } 28 | 29 | .drag > div > div { 30 | padding: 20px; 31 | background: orange; 32 | flex: 1; 33 | height: 100%; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-scroll", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useScroll } from '@use-gesture/react' 3 | 4 | export default function App() { 5 | const [scroll, setScroll] = useState({ direction: 0, delta: 0, movement: 0, offset: 0 }) 6 | const target = React.useRef() 7 | useScroll( 8 | ({ direction, delta, movement, offset }) => { 9 | setScroll({ direction, delta, movement, offset }) 10 | }, 11 | { target, eventOptions: { capture: true } } 12 | ) 13 | 14 | return ( 15 |
16 |
{JSON.stringify(scroll, null, '  ')}
17 |
18 |
19 |
20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-scroll/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-simplest", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/react": "latest", 9 | "react": "^18.1.0", 10 | "react-dom": "^18.1.0", 11 | "react-scripts": "^5.0.1" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | }, 19 | "browserslist": [ 20 | ">0.2%", 21 | "not dead", 22 | "not ie <= 11", 23 | "not op_mini all" 24 | ], 25 | "devDependencies": { 26 | "@types/lodash-es": "^4.17.4", 27 | "@types/react": "^18.0.3", 28 | "@types/react-dom": "^18.0.0", 29 | "typescript": "^4.9.4", 30 | "typescript-plugin-css-modules": "^4.1.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useDrag } from '@use-gesture/react' 2 | import { a, useSpring } from '@react-spring/web' 3 | 4 | import styles from './styles.module.css' 5 | 6 | export default function App() { 7 | const [style, api] = useSpring(() => ({ x: 0, y: 0, scale: 1 })) 8 | const bind = useDrag(({ active, movement: [x, y] }) => { 9 | api.start({ 10 | x: active ? x : 0, 11 | y: active ? y : 0, 12 | scale: active ? 1.2 : 1 13 | }) 14 | }) 15 | 16 | return ( 17 |
18 | 19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | background-color: #ecede7; 13 | } 14 | 15 | *, 16 | *:after, 17 | *:before { 18 | box-sizing: border-box; 19 | } 20 | 21 | .flex { 22 | display: flex; 23 | align-items: center; 24 | } 25 | 26 | .flex.fill { 27 | height: 100%; 28 | } 29 | 30 | .flex.center { 31 | justify-content: center; 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 80px; 4 | width: 80px; 5 | border-radius: 8px; 6 | background-color: hotpink; 7 | cursor: grab; 8 | touch-action: none; 9 | -webkit-user-select: none; 10 | user-select: none; 11 | font-size: 10px; 12 | } 13 | 14 | .drag:focus { 15 | border: 2px solid red; 16 | } 17 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-simplest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three-prevent-scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-three-prevent-scroll", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-three/drei": "^7.6.0", 8 | "@react-three/fiber": "^7.0.6", 9 | "@use-gesture/react": "latest", 10 | "leva": "*", 11 | "react": "^18.1.0", 12 | "react-dom": "^18.1.0", 13 | "react-scripts": "^5.0.1", 14 | "three": "^0.132.2" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test --env=jsdom", 20 | "eject": "react-scripts eject" 21 | }, 22 | "browserslist": [ 23 | ">0.2%", 24 | "not dead", 25 | "not ie <= 11", 26 | "not op_mini all" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three-prevent-scroll/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three-prevent-scroll/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three-prevent-scroll/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three-prevent-scroll/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .canvas { 2 | -webkit-user-drag: none; 3 | -webkit-user-select: none; 4 | user-select: none; 5 | } 6 | .canvas > canvas { 7 | touch-action: pan-y; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | } 11 | 12 | .three { 13 | background-color: #272727; 14 | height: 400px; 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-three", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-three/drei": "^7.6.0", 8 | "@react-three/fiber": "^7.0.6", 9 | "@use-gesture/react": "latest", 10 | "leva": "*", 11 | "react": "^18.1.0", 12 | "react-dom": "^18.1.0", 13 | "react-scripts": "^5.0.1", 14 | "three": "^0.132.2" 15 | }, 16 | "devDependencies": { 17 | "@types/lodash.clamp": "^4.0.6", 18 | "@types/lodash-es": "^4.17.4", 19 | "@types/react": "^18.0.3", 20 | "@types/react-dom": "^18.0.0", 21 | "@types/three": "^0.131.0", 22 | "typescript": "^4.9.4", 23 | "typescript-plugin-css-modules": "^4.1.1" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "react-scripts build", 28 | "test": "react-scripts test --env=jsdom", 29 | "eject": "react-scripts eject" 30 | }, 31 | "browserslist": [ 32 | ">0.2%", 33 | "not dead", 34 | "not ie <= 11", 35 | "not op_mini all" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .canvas > canvas { 2 | touch-action: none; 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-three/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-vanilla", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@leva-ui/plugin-spring": "*", 7 | "@react-spring/web": "^9.4.5", 8 | "@use-gesture/vanilla": "*", 9 | "react": "^18.1.0", 10 | "react-dom": "^18.1.0", 11 | "react-scripts": "^5.0.1" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test --env=jsdom", 17 | "eject": "react-scripts eject" 18 | }, 19 | "browserslist": [ 20 | ">0.2%", 21 | "not dead", 22 | "not ie <= 11", 23 | "not op_mini all" 24 | ], 25 | "devDependencies": { 26 | "@types/lodash-es": "^4.17.4", 27 | "@types/react": "^18.0.3", 28 | "@types/react-dom": "^18.0.0", 29 | "typescript": "^4.9.4", 30 | "typescript-plugin-css-modules": "^4.1.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { Gesture } from '@use-gesture/vanilla' 3 | 4 | export default function App() { 5 | const [wheel, setWheel] = useState({ direction: [0, 0], delta: [0, 0], _movement: [0, 0], offset: [0, 0] }) 6 | useEffect(() => { 7 | const gesture = new Gesture( 8 | window, 9 | { 10 | onWheel: ({ event, direction, delta, _movement, offset }) => { 11 | event.preventDefault() 12 | setWheel({ direction, delta, _movement, offset }) 13 | } 14 | }, 15 | { 16 | eventOptions: { passive: false } 17 | } 18 | ) 19 | return () => gesture.destroy() 20 | }, []) 21 | 22 | return ( 23 |
24 |
{JSON.stringify(wheel, null, '  ')}
25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-vanilla/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-wheel", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@use-gesture/react": "latest", 7 | "react": "^18.1.0", 8 | "react-dom": "^18.1.0", 9 | "react-scripts": "^5.0.1" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | }, 17 | "browserslist": [ 18 | ">0.2%", 19 | "not dead", 20 | "not ie <= 11", 21 | "not op_mini all" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useWheel } from '@use-gesture/react' 3 | 4 | export default function App() { 5 | const [wheel, setWheel] = useState({ direction: [0, 0], delta: [0, 0], _movement: [0, 0], offset: [0, 0] }) 6 | useWheel( 7 | ({ direction, delta, _movement, offset }) => { 8 | setWheel({ direction, delta, _movement, offset }) 9 | }, 10 | { 11 | target: window, 12 | bounds: { top: -500, bottom: 500 } 13 | // rubberband: true 14 | } 15 | ) 16 | 17 | return ( 18 |
19 |
{JSON.stringify(wheel, null, '  ')}
20 |
21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/gesture-wheel/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 120px; 4 | width: 120px; 5 | background-color: #ec625c; 6 | cursor: grab; 7 | touch-action: none; 8 | -webkit-user-select: none; 9 | user-select: none; 10 | font-size: 10px; 11 | } 12 | 13 | .drag > div { 14 | margin: 10%; 15 | width: 80%; 16 | height: 80%; 17 | background-color: #000; 18 | color: #fff; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-family: monospace; 24 | } 25 | 26 | .hover { 27 | height: 200px; 28 | width: 200px; 29 | background-color: royalblue; 30 | } 31 | 32 | .hover:hover { 33 | background-color: darkblue; 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-infinite-slideshow", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { a } from '@react-spring/web' 3 | import { Slider } from './Slider' 4 | import { items } from './items' 5 | 6 | import styles from './styles.module.css' 7 | 8 | export default function App() { 9 | return ( 10 |
11 |
12 | 13 | {({ css }, i) => ( 14 |
15 |
{String(i).padStart(2, '0')}
16 | 17 |
18 | )} 19 |
20 |
21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/infinite-slideshow/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | background: #171720; 3 | } 4 | 5 | .main { 6 | height: 400px; 7 | width: 100%; 8 | } 9 | 10 | .content { 11 | width: 100%; 12 | height: 100%; 13 | padding: 70px 100px; 14 | } 15 | 16 | .marker { 17 | color: white; 18 | position: absolute; 19 | top: 0px; 20 | left: 140px; 21 | font-family: monospace; 22 | } 23 | 24 | .image { 25 | width: 100%; 26 | height: 100%; 27 | background-size: cover; 28 | background-position: center center; 29 | } 30 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-vs-lib", 3 | "version": "1.0.0", 4 | "main": "src/index.jsx", 5 | "dependencies": { 6 | "@use-gesture/react": "latest", 7 | "react": "^18.1.0", 8 | "react-dom": "^18.1.0", 9 | "react-scripts": "^5.0.1" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | }, 17 | "browserslist": [ 18 | ">0.2%", 19 | "not dead", 20 | "not ie <= 11", 21 | "not op_mini all" 22 | ], 23 | "devDependencies": { 24 | "@types/lodash-es": "^4.17.4", 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | background-color: #ecede7; 13 | } 14 | 15 | *, 16 | *:after, 17 | *:before { 18 | box-sizing: border-box; 19 | } 20 | 21 | .flex { 22 | display: flex; 23 | align-items: center; 24 | } 25 | 26 | .flex.fill { 27 | height: 100%; 28 | } 29 | 30 | .flex.center { 31 | justify-content: center; 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | 5 | import './index.css' 6 | 7 | const rootElement = document.getElementById('root') 8 | const root = createRoot(rootElement!) 9 | root.render( 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .drag { 2 | position: absolute; 3 | height: 80px; 4 | width: 80px; 5 | border-radius: 8px; 6 | background-color: hotpink; 7 | cursor: grab; 8 | touch-action: none; 9 | -webkit-user-select: none; 10 | user-select: none; 11 | font-size: 10px; 12 | } 13 | 14 | .drag:focus { 15 | border: 2px solid red; 16 | } 17 | -------------------------------------------------------------------------------- /demo/src/sandboxes/native-vs-lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-slide", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "react": "^18.1.0", 9 | "react-dom": "^18.1.0", 10 | "react-scripts": "^5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test --env=jsdom", 16 | "eject": "react-scripts eject" 17 | }, 18 | "browserslist": [ 19 | ">0.2%", 20 | "not dead", 21 | "not ie <= 11", 22 | "not op_mini all" 23 | ], 24 | "devDependencies": { 25 | "@types/react": "^18.0.3", 26 | "@types/react-dom": "^18.0.0", 27 | "typescript": "^4.9.4", 28 | "typescript-plugin-css-modules": "^4.1.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useSpring, animated } from '@react-spring/web' 2 | import { useDrag } from '@use-gesture/react' 3 | 4 | import styles from './styles.module.css' 5 | 6 | const left = { 7 | bg: `linear-gradient(120deg, #f093fb 0%, #f5576c 100%)`, 8 | justifySelf: 'end', 9 | } 10 | const right = { 11 | bg: `linear-gradient(120deg, #96fbc4 0%, #f9f586 100%)`, 12 | justifySelf: 'start', 13 | } 14 | 15 | const Slider = ({ children }: { children: string }) => { 16 | const [{ x, bg, scale, justifySelf }, api] = useSpring(() => ({ 17 | x: 0, 18 | scale: 1, 19 | ...left, 20 | })) 21 | const bind = useDrag(({ active, movement: [x] }) => 22 | api.start({ 23 | x: active ? x : 0, 24 | scale: active ? 1.1 : 1, 25 | ...(x < 0 ? left : right), 26 | immediate: name => active && name === 'x', 27 | }) 28 | ) 29 | 30 | const avSize = x.to({ 31 | map: Math.abs, 32 | range: [50, 300], 33 | output: [0.5, 1], 34 | extrapolate: 'clamp', 35 | }) 36 | 37 | return ( 38 | 39 | 40 | 41 | {children} 42 | 43 | 44 | ) 45 | } 46 | 47 | export default function App() { 48 | return ( 49 |
50 | Slide. 51 |
52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .item { 2 | position: relative; 3 | width: 300px; 4 | height: 100px; 5 | pointer-events: auto; 6 | transform-origin: 50% 50% 0px; 7 | padding-left: 32px; 8 | padding-right: 32px; 9 | box-sizing: border-box; 10 | display: grid; 11 | align-items: center; 12 | text-align: center; 13 | border-radius: 5px; 14 | box-shadow: 0px 10px 10px -5px rgba(0, 0, 0, 0.2); 15 | touch-action: none; 16 | -webkit-user-select: none; 17 | user-select: none; 18 | } 19 | 20 | .fg { 21 | cursor: -webkit-grab; 22 | background-color: #272727; 23 | color: rgba(255, 255, 255, 0.8); 24 | position: absolute; 25 | height: 100%; 26 | width: 100%; 27 | display: grid; 28 | align-items: center; 29 | text-align: center; 30 | border-radius: 5px; 31 | box-shadow: 0px 10px 30px -5px rgba(0, 0, 0, 0.2); 32 | font-size: 3em; 33 | 34 | font-weight: 600; 35 | transition: box-shadow 0.75s; 36 | } 37 | 38 | .fg:active { 39 | cursor: -webkit-grabbing; 40 | box-shadow: 0px 15px 30px -5px rgba(0, 0, 0, 0.4); 41 | } 42 | 43 | .fg > * { 44 | pointer-events: none; 45 | } 46 | 47 | .av { 48 | width: 60px; 49 | height: 60px; 50 | border-radius: 50%; 51 | background-color: white; 52 | } 53 | -------------------------------------------------------------------------------- /demo/src/sandboxes/slide/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "printWidth": 120, 5 | "semi": false, 6 | "singleQuote": true, 7 | "tabWidth": 2, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gesture-viewpager", 3 | "version": "1.0.0", 4 | "main": "src/index.tsx", 5 | "dependencies": { 6 | "@react-spring/web": "^9.4.5", 7 | "@use-gesture/react": "latest", 8 | "lodash-es": "4.17.15", 9 | "lodash-move": "1.1.1", 10 | "lodash.clamp": "4.0.3", 11 | "react": "^18.1.0", 12 | "react-dom": "^18.1.0", 13 | "react-scripts": "^5.0.1" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test --env=jsdom", 19 | "eject": "react-scripts eject" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ], 27 | "devDependencies": { 28 | "@types/lodash.clamp": "^4.0.6", 29 | "@types/lodash-es": "^4.17.4", 30 | "@types/react": "^18.0.3", 31 | "@types/react-dom": "^18.0.0", 32 | "typescript": "^4.9.4", 33 | "typescript-plugin-css-modules": "^4.1.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | Use-Gesture Sandbox 23 | 24 | 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | body { 9 | font-family: system-ui, sans-serif; 10 | min-height: 100vh; 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:after, 16 | *:before { 17 | box-sizing: border-box; 18 | } 19 | 20 | .flex { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .flex.fill { 26 | height: 100%; 27 | } 28 | 29 | .flex.center { 30 | justify-content: center; 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | const root = createRoot(rootElement!) 8 | root.render( 9 | 10 | 11 | 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | touch-action: none; 6 | } 7 | 8 | .page > div { 9 | touch-action: none; 10 | background-size: cover; 11 | background-repeat: no-repeat; 12 | background-position: center center; 13 | width: 100%; 14 | height: 100%; 15 | box-shadow: 0 62.5px 125px -25px rgba(50, 50, 73, 0.5), 0 37.5px 75px -37.5px rgba(0, 0, 0, 0.6); 16 | } 17 | 18 | .wrapper { 19 | position: relative; 20 | width: 100%; 21 | height: 100%; 22 | overflow: hidden; 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/sandboxes/viewpager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "lib": ["dom", "es2015"], 7 | "plugins": [{ "name": "typescript-plugin-css-modules" }], 8 | "jsx": "react-jsx" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/styles.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | margin: 0 auto; 3 | max-width: 720px; 4 | padding: 20px 16px 0; 5 | min-height: 100vh; 6 | } 7 | 8 | .back { 9 | position: fixed; 10 | left: 10px; 11 | bottom: 10px; 12 | z-index: 100; 13 | padding: 10px; 14 | background: #000; 15 | color: #fff; 16 | font-weight: 500; 17 | font-size: 14px; 18 | text-decoration: none; 19 | border-radius: 2px; 20 | border: 1px solid #333; 21 | } 22 | 23 | .link { 24 | color: inherit; 25 | } 26 | 27 | .linkList { 28 | display: grid; 29 | gap: 10px; 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/vite.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "plugins": [{ "name": "typescript-plugin-css-modules" }] 19 | }, 20 | "include": ["src"], 21 | "references": [{ "path": "./tsconfig.node.json" }] 22 | } 23 | -------------------------------------------------------------------------------- /demo/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /demo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | -------------------------------------------------------------------------------- /documentation/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | public 3 | node_modules 4 | -------------------------------------------------------------------------------- /documentation/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Greg Bergé 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /documentation/README.md: -------------------------------------------------------------------------------- 1 | # [Use-gesture website](https://use-gesture.netlify.app/) 2 | -------------------------------------------------------------------------------- /documentation/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { State } from 'mdx-observable' 3 | 4 | export const wrapRootElement = ({ element }) => { 5 | return {element} 6 | } 7 | -------------------------------------------------------------------------------- /documentation/gatsby-config.js: -------------------------------------------------------------------------------- 1 | const title = '@use-gesture documentation' 2 | const description = `@use-gesture allows you to implement advanced UI interactions with just a few lines of code.` 3 | 4 | module.exports = { 5 | siteMetadata: { 6 | title, 7 | description 8 | }, 9 | plugins: [ 10 | { 11 | resolve: 'gatsby-plugin-pnpm', 12 | options: { 13 | include: ['smooth-doc'] 14 | } 15 | }, 16 | { 17 | resolve: 'smooth-doc', 18 | options: { 19 | name: title, 20 | siteUrl: 'https://use-gesture.netlify.app', 21 | description, 22 | author: 'David Bismut', 23 | sections: ['About', 'Reference', 'More'], 24 | navItems: [ 25 | { title: 'Docs', url: '/docs/' }, 26 | { title: 'API', url: '/docs/gestures/' } 27 | ], 28 | docSearch: { 29 | apiKey: '03ac4140f84a905c678b2501a118eb94', 30 | appId: '1UFCYC8N2G', 31 | indexName: 'use-gesture' 32 | }, 33 | twitterAccount: 'pmndrs', 34 | githubRepositoryURL: 'https://github.com/pmndrs/use-gesture', 35 | carbonAdsURL: '//cdn.carbonads.com/carbon.js?serve=CEAI42QM&placement=use-gesturenetlifyapp' 36 | } 37 | }, 38 | 39 | { 40 | resolve: `gatsby-plugin-google-analytics`, 41 | options: { 42 | trackingId: 'UA-162749258-1' 43 | } 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /documentation/images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/images/404.png -------------------------------------------------------------------------------- /documentation/images/logo-manifest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/images/logo-manifest.png -------------------------------------------------------------------------------- /documentation/images/logo-nav-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/images/logo-nav-dark.png -------------------------------------------------------------------------------- /documentation/images/logo-nav-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/images/logo-nav-light.png -------------------------------------------------------------------------------- /documentation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "documentation", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "gatsby develop -H 0.0.0.0", 7 | "build": "gatsby build", 8 | "clean": "gatsby clean", 9 | "serve": "gatsby serve" 10 | }, 11 | "dependencies": { 12 | "@reach/tabs": "^0.16.4", 13 | "@react-spring/three": "^9.4.5", 14 | "@react-spring/web": "^9.4.5", 15 | "@react-three/drei": "^9.8.1", 16 | "@react-three/fiber": "^8.0.15", 17 | "@use-gesture/react": "*", 18 | "@use-gesture/vanilla": "*", 19 | "animejs": "^3.2.1", 20 | "classnames": "^2.3.2", 21 | "gatsby": "4.12.1", 22 | "gatsby-plugin-google-analytics": "^4.24.0", 23 | "gatsby-plugin-pnpm": "^1.2.10", 24 | "lethargy": "^1.0.9", 25 | "leva": "^0.9.35", 26 | "mdx-observable": "^0.2.0", 27 | "parse-numeric-range": "^1.3.0", 28 | "react": "^18.2.0", 29 | "react-dom": "^18.2.0", 30 | "react-player": "^2.10.0", 31 | "react-toastify": "^8.1.0", 32 | "smooth-doc": "^8.1.0", 33 | "three": "^0.140.2" 34 | }, 35 | "devDependencies": { 36 | "eslint-plugin-flowtype": "^5.2.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /documentation/pages/404.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page not found 3 | --- 4 | 5 | import { x } from '@xstyled/styled-components' 6 | import { Article, ScreenContainer, Button } from 'smooth-doc/components' 7 | import { Link } from 'gatsby' 8 | import notFoundImageURL from '../images/404.png' 9 | 10 | The page you are looking for does not actually exist. 11 | 12 |
13 | 14 | That's an empty page! 15 | 16 | 17 |
18 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /documentation/pages/HeroSandbox/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { HeroTitle as HT } from 'smooth-doc/components' 3 | import styled from '@xstyled/styled-components' 4 | import { useMove } from '@use-gesture/react' 5 | import { useSpring, animated } from '@react-spring/web' 6 | 7 | const HeroTitle = animated(styled(HT)` 8 | color: red; 9 | background: linear-gradient(45deg, #ff9800 0%, #ffeb3b 50%, #ff9800 100%); 10 | background-size: 200% auto; 11 | 12 | color: #000; 13 | background-clip: text; 14 | text-fill-color: transparent; 15 | -webkit-background-clip: text; 16 | -webkit-text-fill-color: transparent; 17 | `) 18 | 19 | export default function Title({ children }) { 20 | const [{ x }, api] = useSpring(() => ({ x: 0 })) 21 | useMove(({ xy: [x, y] }) => api.start({ x: x / window.innerWidth }), { 22 | target: typeof window === 'object' ? window : null 23 | }) 24 | 25 | return {children} 26 | } 27 | -------------------------------------------------------------------------------- /documentation/pages/HeroSandbox/data.js: -------------------------------------------------------------------------------- 1 | import { folder } from 'leva' 2 | 3 | export const tweaks = { 4 | Movement: folder({ 5 | axis: { value: undefined, options: { 'x axis': 'x', 'y axis': 'y', lock: 'lock' } }, 6 | threshold: { value: 0, min: 0, max: 100, step: 1 } 7 | }), 8 | activateBounds: { value: false, label: 'activate bounds' }, 9 | rubberband: { value: 0.15, min: 0, max: 3, render: (get) => get('activateBounds') }, 10 | Bounds: folder( 11 | { 12 | vertical: { value: [-100, 100], min: -200, max: 200, step: 1 }, 13 | horizontal: { value: [-100, 100], min: -200, max: 200, step: 1 } 14 | }, 15 | { render: (get) => get('activateBounds') } 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /documentation/pages/docs/CodeSnippet.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Tabs, TabList as Tlist, Tab as T, TabPanels, TabPanel as Tpanel } from '@reach/tabs' 3 | import { Observe } from 'mdx-observable' 4 | import styled from '@xstyled/styled-components' 5 | import { Article } from 'smooth-doc/components' 6 | 7 | import '@reach/tabs/styles.css' 8 | 9 | export function TabPanel({ as = Article, ...props }) { 10 | return 11 | } 12 | 13 | const TabList = styled(Tlist)` 14 | background: transparent; 15 | font-weight: bold; 16 | ` 17 | 18 | const Tab = styled(T)` 19 | padding: 1rem; 20 | border-width: 3px; 21 | &:focus { 22 | outline: none; 23 | } 24 | &[data-selected] { 25 | color: on-background-primary; 26 | border-color: on-background-primary; 27 | } 28 | ` 29 | 30 | export function CodeSnippet({ children }) { 31 | return ( 32 | 33 | {({ setState, ...state }) => ( 34 | setState({ activeTabIndex: newIndex })}> 35 | 36 | React 37 | Vanilla JS 38 | 39 | {children} 40 | 41 | )} 42 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /documentation/pages/docs/Video.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | 4 | import * as styles from './video.module.css' 5 | 6 | const links = { 7 | drag: { label: 'drag', link: 'gestures' }, 8 | wheel: { label: 'wheel', link: 'gestures' }, 9 | pinch: { label: 'pinch', link: 'gestures' }, 10 | move: { label: 'move', link: 'gestures' }, 11 | initial: { label: 'initial', link: 'options/#initial' }, 12 | rubberband: { label: 'rubberband', link: 'options/#rubberband' }, 13 | touchaction: { label: 'touch-action', link: 'extras/#touch-action' } 14 | } 15 | 16 | const Video = ({ video, id, badges }) => { 17 | return ( 18 |
19 | 24 | 27 | 28 | {badges && ( 29 |
30 | {badges.map((b, i) => ( 31 | 32 | {links[b].label} 33 | 34 | ))} 35 |
36 | )} 37 |
38 | ) 39 | } 40 | 41 | export default Video 42 | -------------------------------------------------------------------------------- /documentation/pages/docs/code/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef } from 'react' 2 | import cn from 'classnames' 3 | import * as Examples from './examples' 4 | import * as styles from './styles.module.css' 5 | 6 | export default function Example({ id, disableOverlay }) { 7 | const Component = Examples[id] 8 | const ref = useRef() 9 | const [active, setActive] = useState(false) 10 | 11 | React.useLayoutEffect(() => { 12 | document.body.classList.toggle('dragged', active) 13 | }, [active]) 14 | 15 | return ( 16 | <> 17 | {!disableOverlay &&
} 18 |
19 | 20 |
21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /documentation/pages/docs/code/rug.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { EasterDiv } from './examples' 3 | 4 | const handMojis = ['👆', '👇', '👈', '🤘', '🤙', '✊', '🖖', '🖐', '🤞', '👍', '👊'] 5 | const randomEmoji = () => handMojis[Math.floor(Math.random() * handMojis.length)] 6 | 7 | export default function Rug({ pkg }) { 8 | const [emoji, setEmoji] = React.useState(handMojis[0]) 9 | 10 | useEffect(() => setEmoji(randomEmoji()), []) 11 | 12 | return ( 13 | 14 | 15 | {emoji} @use-gesture 16 | {pkg && `/${pkg}`} 17 | 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /documentation/pages/docs/examples.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Examples 3 | section: More 4 | order: 1 5 | --- 6 | 7 | # Examples 8 | 9 | Click on the examples below to open them on codesandbox. 10 | 11 | 12 | 13 | import Video from './Video' 14 | import * as styles from './video.module.css' 15 | 16 |
17 |
28 | -------------------------------------------------------------------------------- /documentation/pages/docs/upgrading.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrading to @use-gesture 3 | section: More 4 | order: 4 5 | --- 6 | 7 | import UseGesture from './code/rug' 8 | 9 | # Upgrading to @use-gesture/react 10 | 11 | How to switch from `react-use-gesture` to 12 | 13 | ## Transition 14 | 15 | `react-use-gesture` was born as a React-only project. replaces `react-use-gesture` completely and relies on a universal core, that also powers . 16 | 17 | Upgrading from `react-use-gesture` to is rather straightforward, although includes some breaking changes that are listed [here](https://github.com/pmndrs/use-gesture/blob/main/packages/react/CHANGELOG.md#1000). 18 | 19 | ### Main breaking change 20 | 21 | The API is 95% the same as before, the main one being the `domTarget` option being renamed to `target`. 22 | -------------------------------------------------------------------------------- /documentation/pages/docs/utilities.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Utilities 3 | section: Reference 4 | order: 4 5 | --- 6 | 7 | import UseGesture from './code/rug' 8 | 9 | # Utilities 10 | 11 | ‌ uses a set of utility functions internally that are exposed for anybody's convenience. Well only one actually. 12 | 13 | ### rubberbandIfOutOfBounds 14 | 15 | Calculates the rubberbanding effect from a given `position` value, two bounds `min`, `max` and an elasticity `constant`. 16 | 17 | ```ts 18 | function rubberbandIfOutOfBounds(position: number, min: number, max: number, constant = 0.15): number 19 | ``` 20 | -------------------------------------------------------------------------------- /documentation/pages/docs/video.module.css: -------------------------------------------------------------------------------- 1 | .videos { 2 | display: grid; 3 | align-items: flex-start; 4 | grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); 5 | grid-gap: 1rem; 6 | } 7 | 8 | .videos > div video { 9 | transition: filter 400ms ease; 10 | } 11 | 12 | .videos > div:hover video { 13 | filter: brightness(1.1); 14 | } 15 | 16 | .badges { 17 | display: flex; 18 | margin: 0.4em -0.3rem; 19 | } 20 | 21 | .badge { 22 | font-size: 0.8rem; 23 | margin: 0 0.3rem; 24 | } 25 | 26 | .badges > .badge { 27 | text-decoration: none; 28 | color: var(--xstyled-colors-on-background-light, #4a5568); 29 | background-color: var(--xstyled-colors-control-background); 30 | padding: 0.4rem 0.5rem; 31 | border-radius: 2px; 32 | } 33 | 34 | .badges > .badge:hover { 35 | background-color: var(--xstyled-colors-on-background-primary, #667eea); 36 | color: #fff; 37 | } 38 | 39 | .playerWrapper { 40 | position: relative; 41 | padding-top: 56.25%; /* Player ratio: 100 / (1280 / 720) */ 42 | } 43 | 44 | .player { 45 | position: absolute; 46 | top: 0; 47 | left: 0; 48 | } 49 | -------------------------------------------------------------------------------- /documentation/pages/partials/shields.mdx: -------------------------------------------------------------------------------- 1 | ![npm (tag)](https://img.shields.io/npm/v/@use-gesture/core?style=flat&colorA=000000&colorB=000000) ![npm bundle 2 | size](https://img.shields.io/bundlephobia/minzip/@use-gesture/core?style=flat&colorA=000000&colorB=000000) 3 | ![NPM](https://img.shields.io/npm/l/@use-gesture/core?style=flat&colorA=000000&colorB=000000) 4 | [![Discord 5 | Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/ZZjjNvJ) 6 | -------------------------------------------------------------------------------- /documentation/src/smooth-doc/components/SiblingNav.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import styled, { down, css } from '@xstyled/styled-components' 4 | 5 | export const InnerSiblingNavLink = styled.aBox` 6 | display: flex; 7 | align-items: center; 8 | font-weight: bold; 9 | transition: fast; 10 | text-decoration: none !important; 11 | p { 12 | letter-spacing: 0.14em; 13 | text-transform: uppercase; 14 | font-weight: 400; 15 | font-size: 12; 16 | margin: 0; 17 | } 18 | span { 19 | margin: 0 16px 0 4px; 20 | } 21 | h3 { 22 | margin: 0; 23 | font-size: 16; 24 | color: on-background-primary; 25 | } 26 | &:hover { 27 | color: on-background-primary-dark; 28 | } 29 | &[data-type='next'] { 30 | justify-content: flex-end; 31 | span { 32 | margin: 0 4px 0 16px; 33 | } 34 | } 35 | &[data-type='next']:hover { 36 | transform: translateX(2px); 37 | } 38 | &[data-type='previous']:hover { 39 | transform: translateX(-2px); 40 | } 41 | ` 42 | 43 | export const SiblingNavLink = React.forwardRef(({ type, children, ...props }, ref) => { 44 | return ( 45 | 46 | {type === 'previous' && '← '} 47 |
48 |

{type === 'previous' ? 'Prev' : 'Next'}

49 |

{children}

50 |
51 | {type === 'next' && ' →'} 52 |
53 | ) 54 | }) 55 | 56 | export const SiblingNav = styled.navBox` 57 | display: grid; 58 | grid-template-areas: 'previous next'; 59 | justify-content: space-between; 60 | margin: 5 0; 61 | ${down( 62 | 'sm', 63 | css` 64 | display: flex; 65 | flex-direction: column; 66 | ` 67 | )} 68 | ` 69 | -------------------------------------------------------------------------------- /documentation/src/smooth-doc/theme.js: -------------------------------------------------------------------------------- 1 | import { theme as baseTheme } from 'smooth-doc/src/theme' 2 | import NightOwlTheme from 'prism-react-renderer/themes/nightOwl' 3 | import './styles.css' 4 | 5 | export const theme = { 6 | ...baseTheme, 7 | 'prism-theme': NightOwlTheme, 8 | colors: { 9 | ...baseTheme.colors, 10 | 'editor-background': 'rgb(1, 22, 39)', 11 | modes: { 12 | ...baseTheme.colors.modes, 13 | dark: { 14 | ...baseTheme.colors.modes.dark, 15 | 'editor-background': 'rgb(1, 22, 39)' 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /documentation/static/equirectangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/equirectangular.png -------------------------------------------------------------------------------- /documentation/static/piz_compressed.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/piz_compressed.exr -------------------------------------------------------------------------------- /documentation/static/studio.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/studio.hdr -------------------------------------------------------------------------------- /documentation/static/videos/actionsheet.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/actionsheet.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/cards.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/cards.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/draggable.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/draggable.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/infinitescroll.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/infinitescroll.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/multi.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/multi.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/rocket.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/rocket.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/simple.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/simple.mp4 -------------------------------------------------------------------------------- /documentation/static/videos/viewpager.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmndrs/use-gesture/c779631aa05959638dee81b9a25fb1299a7467f6/documentation/static/videos/viewpager.mp4 -------------------------------------------------------------------------------- /packages/core/actions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "dist/use-gesture-core-actions.cjs.js", 3 | "module": "dist/use-gesture-core-actions.esm.js" 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-gesture/core", 3 | "version": "10.3.1", 4 | "description": "Core engine for receiving gestures", 5 | "license": "MIT", 6 | "main": "dist/use-gesture-core.cjs.js", 7 | "module": "dist/use-gesture-core.esm.js", 8 | "exports": { 9 | ".": { 10 | "module": "./dist/use-gesture-core.esm.js", 11 | "default": "./dist/use-gesture-core.cjs.js" 12 | }, 13 | "./types": { 14 | "module": "./types/dist/use-gesture-core-types.esm.js", 15 | "default": "./types/dist/use-gesture-core-types.cjs.js" 16 | }, 17 | "./utils": { 18 | "module": "./utils/dist/use-gesture-core-utils.esm.js", 19 | "default": "./utils/dist/use-gesture-core-utils.cjs.js" 20 | }, 21 | "./actions": { 22 | "module": "./actions/dist/use-gesture-core-actions.esm.js", 23 | "default": "./actions/dist/use-gesture-core-actions.cjs.js" 24 | }, 25 | "./package.json": "./package.json" 26 | }, 27 | "sideEffects": false, 28 | "preconstruct": { 29 | "exports": true, 30 | "entrypoints": [ 31 | "./index.ts", 32 | "./utils.ts", 33 | "./actions.ts", 34 | "./types.ts" 35 | ] 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git+https://github.com/pmndrs/use-gesture.git", 40 | "directory": "packages/core" 41 | }, 42 | "bugs": { 43 | "url": "https://github.com/pmndrs/use-gesture/issues" 44 | }, 45 | "author": "Paul Henschel", 46 | "contributors": [ 47 | "David Bismut (https://github.com/dbismut)" 48 | ], 49 | "homepage": "https://use-gesture.netlify.app" 50 | } 51 | -------------------------------------------------------------------------------- /packages/core/src/EventStore.ts: -------------------------------------------------------------------------------- 1 | import type { Controller } from './Controller' 2 | import { GestureKey } from './types' 3 | import { toDomEventType } from './utils/events' 4 | 5 | export class EventStore { 6 | private _listeners = new Set<() => void>() 7 | private _ctrl: Controller 8 | private _gestureKey?: GestureKey 9 | constructor(ctrl: Controller, gestureKey?: GestureKey) { 10 | this._ctrl = ctrl 11 | this._gestureKey = gestureKey 12 | } 13 | 14 | add( 15 | element: EventTarget, 16 | device: string, 17 | action: string, 18 | handler: (event: any) => void, 19 | options?: AddEventListenerOptions 20 | ) { 21 | const listeners = this._listeners 22 | const type = toDomEventType(device, action) 23 | const _options = this._gestureKey ? this._ctrl.config[this._gestureKey]!.eventOptions : {} 24 | const eventOptions = { ..._options, ...options } 25 | element.addEventListener(type, handler, eventOptions) 26 | const remove = () => { 27 | element.removeEventListener(type, handler, eventOptions) 28 | listeners.delete(remove) 29 | } 30 | listeners.add(remove) 31 | return remove 32 | } 33 | 34 | clean() { 35 | this._listeners.forEach((remove) => remove()) 36 | this._listeners.clear() // just for safety 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/TimeoutStore.ts: -------------------------------------------------------------------------------- 1 | export class TimeoutStore { 2 | private _timeouts = new Map() 3 | 4 | add any>( 5 | key: string, 6 | callback: FunctionType, 7 | ms = 140, 8 | ...args: Parameters 9 | ) { 10 | this.remove(key) 11 | this._timeouts.set(key, window.setTimeout(callback, ms, ...args)) 12 | } 13 | 14 | remove(key: string) { 15 | const timeout = this._timeouts.get(key) 16 | if (timeout) window.clearTimeout(timeout) 17 | } 18 | 19 | clean() { 20 | this._timeouts.forEach((timeout) => void window.clearTimeout(timeout)) 21 | this._timeouts.clear() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/config/coordinatesConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { commonConfigResolver } from './commonConfigResolver' 2 | import { InternalCoordinatesOptions, CoordinatesConfig, Bounds, DragBounds, State, Vector2 } from '../types' 3 | 4 | const DEFAULT_AXIS_THRESHOLD = 0 5 | 6 | export const coordinatesConfigResolver = { 7 | ...commonConfigResolver, 8 | axis( 9 | this: InternalCoordinatesOptions, 10 | _v: any, 11 | _k: string, 12 | { axis }: CoordinatesConfig 13 | ): InternalCoordinatesOptions['axis'] { 14 | this.lockDirection = axis === 'lock' 15 | if (!this.lockDirection) return axis as any 16 | }, 17 | axisThreshold(value = DEFAULT_AXIS_THRESHOLD) { 18 | return value 19 | }, 20 | bounds( 21 | value: DragBounds | ((state: State) => DragBounds) = {} 22 | ): (() => EventTarget | null) | HTMLElement | [Vector2, Vector2] { 23 | if (typeof value === 'function') { 24 | // @ts-ignore 25 | return (state: State) => coordinatesConfigResolver.bounds(value(state)) 26 | } 27 | 28 | if ('current' in value) { 29 | return () => value.current 30 | } 31 | 32 | if (typeof HTMLElement === 'function' && value instanceof HTMLElement) { 33 | return value 34 | } 35 | 36 | const { left = -Infinity, right = Infinity, top = -Infinity, bottom = Infinity } = value as Bounds 37 | 38 | return [ 39 | [left, right], 40 | [top, bottom] 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/core/src/config/hoverConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { coordinatesConfigResolver } from './coordinatesConfigResolver' 2 | 3 | export const hoverConfigResolver = { 4 | ...coordinatesConfigResolver, 5 | mouseOnly: (value = true) => value 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/src/config/moveConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { coordinatesConfigResolver } from './coordinatesConfigResolver' 2 | 3 | export const moveConfigResolver = { 4 | ...coordinatesConfigResolver, 5 | mouseOnly: (value = true) => value 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/src/config/scrollConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { coordinatesConfigResolver } from './coordinatesConfigResolver' 2 | 3 | export const scrollConfigResolver = coordinatesConfigResolver 4 | -------------------------------------------------------------------------------- /packages/core/src/config/sharedConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { Target } from '../types' 2 | import { SUPPORT } from './support' 3 | 4 | export const sharedConfigResolver = { 5 | target(value: Target) { 6 | if (value) { 7 | return () => ('current' in value ? value.current : value) 8 | } 9 | return undefined 10 | }, 11 | enabled(value = true) { 12 | return value 13 | }, 14 | window(value = SUPPORT.isBrowser ? window : undefined) { 15 | return value 16 | }, 17 | eventOptions({ passive = true, capture = false } = {}) { 18 | return { passive, capture } 19 | }, 20 | transform(value: any) { 21 | return value 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/core/src/config/support.ts: -------------------------------------------------------------------------------- 1 | const isBrowser = typeof window !== 'undefined' && window.document && window.document.createElement 2 | 3 | function supportsTouchEvents(): boolean { 4 | return isBrowser && 'ontouchstart' in window 5 | } 6 | 7 | function isTouchScreen(): boolean { 8 | return supportsTouchEvents() || (isBrowser && window.navigator.maxTouchPoints > 1) 9 | } 10 | 11 | function supportsPointerEvents(): boolean { 12 | return isBrowser && 'onpointerdown' in window 13 | } 14 | 15 | function supportsPointerLock(): boolean { 16 | return isBrowser && 'exitPointerLock' in window.document 17 | } 18 | 19 | function supportsGestureEvents(): boolean { 20 | try { 21 | // TODO [TS] possibly find GestureEvent definitions? 22 | // @ts-ignore: no type definitions for webkit GestureEvents 23 | return 'constructor' in GestureEvent 24 | } catch (e) { 25 | return false 26 | } 27 | } 28 | 29 | export const SUPPORT = { 30 | isBrowser, 31 | gesture: supportsGestureEvents(), 32 | /** 33 | * It looks from https://github.com/pmndrs/use-gesture/discussions/421 that 34 | * some touchscreens using webkits don't have 'ontouchstart' in window. So 35 | * we're considering that browsers support TouchEvent if they have 36 | * `maxTouchPoints > 1` 37 | * 38 | * Update 16/09/2023: This generates failure on other Windows systems, so reverting 39 | * back to detecting TouchEvent support only. 40 | * https://github.com/pmndrs/use-gesture/issues/626 41 | */ 42 | touch: supportsTouchEvents(), 43 | // touch: isTouchScreen(), 44 | touchscreen: isTouchScreen(), 45 | pointer: supportsPointerEvents(), 46 | pointerLock: supportsPointerLock() 47 | } 48 | -------------------------------------------------------------------------------- /packages/core/src/config/wheelConfigResolver.ts: -------------------------------------------------------------------------------- 1 | import { coordinatesConfigResolver } from './coordinatesConfigResolver' 2 | 3 | export const wheelConfigResolver = coordinatesConfigResolver 4 | -------------------------------------------------------------------------------- /packages/core/src/engines/HoverEngine.ts: -------------------------------------------------------------------------------- 1 | import { CoordinatesEngine } from './CoordinatesEngine' 2 | import { pointerValues } from '../utils/events' 3 | import { V } from '../utils/maths' 4 | 5 | export class HoverEngine extends CoordinatesEngine<'hover'> { 6 | ingKey = 'hovering' as const 7 | 8 | enter(event: PointerEvent) { 9 | if (this.config.mouseOnly && event.pointerType !== 'mouse') return 10 | this.start(event) 11 | this.computeValues(pointerValues(event)) 12 | 13 | this.compute(event) 14 | this.emit() 15 | } 16 | 17 | leave(event: PointerEvent) { 18 | if (this.config.mouseOnly && event.pointerType !== 'mouse') return 19 | 20 | const state = this.state 21 | if (!state._active) return 22 | 23 | state._active = false 24 | const values = pointerValues(event) 25 | state._movement = state._delta = V.sub(values, state._values) 26 | 27 | this.computeValues(values) 28 | this.compute(event) 29 | 30 | state.delta = state.movement 31 | this.emit() 32 | } 33 | 34 | bind(bindFunction: any) { 35 | bindFunction('pointer', 'enter', this.enter.bind(this)) 36 | bindFunction('pointer', 'leave', this.leave.bind(this)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/engines/MoveEngine.ts: -------------------------------------------------------------------------------- 1 | import { CoordinatesEngine } from './CoordinatesEngine' 2 | import { pointerValues } from '../utils/events' 3 | import { V } from '../utils/maths' 4 | 5 | export class MoveEngine extends CoordinatesEngine<'move'> { 6 | ingKey = 'moving' as const 7 | 8 | move(event: PointerEvent) { 9 | if (this.config.mouseOnly && event.pointerType !== 'mouse') return 10 | if (!this.state._active) this.moveStart(event) 11 | else this.moveChange(event) 12 | this.timeoutStore.add('moveEnd', this.moveEnd.bind(this)) 13 | } 14 | 15 | moveStart(event: PointerEvent) { 16 | this.start(event) 17 | this.computeValues(pointerValues(event)) 18 | this.compute(event) 19 | this.computeInitial() 20 | this.emit() 21 | } 22 | 23 | moveChange(event: PointerEvent) { 24 | if (!this.state._active) return 25 | const values = pointerValues(event) 26 | const state = this.state 27 | state._delta = V.sub(values, state._values) 28 | V.addTo(state._movement, state._delta) 29 | 30 | this.computeValues(values) 31 | 32 | this.compute(event) 33 | this.emit() 34 | } 35 | 36 | moveEnd(event?: PointerEvent) { 37 | if (!this.state._active) return 38 | this.state._active = false 39 | this.compute(event) 40 | this.emit() 41 | } 42 | 43 | bind(bindFunction: any) { 44 | bindFunction('pointer', 'change', this.move.bind(this)) 45 | bindFunction('pointer', 'leave', this.moveEnd.bind(this)) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/core/src/engines/ScrollEngine.ts: -------------------------------------------------------------------------------- 1 | import { CoordinatesEngine } from './CoordinatesEngine' 2 | import { scrollValues } from '../utils/events' 3 | import { V } from '../utils/maths' 4 | 5 | export class ScrollEngine extends CoordinatesEngine<'scroll'> { 6 | ingKey = 'scrolling' as const 7 | 8 | scroll(event: UIEvent) { 9 | if (!this.state._active) this.start(event) 10 | this.scrollChange(event) 11 | this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this)) 12 | } 13 | 14 | scrollChange(event: UIEvent) { 15 | if (event.cancelable) event.preventDefault() 16 | const state = this.state 17 | const values = scrollValues(event) 18 | state._delta = V.sub(values, state._values) 19 | V.addTo(state._movement, state._delta) 20 | 21 | this.computeValues(values) 22 | this.compute(event) 23 | 24 | this.emit() 25 | } 26 | 27 | scrollEnd() { 28 | if (!this.state._active) return 29 | this.state._active = false 30 | this.compute() 31 | this.emit() 32 | } 33 | 34 | bind(bindFunction: any) { 35 | bindFunction('scroll', '', this.scroll.bind(this)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/core/src/engines/WheelEngine.ts: -------------------------------------------------------------------------------- 1 | import { CoordinatesEngine } from './CoordinatesEngine' 2 | import { wheelValues } from '../utils/events' 3 | import { V } from '../utils/maths' 4 | import { clampStateInternalMovementToBounds } from '../utils/state' 5 | 6 | export interface WheelEngine extends CoordinatesEngine<'wheel'> { 7 | wheel(this: WheelEngine, event: WheelEvent): void 8 | wheelChange(this: WheelEngine, event: WheelEvent): void 9 | wheelEnd(this: WheelEngine): void 10 | } 11 | 12 | export class WheelEngine extends CoordinatesEngine<'wheel'> { 13 | ingKey = 'wheeling' as const 14 | 15 | wheel(event: WheelEvent) { 16 | if (!this.state._active) this.start(event) 17 | this.wheelChange(event) 18 | this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)) 19 | } 20 | 21 | wheelChange(event: WheelEvent) { 22 | const state = this.state 23 | state._delta = wheelValues(event) 24 | V.addTo(state._movement, state._delta) 25 | 26 | // _movement rolls back to when it passed the bounds. 27 | clampStateInternalMovementToBounds(state) 28 | 29 | this.compute(event) 30 | this.emit() 31 | } 32 | 33 | wheelEnd() { 34 | if (!this.state._active) return 35 | this.state._active = false 36 | this.compute() 37 | this.emit() 38 | } 39 | 40 | bind(bindFunction: any) { 41 | bindFunction('wheel', '', this.wheel.bind(this)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { Controller } from './Controller' 2 | export { parseMergedHandlers } from './parser' 3 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | // type exports for core 2 | 3 | export * from './types/index' 4 | -------------------------------------------------------------------------------- /packages/core/src/types/action.ts: -------------------------------------------------------------------------------- 1 | import type { ResolverMap } from '../config/resolver' 2 | import type { Controller } from '../Controller' 3 | import type { Engine } from '../engines/Engine' 4 | import { GestureKey } from './config' 5 | 6 | export type EngineClass = { 7 | new (controller: Controller, args: any[], key: Key): Engine 8 | } 9 | 10 | export type Action = { 11 | key: GestureKey 12 | engine: EngineClass 13 | resolver: ResolverMap 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './config' 2 | export * from './internalConfig' 3 | export * from './state' 4 | export * from './utils' 5 | export * from './handlers' 6 | export * from './action' 7 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | // additional core exports 2 | 3 | export { rubberbandIfOutOfBounds } from './utils/maths' 4 | -------------------------------------------------------------------------------- /packages/core/src/utils/fn.ts: -------------------------------------------------------------------------------- 1 | export function call(v: T | ((...args: any[]) => T), ...args: any[]): T { 2 | if (typeof v === 'function') { 3 | // @ts-ignore 4 | return v(...args) 5 | } else { 6 | return v 7 | } 8 | } 9 | 10 | export function noop() {} 11 | 12 | export function chain(...fns: Function[]): Function { 13 | if (fns.length === 0) return noop 14 | if (fns.length === 1) return fns[0] 15 | 16 | return function (this: any) { 17 | let result 18 | for (const fn of fns) { 19 | result = fn.apply(this, arguments) || result 20 | } 21 | return result 22 | } 23 | } 24 | 25 | export function assignDefault(value: Partial | undefined, fallback: T): T { 26 | return Object.assign({}, fallback, value || {}) 27 | } 28 | -------------------------------------------------------------------------------- /packages/core/src/utils/state.ts: -------------------------------------------------------------------------------- 1 | import { CommonGestureState } from '../types' 2 | 3 | // _movement rolls back to when it passed the bounds. 4 | /** 5 | * @note code is currently used in WheelEngine and PinchEngine. 6 | */ 7 | export function clampStateInternalMovementToBounds(state: CommonGestureState) { 8 | const [ox, oy] = state.overflow 9 | const [dx, dy] = state._delta 10 | const [dirx, diry] = state._direction 11 | 12 | if ((ox < 0 && dx > 0 && dirx < 0) || (ox > 0 && dx < 0 && dirx > 0)) { 13 | state._movement[0] = state._movementBound[0] as number 14 | } 15 | 16 | if ((oy < 0 && dy > 0 && diry < 0) || (oy > 0 && dy < 0 && diry > 0)) { 17 | state._movement[1] = state._movementBound[1] as number 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "dist/use-gesture-core-types.cjs.js", 3 | "module": "dist/use-gesture-core-types.esm.js" 4 | } 5 | -------------------------------------------------------------------------------- /packages/core/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "dist/use-gesture-core-utils.cjs.js", 3 | "module": "dist/use-gesture-core-utils.esm.js" 4 | } 5 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-gesture/react", 3 | "version": "10.3.1", 4 | "description": "React target for @use-gesture", 5 | "keywords": [ 6 | "react", 7 | "hook", 8 | "gesture", 9 | "mouse", 10 | "trackpad", 11 | "touch", 12 | "drag", 13 | "pinch", 14 | "rotate", 15 | "scale", 16 | "zoom", 17 | "scroll", 18 | "wheel" 19 | ], 20 | "license": "MIT", 21 | "sideEffects": false, 22 | "main": "dist/use-gesture-react.cjs.js", 23 | "module": "dist/use-gesture-react.esm.js", 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/pmndrs/use-gesture.git", 27 | "directory": "packages/react" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/pmndrs/use-gesture/issues" 31 | }, 32 | "author": "Paul Henschel", 33 | "contributors": [ 34 | "David Bismut (https://github.com/dbismut)" 35 | ], 36 | "homepage": "https://use-gesture.netlify.app", 37 | "peerDependencies": { 38 | "react": ">= 16.8.0" 39 | }, 40 | "dependencies": { 41 | "@use-gesture/core": "10.3.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/react/src/createUseGesture.ts: -------------------------------------------------------------------------------- 1 | import { parseMergedHandlers } from '@use-gesture/core' 2 | import { registerAction } from '@use-gesture/core/actions' 3 | import { Action, GestureHandlers, UserGestureConfig } from '@use-gesture/core/types' 4 | import { useRecognizers } from './useRecognizers' 5 | 6 | export function createUseGesture(actions: Action[]) { 7 | actions.forEach(registerAction) 8 | 9 | return function useGesture( 10 | _handlers: GestureHandlers, 11 | _config?: Config 12 | ) { 13 | const { handlers, nativeHandlers, config } = parseMergedHandlers(_handlers, _config || {}) 14 | return useRecognizers(handlers, config, undefined, nativeHandlers) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export { useDrag } from './useDrag' 2 | export { usePinch } from './usePinch' 3 | export { useWheel } from './useWheel' 4 | export { useScroll } from './useScroll' 5 | export { useMove } from './useMove' 6 | export { useHover } from './useHover' 7 | export { useGesture } from './useGesture' 8 | export { createUseGesture } from './createUseGesture' 9 | 10 | export * from '@use-gesture/core/utils' 11 | export * from '@use-gesture/core/actions' 12 | export * from '@use-gesture/core/types' 13 | -------------------------------------------------------------------------------- /packages/react/src/types.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | /* Type tests for @use-gesture/react */ 3 | 4 | import { useRef } from 'react' 5 | import { expectType } from 'tsd' 6 | import { useDrag, useGesture } from '.' 7 | import { ReactDOMAttributes } from './types' 8 | 9 | /* Checks that gesture hooks return event props handlers */ 10 | expectType<(...args: any[]) => ReactDOMAttributes>(useDrag(() => {})) 11 | 12 | /* Checks that gesture hooks don't return any value when used with config option `target` */ 13 | expectType(useDrag(() => {}, { target: window })) 14 | 15 | /* Checks that hooks accept generics to cast event type */ 16 | useDrag(({ event }) => expectType(event)) 17 | 18 | const fakeDiv = 'fake' as any as HTMLDivElement 19 | const fakeRef = useRef(null) 20 | /* Checks config.bounds type for useDrag */ 21 | useDrag(() => {}, { bounds: { left: 0 } }) 22 | useDrag(() => {}, { bounds: fakeDiv }) 23 | useDrag(() => {}, { bounds: fakeRef }) 24 | 25 | /* Checks that useGesture returns event props handler */ 26 | expectType<(...args: any[]) => ReactDOMAttributes>(useGesture({ onPinch: () => {} })) 27 | 28 | /* Checks that useGesture doesn't return any value when used with config option `target` */ 29 | expectType(useGesture({ onPinch: () => {} }, { target: window })) 30 | 31 | /* Checks that useGesture accepts generics to cast event type */ 32 | useGesture<{ drag: MouseEvent; pinch: WheelEvent; onClick: PointerEvent }>({ 33 | onDrag: ({ event }) => expectType(event), 34 | onPinch: ({ event }) => expectType(event), 35 | onClick: ({ event }) => expectType(event) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/react/src/types.ts: -------------------------------------------------------------------------------- 1 | import { DOMHandlers } from '@use-gesture/core/types' 2 | 3 | export type ReactDOMAttributes = { 4 | [Key in keyof DOMHandlers]: React.DOMAttributes[Key] 5 | } 6 | -------------------------------------------------------------------------------- /packages/react/src/useDrag.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, dragAction } from '@use-gesture/core/actions' 2 | import { EventTypes, Handler, UserDragConfig } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Drag hook. 7 | * 8 | * @param {Handler<'drag'>} handler - the function fired every time the drag gesture updates 9 | * @param {UserDragConfig} config - the config object including generic options and drag options 10 | */ 11 | export function useDrag( 12 | handler: Handler<'drag', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(dragAction) 16 | return useRecognizers({ drag: handler }, config || {}, 'drag') 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/src/useGesture.ts: -------------------------------------------------------------------------------- 1 | import { dragAction, pinchAction, scrollAction, wheelAction, moveAction, hoverAction } from '@use-gesture/core/actions' 2 | import { GestureHandlers, UserGestureConfig, EventTypes, AnyHandlerEventTypes } from '@use-gesture/core/types' 3 | import { createUseGesture } from './createUseGesture' 4 | 5 | /** 6 | * @public 7 | * 8 | * The most complete gesture hook, allowing support for multiple gestures. 9 | * 10 | * @param {GestureHandlers} handlers - an object with on[Gesture] keys containg gesture handlers 11 | * @param {UserGestureConfig} config - the full config object 12 | */ 13 | export function useGesture< 14 | HandlerTypes extends AnyHandlerEventTypes = EventTypes, 15 | Config extends UserGestureConfig = UserGestureConfig 16 | >(handlers: GestureHandlers, config?: Config) { 17 | const hook = createUseGesture([dragAction, pinchAction, scrollAction, wheelAction, moveAction, hoverAction]) 18 | return hook(handlers, config || ({} as Config)) 19 | } 20 | -------------------------------------------------------------------------------- /packages/react/src/useHover.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, hoverAction } from '@use-gesture/core/actions' 2 | import { EventTypes, UserHoverConfig, Handler } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Hover hook. 7 | * 8 | * @param {Handler<'hover'>} handler - the function fired every time the hover gesture updates 9 | * @param {UserHoverConfig} config - the config object including generic options and hover options 10 | */ 11 | export function useHover( 12 | handler: Handler<'hover', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(hoverAction) 16 | return useRecognizers({ hover: handler }, config || {}, 'hover') 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/src/useMove.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, moveAction } from '@use-gesture/core/actions' 2 | import { UserMoveConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Move hook. 7 | * 8 | * @param {Handler<'move'>} handler - the function fired every time the move gesture updates 9 | * @param {UserMoveConfig} config - the config object including generic options and move options 10 | */ 11 | export function useMove( 12 | handler: Handler<'move', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(moveAction) 16 | return useRecognizers({ move: handler }, config || {}, 'move') 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/src/usePinch.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, pinchAction } from '@use-gesture/core/actions' 2 | import { UserPinchConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Pinch hook. 7 | * 8 | * @param {Handler<'pinch'>} handler - the function fired every time the pinch gesture updates 9 | * @param {UserPinchConfig} config - the config object including generic options and pinch options 10 | */ 11 | export function usePinch( 12 | handler: Handler<'pinch', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(pinchAction) 16 | return useRecognizers({ pinch: handler }, config || {}, 'pinch') 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/src/useRecognizers.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/exhaustive-deps */ 2 | import React from 'react' 3 | import { Controller } from '@use-gesture/core' 4 | import { GenericOptions, GestureKey, InternalHandlers, NativeHandlers } from '@use-gesture/core/types' 5 | import { ReactDOMAttributes } from './types' 6 | 7 | type HookReturnType = Config['target'] extends object 8 | ? void 9 | : (...args: any[]) => ReactDOMAttributes 10 | 11 | /** 12 | * Utility hook called by all gesture hooks and that will be responsible for 13 | * the internals. 14 | * 15 | * @param {InternalHandlers} handlers 16 | * @param {GenericOptions} config 17 | * @param {GestureKey} gestureKey 18 | * @param {NativeHandler} nativeHandlers 19 | * @returns nothing when config.target is set, a binding function when not. 20 | */ 21 | export function useRecognizers( 22 | handlers: InternalHandlers, 23 | config: Config | {} = {}, 24 | gestureKey?: GestureKey, 25 | nativeHandlers?: NativeHandlers 26 | ): HookReturnType { 27 | const ctrl = React.useMemo(() => new Controller(handlers), []) 28 | ctrl.applyHandlers(handlers, nativeHandlers) 29 | ctrl.applyConfig(config, gestureKey) 30 | 31 | React.useEffect(ctrl.effect.bind(ctrl)) 32 | 33 | React.useEffect(() => { 34 | return ctrl.clean.bind(ctrl) 35 | }, []) 36 | 37 | // When target is undefined we return the bind function of the controller which 38 | // returns prop handlers. 39 | // @ts-ignore 40 | if (config.target === undefined) { 41 | return ctrl.bind.bind(ctrl) as any 42 | } 43 | return undefined as any 44 | } 45 | -------------------------------------------------------------------------------- /packages/react/src/useScroll.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, scrollAction } from '@use-gesture/core/actions' 2 | import { UserScrollConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Scroll hook. 7 | * 8 | * @param {Handler<'scroll'>} handler - the function fired every time the scroll gesture updates 9 | * @param {UserScrollConfig} config - the config object including generic options and scroll options 10 | */ 11 | export function useScroll( 12 | handler: Handler<'scroll', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(scrollAction) 16 | return useRecognizers({ scroll: handler }, config || {}, 'scroll') 17 | } 18 | -------------------------------------------------------------------------------- /packages/react/src/useWheel.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, wheelAction } from '@use-gesture/core/actions' 2 | import { UserWheelConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { useRecognizers } from './useRecognizers' 4 | 5 | /** 6 | * Wheel hook. 7 | * 8 | * @param {Handler<'wheel'>} handler - the function fired every time the wheel gesture updates 9 | * @param {UserWheelConfig} config - the config object including generic options and wheel options 10 | */ 11 | export function useWheel( 12 | handler: Handler<'wheel', EventType>, 13 | config?: Config 14 | ) { 15 | registerAction(wheelAction) 16 | return useRecognizers({ wheel: handler }, config || {}, 'wheel') 17 | } 18 | -------------------------------------------------------------------------------- /packages/vanilla/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@use-gesture/vanilla", 3 | "version": "10.3.1", 4 | "description": "Vanilla target for @use-gesture", 5 | "keywords": [ 6 | "react", 7 | "hook", 8 | "gesture", 9 | "mouse", 10 | "trackpad", 11 | "touch", 12 | "drag", 13 | "pinch", 14 | "rotate", 15 | "scale", 16 | "zoom", 17 | "scroll", 18 | "wheel" 19 | ], 20 | "license": "MIT", 21 | "sideEffects": false, 22 | "main": "dist/use-gesture-vanilla.cjs.js", 23 | "module": "dist/use-gesture-vanilla.esm.js", 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/pmndrs/use-gesture.git", 27 | "directory": "packages/vanilla" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/pmndrs/use-gesture/issues" 31 | }, 32 | "author": "Paul Henschel", 33 | "contributors": [ 34 | "David Bismut (https://github.com/dbismut)" 35 | ], 36 | "homepage": "https://use-gesture.netlify.app", 37 | "dependencies": { 38 | "@use-gesture/core": "10.3.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/vanilla/src/DragGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, dragAction } from '@use-gesture/core/actions' 2 | import { EventTypes, Handler, UserDragConfig } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface DragGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'drag', EventType>, 9 | config?: UserDragConfig 10 | ): DragGesture 11 | } 12 | 13 | export interface DragGesture extends Recognizer<'drag'> {} 14 | 15 | export const DragGesture: DragGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'drag', EventType>, 18 | config?: UserDragConfig 19 | ) { 20 | registerAction(dragAction) 21 | return new Recognizer(target, { drag: handler }, config || {}, 'drag') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/Gesture.ts: -------------------------------------------------------------------------------- 1 | import { dragAction, pinchAction, scrollAction, wheelAction, moveAction, hoverAction } from '@use-gesture/core/actions' 2 | import { AnyHandlerEventTypes, EventTypes, GestureHandlers, UserGestureConfig } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | import { createGesture } from './createGesture' 5 | 6 | interface GestureConstructor { 7 | new ( 8 | target: EventTarget, 9 | handlers: GestureHandlers, 10 | config?: UserGestureConfig 11 | ): Gesture 12 | } 13 | 14 | export interface Gesture extends Recognizer {} 15 | 16 | export const Gesture: GestureConstructor = function ( 17 | target: EventTarget, 18 | handlers: GestureHandlers, 19 | config?: UserGestureConfig 20 | ) { 21 | const gestureFunction = createGesture([dragAction, pinchAction, scrollAction, wheelAction, moveAction, hoverAction]) 22 | return gestureFunction(target, handlers, config || ({} as UserGestureConfig)) 23 | } as any 24 | -------------------------------------------------------------------------------- /packages/vanilla/src/HoverGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, hoverAction } from '@use-gesture/core/actions' 2 | import { EventTypes, UserHoverConfig, Handler } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface HoverGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'hover', EventType>, 9 | config?: UserHoverConfig 10 | ): HoverGesture 11 | } 12 | 13 | export interface HoverGesture extends Recognizer<'hover'> {} 14 | 15 | export const HoverGesture: HoverGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'hover', EventType>, 18 | config?: UserHoverConfig 19 | ) { 20 | registerAction(hoverAction) 21 | return new Recognizer(target, { hover: handler }, config || {}, 'hover') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/MoveGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, moveAction } from '@use-gesture/core/actions' 2 | import { UserMoveConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface MoveGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'move', EventType>, 9 | config?: UserMoveConfig 10 | ): MoveGesture 11 | } 12 | 13 | export interface MoveGesture extends Recognizer<'move'> {} 14 | 15 | export const MoveGesture: MoveGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'move', EventType>, 18 | config?: UserMoveConfig 19 | ) { 20 | registerAction(moveAction) 21 | return new Recognizer(target, { move: handler }, config || {}, 'move') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/PinchGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, pinchAction } from '@use-gesture/core/actions' 2 | import { UserPinchConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface PinchGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'pinch', EventType>, 9 | config?: UserPinchConfig 10 | ): PinchGesture 11 | } 12 | 13 | export interface PinchGesture extends Recognizer<'pinch'> {} 14 | 15 | export const PinchGesture: PinchGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'pinch', EventType>, 18 | config?: UserPinchConfig 19 | ) { 20 | registerAction(pinchAction) 21 | return new Recognizer(target, { pinch: handler }, config || {}, 'pinch') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/Recognizer.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@use-gesture/core' 2 | import { GestureKey, InternalHandlers, NativeHandlers, UserGestureConfig } from '@use-gesture/core/types' 3 | 4 | export class Recognizer { 5 | private _gestureKey?: GK 6 | private _ctrl: Controller 7 | private _target: EventTarget 8 | 9 | constructor( 10 | target: EventTarget, 11 | handlers: InternalHandlers, 12 | config: GK extends keyof UserGestureConfig ? UserGestureConfig[GK] : UserGestureConfig, 13 | gestureKey?: GK, 14 | nativeHandlers?: NativeHandlers 15 | ) { 16 | this._target = target 17 | this._gestureKey = gestureKey 18 | this._ctrl = new Controller(handlers) 19 | this._ctrl.applyHandlers(handlers, nativeHandlers) 20 | this._ctrl.applyConfig({ ...config, target }, gestureKey) 21 | 22 | this._ctrl.effect() 23 | } 24 | 25 | destroy() { 26 | this._ctrl.clean() 27 | } 28 | 29 | setConfig(config: GK extends keyof UserGestureConfig ? UserGestureConfig[GK] : UserGestureConfig) { 30 | this._ctrl.clean() 31 | this._ctrl.applyConfig({ ...config, target: this._target }, this._gestureKey) 32 | this._ctrl.effect() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/vanilla/src/ScrollGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, scrollAction } from '@use-gesture/core/actions' 2 | import { UserScrollConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface ScrollGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'scroll', EventType>, 9 | config?: UserScrollConfig 10 | ): ScrollGesture 11 | } 12 | 13 | export interface ScrollGesture extends Recognizer<'scroll'> {} 14 | 15 | export const ScrollGesture: ScrollGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'scroll', EventType>, 18 | config?: UserScrollConfig 19 | ) { 20 | registerAction(scrollAction) 21 | return new Recognizer(target, { scroll: handler }, config || {}, 'scroll') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/WheelGesture.ts: -------------------------------------------------------------------------------- 1 | import { registerAction, wheelAction } from '@use-gesture/core/actions' 2 | import { UserWheelConfig, Handler, EventTypes } from '@use-gesture/core/types' 3 | import { Recognizer } from './Recognizer' 4 | 5 | interface WheelGestureConstructor { 6 | new ( 7 | target: EventTarget, 8 | handler: Handler<'wheel', EventType>, 9 | config?: UserWheelConfig 10 | ): WheelGesture 11 | } 12 | 13 | export interface WheelGesture extends Recognizer<'wheel'> {} 14 | 15 | export const WheelGesture: WheelGestureConstructor = function ( 16 | target: EventTarget, 17 | handler: Handler<'wheel', EventType>, 18 | config?: UserWheelConfig 19 | ) { 20 | registerAction(wheelAction) 21 | return new Recognizer(target, { wheel: handler }, config || {}, 'wheel') 22 | } as any 23 | -------------------------------------------------------------------------------- /packages/vanilla/src/createGesture.ts: -------------------------------------------------------------------------------- 1 | import { parseMergedHandlers } from '@use-gesture/core' 2 | import { registerAction } from '@use-gesture/core/actions' 3 | import { Action, GestureHandlers, UserGestureConfig } from '@use-gesture/core/types' 4 | import { Recognizer } from './Recognizer' 5 | 6 | export function createGesture(actions: Action[]) { 7 | actions.forEach(registerAction) 8 | 9 | return function (target: EventTarget, _handlers: GestureHandlers, _config?: UserGestureConfig) { 10 | const { handlers, nativeHandlers, config } = parseMergedHandlers(_handlers, _config || {}) 11 | return new Recognizer(target, handlers, config, undefined, nativeHandlers) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/vanilla/src/index.ts: -------------------------------------------------------------------------------- 1 | export { DragGesture } from './DragGesture' 2 | export { PinchGesture } from './PinchGesture' 3 | export { WheelGesture } from './WheelGesture' 4 | export { ScrollGesture } from './ScrollGesture' 5 | export { MoveGesture } from './MoveGesture' 6 | export { HoverGesture } from './HoverGesture' 7 | export { Gesture } from './Gesture' 8 | 9 | export { createGesture } from './createGesture' 10 | 11 | export * from '@use-gesture/core/utils' 12 | export * from '@use-gesture/core/types' 13 | export * from '@use-gesture/core/actions' 14 | -------------------------------------------------------------------------------- /packages/vanilla/src/types.test.ts: -------------------------------------------------------------------------------- 1 | /* Type tests for @use-gesture/vanilla */ 2 | 3 | import { expectType } from 'tsd' 4 | import { DragGesture, Gesture } from '.' 5 | 6 | /* Checks that hooks accept generics to cast event type */ 7 | new DragGesture(window, ({ event }) => expectType(event)) 8 | 9 | /* Checks that useGesture accepts generics to cast event type */ 10 | new Gesture<{ drag: MouseEvent; pinch: WheelEvent; onClick: PointerEvent }>(window, { 11 | onDrag: ({ event }) => expectType(event), 12 | onPinch: ({ event }) => expectType(event), 13 | onClick: ({ event }) => expectType(event) 14 | }) 15 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | # all packages in subdirs of packages/ 3 | - 'packages/*' 4 | - 'demo' 5 | - 'documentation' 6 | -------------------------------------------------------------------------------- /test/components/Api.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useGesture, useDrag } from '../../packages/react/src' 3 | import { Common } from './Common' 4 | 5 | interface Props { 6 | args1: any 7 | args2: any 8 | } 9 | 10 | export const BindProps: React.FC = ({ args1 = [], args2 = [] }) => { 11 | const [state, set] = React.useState({}) 12 | const bind = useDrag(({ event, cancel, ...rest }) => void set(rest)) 13 | 14 | return ( 15 | <> 16 | 24 | 32 | 33 | ) 34 | } 35 | 36 | export const GenuineHandlers: React.FC<{ args: string }> = ({ args = '' }) => { 37 | const [state, set] = React.useState({}) 38 | const [state2, set2] = React.useState('mouse not down') 39 | const [state3, set3] = React.useState('not clicked') 40 | 41 | const bind = useGesture({ 42 | onDrag: ({ event, cancel, ...rest }) => void set(rest), 43 | onMouseDown: ({ args }) => set2('mouse down ' + args[0]), 44 | onClick: ({ args }) => set3('clicked ' + args[0]) 45 | }) 46 | 47 | return ( 48 | // @ts-ignore 49 | 50 |
{state2}
51 |
{state3}
52 |
53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /test/components/Interactive.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Common, createHandlers } from './Common' 3 | import { useGesture } from '../../packages/react/src' 4 | import { InteractiveType } from './types' 5 | 6 | const Interactive: InteractiveType = ({ bindArgs = [], gestures, canceled, memoArg, config }) => { 7 | const [state, set] = React.useState({}) 8 | const [[startFired, endFired], setStartEnd] = React.useState([0, 0]) 9 | 10 | const bind: any = useGesture(createHandlers({ gestures, memoArg, set, setStartEnd, canceled }), config) 11 | const testKey = gestures.join('').toLowerCase() 12 | 13 | return ( 14 | 21 | ) 22 | } 23 | 24 | export default Interactive 25 | -------------------------------------------------------------------------------- /test/components/InteractiveDom.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Common, createHandlers } from './Common' 3 | import { useGesture } from '../../packages/react/src' 4 | import { InteractiveType } from './types' 5 | 6 | const InteractiveDom: InteractiveType = ({ gestures, canceled, memoArg, config, target }) => { 7 | const targetRef = React.useRef(null) 8 | const [state, set] = React.useState({}) 9 | const [[startFired, endFired], setStartEnd] = React.useState([0, 0]) 10 | 11 | useGesture(createHandlers({ gestures, memoArg, set, setStartEnd, canceled }), { 12 | ...config, 13 | target: target || targetRef 14 | }) 15 | 16 | const testKey = 'dom-' + gestures.join('').toLowerCase() 17 | 18 | return 19 | } 20 | 21 | export default InteractiveDom 22 | -------------------------------------------------------------------------------- /test/components/types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { UserGestureConfig } from '../../packages/core/src/types' 3 | 4 | interface Props { 5 | bindArgs?: any[] 6 | gestures: string[] 7 | cancel?: Function 8 | canceled?: boolean 9 | memoArg?: any 10 | config?: UserGestureConfig 11 | target?: EventTarget | React.RefObject 12 | } 13 | 14 | export type InteractiveType = React.FunctionComponent 15 | -------------------------------------------------------------------------------- /test/global.d.ts: -------------------------------------------------------------------------------- 1 | import 'jest-chain' 2 | -------------------------------------------------------------------------------- /test/utils.tsx: -------------------------------------------------------------------------------- 1 | export const later = (delay: number = 10) => new Promise((resolve) => setTimeout(resolve, delay)) 2 | 3 | export function patchCreateEvent(createEvent: any) { 4 | // patching createEvent 5 | for (let key in createEvent) { 6 | if (key.indexOf('pointer') === 0) { 7 | // @ts-ignore 8 | const fn = createEvent[key.replace('pointer', 'mouse')] 9 | if (!fn) continue 10 | // @ts-ignore 11 | createEvent[key] = function (type, { pointerId = 1, pointerType = 'mouse', ...rest } = {}) { 12 | const event = fn(type, rest) 13 | event.pointerId = pointerId 14 | event.pointerType = pointerType 15 | const eventType = event.type 16 | Object.defineProperty(event, 'type', { 17 | get: function () { 18 | return eventType.replace('mouse', 'pointer') 19 | } 20 | }) 21 | return event 22 | } 23 | } 24 | } 25 | } 26 | --------------------------------------------------------------------------------