Showing preview only (669K chars total). Download the full file or copy to clipboard to get everything.
Repository: taye/interact.js
Branch: main
Commit: d3d474610c11
Files: 287
Total size: 604.4 KB
Directory structure:
gitextract_w464gyf3/
├── .browserslistrc
├── .codeclimate.yml
├── .eslintignore
├── .eslintrc.cjs
├── .github/
│ ├── stale.yml
│ └── workflows/
│ ├── publish.yml
│ └── test.yml
├── .gitignore
├── .husky/
│ ├── .gitignore
│ └── pre-commit
├── .npmignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.json
├── .stylelintrc.cjs
├── .yarnrc
├── CHANGELOG.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── babel.config.cjs
├── bin/
│ ├── _add_plugin_indexes
│ ├── _bundle
│ ├── _check_deps
│ ├── _clean
│ ├── _link
│ ├── _lint
│ ├── _release
│ ├── _types
│ └── _version
├── bundle.rollup.config.cjs
├── docs/
│ ├── action-options.md
│ ├── auto-start.md
│ ├── draggable.md
│ ├── dropzone.md
│ ├── events.md
│ ├── faq.md
│ ├── gesturable.md
│ ├── inertia.md
│ ├── installation.md
│ ├── introduction.md
│ ├── migrating.md
│ ├── modifiers.md
│ ├── reflow.md
│ ├── resizable.md
│ ├── restriction.md
│ ├── snapping.md
│ └── tooling.md
├── esnext.rollup.config.cjs
├── examples/
│ ├── .eslintignore
│ ├── .eslintrc.cjs
│ ├── dropzones/
│ │ ├── index.css
│ │ ├── index.html
│ │ └── index.js
│ ├── events/
│ │ ├── index.css
│ │ ├── index.html
│ │ └── index.js
│ ├── iframes/
│ │ ├── bottom.html
│ │ ├── index.css
│ │ ├── index.html
│ │ ├── index.js
│ │ └── middle.html
│ ├── snap/
│ │ ├── index.css
│ │ ├── index.html
│ │ └── index.js
│ ├── sortable/
│ │ ├── index.html
│ │ ├── react.js
│ │ ├── shared.js
│ │ ├── style.css
│ │ └── vue.js
│ ├── star/
│ │ ├── index.css
│ │ └── index.js
│ ├── svg-editor/
│ │ ├── index.html
│ │ └── index.js
│ └── transform/
│ ├── index.html
│ └── index.js
├── jest.config.ts
├── lerna.json
├── package.json
├── packages/
│ ├── .eslintrc.cjs
│ ├── @interactjs/
│ │ ├── actions/
│ │ │ ├── README.md
│ │ │ ├── actions.spec.ts
│ │ │ ├── drag/
│ │ │ │ ├── drag.spec.ts
│ │ │ │ └── plugin.ts
│ │ │ ├── drop/
│ │ │ │ ├── DropEvent.spec.ts
│ │ │ │ ├── DropEvent.ts
│ │ │ │ ├── drop.spec.ts
│ │ │ │ └── plugin.ts
│ │ │ ├── gesture/
│ │ │ │ ├── gesture.spec.ts
│ │ │ │ └── plugin.ts
│ │ │ ├── package.json
│ │ │ ├── plugin.ts
│ │ │ └── resize/
│ │ │ ├── plugin.ts
│ │ │ └── resize.spec.ts
│ │ ├── auto-scroll/
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── auto-start/
│ │ │ ├── InteractableMethods.ts
│ │ │ ├── README.md
│ │ │ ├── autoStart.spec.ts
│ │ │ ├── base.ts
│ │ │ ├── dragAxis.ts
│ │ │ ├── hold.spec.ts
│ │ │ ├── hold.ts
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── core/
│ │ │ ├── BaseEvent.ts
│ │ │ ├── Eventable.spec.ts
│ │ │ ├── Eventable.ts
│ │ │ ├── InteractEvent.ts
│ │ │ ├── InteractStatic.ts
│ │ │ ├── Interactable.spec.ts
│ │ │ ├── Interactable.ts
│ │ │ ├── InteractableSet.ts
│ │ │ ├── Interaction.spec.ts
│ │ │ ├── Interaction.ts
│ │ │ ├── NativeTypes.ts
│ │ │ ├── PointerInfo.ts
│ │ │ ├── README.md
│ │ │ ├── events.ts
│ │ │ ├── interactablePreventDefault.spec.ts
│ │ │ ├── interactablePreventDefault.ts
│ │ │ ├── interactionFinder.spec.ts
│ │ │ ├── interactionFinder.ts
│ │ │ ├── interactions.spec.ts
│ │ │ ├── interactions.ts
│ │ │ ├── options.ts
│ │ │ ├── package.json
│ │ │ ├── scope.spec.ts
│ │ │ ├── scope.ts
│ │ │ ├── tests/
│ │ │ │ └── _helpers.ts
│ │ │ └── types.ts
│ │ ├── dev-tools/
│ │ │ ├── README.md
│ │ │ ├── babel-plugin-prod.js
│ │ │ ├── babel-plugin-prod.spec.ts
│ │ │ ├── devTools.spec.ts
│ │ │ ├── package.json
│ │ │ ├── plugin.ts
│ │ │ └── visualizer/
│ │ │ ├── plugin.stub.ts
│ │ │ ├── plugin.ts
│ │ │ ├── visualizer.spec.stub.ts
│ │ │ ├── visualizer.spec.ts
│ │ │ ├── vueModules.stub.ts
│ │ │ └── vueModules.ts
│ │ ├── inertia/
│ │ │ ├── README.md
│ │ │ ├── inertia.spec.ts
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── interact/
│ │ │ ├── README.md
│ │ │ ├── index.ts
│ │ │ ├── interact.spec.ts
│ │ │ └── package.json
│ │ ├── interactjs/
│ │ │ ├── index.stub.ts
│ │ │ ├── index.ts
│ │ │ └── package.json
│ │ ├── modifiers/
│ │ │ ├── Modification.ts
│ │ │ ├── README.md
│ │ │ ├── all.ts
│ │ │ ├── aspectRatio.spec.ts
│ │ │ ├── aspectRatio.ts
│ │ │ ├── avoid/
│ │ │ │ ├── avoid.stub.ts
│ │ │ │ └── avoid.ts
│ │ │ ├── base.spec.ts
│ │ │ ├── base.ts
│ │ │ ├── noop.ts
│ │ │ ├── package.json
│ │ │ ├── plugin.ts
│ │ │ ├── restrict/
│ │ │ │ ├── edges.spec.ts
│ │ │ │ ├── edges.ts
│ │ │ │ ├── pointer.spec.ts
│ │ │ │ ├── pointer.ts
│ │ │ │ ├── rect.ts
│ │ │ │ ├── size.spec.ts
│ │ │ │ └── size.ts
│ │ │ ├── rubberband/
│ │ │ │ ├── rubberband.stub.ts
│ │ │ │ └── rubberband.ts
│ │ │ ├── snap/
│ │ │ │ ├── edges.spec.ts
│ │ │ │ ├── edges.ts
│ │ │ │ ├── pointer.spec.ts
│ │ │ │ ├── pointer.ts
│ │ │ │ ├── size.spec.ts
│ │ │ │ └── size.ts
│ │ │ ├── spring/
│ │ │ │ ├── spring.stub.ts
│ │ │ │ └── spring.ts
│ │ │ ├── transform/
│ │ │ │ ├── transform.stub.ts
│ │ │ │ └── transform.ts
│ │ │ └── types.ts
│ │ ├── offset/
│ │ │ ├── offset.spec.ts
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── pointer-events/
│ │ │ ├── PointerEvent.spec.ts
│ │ │ ├── PointerEvent.ts
│ │ │ ├── README.md
│ │ │ ├── base.spec.ts
│ │ │ ├── base.ts
│ │ │ ├── holdRepeat.spec.ts
│ │ │ ├── holdRepeat.ts
│ │ │ ├── interactableTargets.ts
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── reflow/
│ │ │ ├── README.md
│ │ │ ├── package.json
│ │ │ ├── plugin.ts
│ │ │ └── reflow.spec.ts
│ │ ├── snappers/
│ │ │ ├── all.ts
│ │ │ ├── edgeTarget.stub.ts
│ │ │ ├── edgeTarget.ts
│ │ │ ├── elements.stub.ts
│ │ │ ├── elements.ts
│ │ │ ├── grid.ts
│ │ │ ├── package.json
│ │ │ └── plugin.ts
│ │ ├── types/
│ │ │ ├── README.md
│ │ │ ├── index.ts
│ │ │ ├── package.json
│ │ │ └── types.spec.ts
│ │ └── utils/
│ │ ├── ElementState.stub.ts
│ │ ├── ElementState.ts
│ │ ├── README.md
│ │ ├── arr.ts
│ │ ├── browser.ts
│ │ ├── center.ts
│ │ ├── clone.ts
│ │ ├── displace.stub.ts
│ │ ├── displace.ts
│ │ ├── domObjects.ts
│ │ ├── domUtils.spec.ts
│ │ ├── domUtils.ts
│ │ ├── exchange.stub.ts
│ │ ├── exchange.ts
│ │ ├── extend.ts
│ │ ├── getOriginXY.ts
│ │ ├── hypot.ts
│ │ ├── is.ts
│ │ ├── isNonNativeEvent.ts
│ │ ├── isWindow.ts
│ │ ├── misc.ts
│ │ ├── normalizeListeners.spec.ts
│ │ ├── normalizeListeners.ts
│ │ ├── package.json
│ │ ├── pointerExtend.ts
│ │ ├── pointerUtils.ts
│ │ ├── raf.ts
│ │ ├── rect.ts
│ │ ├── shallowEqual.ts
│ │ └── window.ts
│ └── interactjs/
│ ├── .npmignore
│ ├── LICENSE
│ ├── README.md
│ ├── bower.json
│ ├── index.ts
│ └── package.json
├── scripts/
│ ├── .eslintrc.cjs
│ ├── addPluginIndexes.js
│ ├── babel/
│ │ ├── absolute-imports.js
│ │ ├── inline-env-vars.js
│ │ ├── relative-imports.js
│ │ └── vue-sfc.js
│ ├── bin/
│ │ ├── _check_deps.js
│ │ ├── add_plugin_indexes.js
│ │ ├── bundle.js
│ │ ├── clean.js
│ │ ├── lint.js
│ │ ├── release.js
│ │ ├── types.js
│ │ └── version.js
│ ├── execTypes.js
│ ├── getVersion.js
│ ├── headers.js
│ └── utils.js
├── shims.d.ts
├── test/
│ ├── .eslintrc.cjs
│ └── fixtures/
│ ├── babelPluginProject/
│ │ ├── index.js
│ │ └── node_modules/
│ │ └── @interactjs/
│ │ └── a/
│ │ ├── a.js
│ │ ├── b/
│ │ │ ├── b.js
│ │ │ └── index.js
│ │ ├── package-main-file.js
│ │ └── package.json
│ └── dependentTsProject/
│ ├── index.ts
│ └── tsconfig.json
├── tsconfig.json
├── typedoc.config.cjs
├── types.tsconfig.json
├── vijest.config.js
└── vite.config.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .browserslistrc
================================================
defaults and fully supports es6-module
node >= 16
================================================
FILE: .codeclimate.yml
================================================
plugins:
eslint:
enabled: false
channel: eslint-6
extensions:
- .ts
- .js
duplication:
enabled: false
config:
languages:
- javascript
- typescript
ratings:
paths:
- "packages/**/*.ts"
exclude_paths:
- "**/examples/"
- "**/build/"
- "**/docs/"
- "**/_*"
- "**/*.spec.ts"
- "**/*.d.ts"
================================================
FILE: .eslintignore
================================================
dist
coverage
**/node_modules/**
_angular
================================================
FILE: .eslintrc.cjs
================================================
module.exports = {
extends: [
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript',
'plugin:react/all',
'standard',
'prettier',
],
settings: {
'import/resolver': { typescript: null },
react: { version: '16' },
},
env: {
commonjs: true,
es6: true,
node: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
},
plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc', 'markdown'],
globals: {
globalThis: false,
},
rules: {
'linebreak-style': ['error', 'unix'],
'lines-between-class-members': 'off',
'no-caller': 'error',
'no-console': 'off',
'no-empty': 'off',
'no-prototype-builtins': 'off',
'no-shadow': 'error',
'no-useless-constructor': 'off',
'no-var': 'error',
'import/no-extraneous-dependencies': ['error', { devDependencies: false }],
'import/order': [
'error',
{
alphabetize: { order: 'asc', caseInsensitive: true },
'newlines-between': 'always',
groups: ['builtin', 'external', 'internal', 'parent', 'index', 'sibling'],
pathGroups: [{ pattern: '@interactjs/**', group: 'internal' }],
},
],
'operator-linebreak': 'off',
'prefer-arrow-callback': ['error', { allowNamedFunctions: true }],
'prefer-const': 'error',
'standard/array-bracket-even-spacing': 'off',
'standard/computed-property-even-spacing': 'off',
'standard/object-curly-even-spacing': 'off',
'tsdoc/syntax': 'warn',
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/member-accessibility': 'off',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-use-before-define': 'off',
},
overrides: [
{
files: '*.{ts{,x},vue}',
rules: {
'import/named': 'off',
'import/no-named-as-default': 'off',
'import/no-unresolved': 'off',
'no-redeclare': 'off',
'no-shadow': 'off',
'no-undef': 'off',
'no-unused-vars': 'off',
'no-use-before-define': 'off',
},
},
{
files: '{,.md/}*.vue',
extends: ['plugin:vue/vue3-essential'],
parserOptions: { parser: '@typescript-eslint/parser' },
},
{
files: '*.spec.ts',
extends: ['plugin:jest/recommended', 'plugin:jest/style'],
rules: {
'array-bracket-spacing': 'off',
'import/no-extraneous-dependencies': 'off',
'jest/consistent-test-it': ['error', { fn: 'test' }],
},
},
{ files: '**/*.md', processor: 'markdown/markdown' },
{
files: '**/*.md/*.{{ts,js}{,x},vue}',
rules: {
'arrow-parens': 'off',
'import/no-named-as-default': 'off',
'import/no-unresolved': 'off',
'no-console': 'off',
'no-redeclare': 'off',
'no-shadow': 'off',
'no-undef': 'off',
'no-unused-vars': 'off',
'no-use-before-define': 'off',
'no-var': 'off',
'prefer-arrow-callback': 'off',
},
},
],
}
================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 14
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
only: issues
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
exemptProjects: true
================================================
FILE: .github/workflows/publish.yml
================================================
on:
push:
branches:
- main
- next
jobs:
test:
uses: ./.github/workflows/test.yml
publish-npm:
name: '📦 Build and Publish 🚀'
needs: [test]
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
registry-url: https://registry.npmjs.org/
cache: yarn
- name: ⚙ bootstrap
run: 'npm run bootstrap && git fetch --tags'
- name: 📦 build and publish 🚀
run: npx _release
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
================================================
FILE: .github/workflows/test.yml
================================================
on:
pull_request:
workflow_dispatch:
workflow_call:
jobs:
test:
name: '🧪 Test'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ianwalter/playwright-container@43940dfa7d309fe3569b9df407ae9e84dcbf2e7f
- name: ⚙ bootstrap
run: 'npm run bootstrap && npx _check_deps && npx _add_plugin_indexes'
- name: 📐 types
run: npx tsc -b -f
- name: 🔍 lint
run: npx _lint
- name: 🧪 tests
run: npm test
================================================
FILE: .gitignore
================================================
*.d.ts
*.d.ts.map
!interactjs/index.d.ts
!shims.d.ts
packages/@interactjs/**/index.ts
packages/@interactjs/*/use/**/*.ts
!packages/@interactjs/types/index.ts
!packages/@interactjs/interact/index.ts
!packages/@interactjs/interactjs/index.ts
!packages/@interactjs/rebound/index.ts
packages/**/*.js
packages/**/*.js.map
!packages/@interactjs/dev-tools/babel-plugin-prod.js
node_modules
!test/fixtures/**/node_modules
dist
.projectroot
.env
.envrc
.nyc_output
yarn-error.log
.yarn-cache
.pnpm-store
npm-debug.log
pnpm-debug.log
coverage
cc-test-reporter
lerna-debug.log
.vim
.cjsescache
================================================
FILE: .husky/.gitignore
================================================
_
================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged
================================================
FILE: .npmignore
================================================
*.ts
!*.d.ts
*.map.*
*.spec.ts
*.spec.js
dist/docs
guide
================================================
FILE: .npmrc
================================================
link-workspace-packages = true
shared-workspace-lockfile = true
prefer-frozen-lockfile = true
================================================
FILE: .nvmrc
================================================
v20.10.0
================================================
FILE: .prettierignore
================================================
dist
coverage
node_modules
================================================
FILE: .prettierrc.json
================================================
{
"printWidth": 110,
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}
================================================
FILE: .stylelintrc.cjs
================================================
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-recess-order', 'stylelint-config-css-modules'],
ignoreFiles: ['dist/**/*', 'coverage/**/*'],
}
================================================
FILE: .yarnrc
================================================
registry "https://registry.npmjs.org"
================================================
FILE: CHANGELOG.md
================================================
## v1.10.27
- fix(types): fix issues with `skipLibCheck: false`
## v1.10.26
- fix: improve build; check output for ES2018 compatibility
## v1.10.25
- fix: bundle to ES5 syntax
## v1.10.24
- chore: generate api docs
## v1.10.23
- fix: transform nullish coalescing; fix symbol-tree build
## v1.10.22
- fix(actions/gesture): fix error when inertia is enabled for gestures #995
## v1.10.21
- fix(actions/drop): fix regression with drop event targets #1016
## v1.10.20
- fix(types): import plugins for module augmentations #933
## v1.10.19
- fix(core/scope): remove duplicate Interactable super.unset
- fix(utils/pointerExtend): skip all vendor-prefixed props. Close #978
## v1.10.18
- fix(interact): remove types dependency
- fix: set "type": "module" for scoped packages
- fix(modifiers): allow toggling aspectRatio modifier during interaction
- fix(types): import plugins for module augmentations
- fix(interactjs): don't assign module.exports in esm package
## v1.10.17
- fixed missing typings when only the `@interactjs/interactjs` package is
installed and imported
- added index to vue package for installing with side effect import
## v1.10.16
- remove vue and react deps fron pro `@interactjs/interactjs` package
## v1.10.15
- fixed an issue with broken `@interactjs/types` #972
## v1.10.14
- fixed an issue with iframes on Webkit #942. Thanks, @tulps, for PR #943
- fixed top-right and bottom-left resizing with aspectRatio with sub-modifiers #944. Thanks again, @tulps, for PR #963
- fixed typings for `@itneractjs/` scoped module packages #933
- added `doubletap.double === true` event prop for consistency with `tap.double`
- fixed a bug with calling `interactable.unset()` in a `drop` listener #919
## v1.10.13
- Added `.d.ts` files to all `@interactjs/*` packages
## v1.10.12
- fixed incorrect behaviour when `interactable.unset()` is called multiple
times
## v1.10.11
- fixed incorrect "module" field in package.json https://github.com/taye/interact.js/issues/894#issuecomment-811046898
## v1.10.10
- fixed issue with unresolved stub files #894
- fixed commonjs import of `interactjs` package
## v1.10.9
- improved support for SSR environments
## v1.10.8
- fixed imports of missing modules #891
## v1.10.7
- correctly replace `process.env.npm_package_version` in min bundle #890
## v1.10.6
- fix packaging error
## v1.10.5
- fix packaging error
## v1.10.4
- fix NPE in indexOfDeepestElement if first element has no parent #887
- improve babel-plugin-prod on windows #885
## v1.10.3
- fixed issue with TS strict null checks #882
- fixed issue with type imports being emitted in JS modules #881
## v1.10.2
- marked interact.{on,off} methods as deprecated
## v1.10.1
- fixed mouseButtons option typings #865
- removed plugin index module warnings
## v1.10.0
- changed production files extension from '.min.js' to '.prod.js' #857
- added experimental `@interactjs/dev-tools/babel-plugin-prod` babel plugin to
change `@interactjs/*` imports to production versions
- added `sideEffects` fields to package.json files
## v1.9.22
- fixed inertia issue with arbitrary plugin order #834
- fixed inertia regression #853
## v1.9.21
- used findIndex polyfill to support 1E11 #852
- fixed issue where resize reflow increased element size #817
- fixed drop event order: fire `dropmove` after `dragenter` #841 and final
drop events before `dragend` #842
- updated docs #844 #829
## v1.9.20
- fixed ordering of plugins
## v1.9.19
- exposed `DropEvent` type
## v1.9.18
- fixed further issues with types
## v1.9.17
- fixed missing types for interactjs package
## v1.9.16
- fixed missing types for interactjs package
## v1.9.15
- fixed missing types for interactjs package
## v1.9.15
- fixed further regression breaking typescript builds #816
## v1.9.14
- fixed regression breaking typescript builds #816
## v1.9.13
- fixed regression breaking es5 compatibility of .min.js bundle #814
## v1.9.12
- fixed regression breaking commonjs imports withotu .default
## v1.9.11
- fixed issue with missing width/height on rectChecker result
- fixed resize checker with negative sizes
- moved generated plugin use modules to @interactjs/_/{use/,}_/index.ts #800
- changed snap function args to provide interaction proxy
- restored dev-tools helpers in development bundle
## v1.9.10
- fixed issue with uninitialized scope in non browser env #803
## v1.9.9
- fixed typescript issue #807
## v1.9.8
- fixed minified bundle #802
- fixed issue with removing delegated events #801
## v1.9.7
- fixed typing issues
## v1.9.6
- improved package dependencies
## v1.9.5
- made `core` and `utils` packages dependencies of `interact`
## v1.9.4
- restored `@interactjs/*/use/*.js*` builds
## v1.9.2
- fixed imports within generated modules
## v1.9.1
- added `@interactjs/*/use/*.min.js` builds
- fixed issue with webpack minifier #800
- fixed typescript issues
## v1.9.0
- added various `@interactjs/*/use` packages for simpler selective imports
#800
- fixed endOnly modifiers without inertia
## v1.8.5
- fixed a but causing incorrect modifications after resuming inertia #790
## v1.8.4
- fixed bug when calling interaction.move() from start event #791
## v1.8.3
- fixed bug when calling interaction.move() from start event #791
- fixed invalid non-array argument spread types #789
- fixed missing typescript definition of some interactable methods #788
- disabled `.d.ts.map` files output since the `.ts` source files are not
published
- fixed typings for modifiers
## v1.8.2
- enabled `.d.ts.map` files output
- added license field to @interactjs/interact package.json
## v1.8.1
- fixed an issue causing flickering a cursor on Firefox for Windows #781
## v1.8.0
Changes from prerelease versions listed below. See
https://github.com/taye/interact.js/projects/4#column-7093512 for a list of
issues and pull requests.
## v1.8.0-rc.3
- fixed incorrect publish
## v1.8.0-rc.2
- refactoring
## v1.8.0-rc.1
- fixed `interact.snappers.grid` arg typings
(https://twitter.com/ksumarine/status/1204457347856424960)
- removed "?" from definitions for interact.{modifiers,snappers,createSnapGrid}
## v1.8.0-rc.0
- fixed `modifiers.restrictSize` #779
- fixed option types in typescript and fixed devTools options #776
## v1.8.0-alpha.7
- reverted to typescript@3.6 to avoid backwards compatibility issues #775
## v1.8.0-alpha.6
- fixed dev scripts
## v1.8.0-alpha.5
- moved `interact.dynamicDrop` definition in order to avoid compilation errors
## v1.8.0-alpha.4
- added `main` field to interactjs package.json #774
- removed baseUrl from project tsconfig to avoid relative imports in generated
declarations
## v1.8.0-alpha.3
- added missing typescript declaration files
## v1.8.0-alpha.2
- used non relative imports in .ts files with correct config for
babel-plugin-bare-import-rewrite
## v1.8.0-alpha.1
- added `event.modifiers` array #772
## v1.8.0-alpha.0
- added `aspectRatio` modifier #638
## v1.7.4
- fixed `interact.snappers.grid` arg typings
(https://twitter.com/ksumarine/status/1204457347856424960)
- removed "?" from definitions for interact.{modifiers,snappers,createSnapGrid}
## v1.7.3
- fixed interactjs package main and browser fields #774
- reverted to typescript@3.6 to avoid backwards compatibility issues #775
## v1.7.2
- fixed typescript definition files #771
## v1.7.1
- reorganized modules for esnext resolution
## v1.7.0
- fixed hold repeat `event.count`
- added esnext js builds #769
## v1.6.3
- fixed issue with inertia resume with `endOnly: false` #765
## v1.6.2
- @mlucool added license field to package.json of sub modules #755
- added `rect`, `deltaRect` and `edges` to resizestart and resizeend events #754
## v1.6.1
- fixed resize without invert
## v1.6.0
- avoided accessing deprecated event.mozPressure #751
- changed typings to use `HTMLElement | SVGElement` for `event.target` #747
- added `interacting` arg to cursorChecker #739
- added zIndex compare for sibling dropzones
## v1.5.4
- fixed broken modifiers #746
## v1.5.3
- fixed issues with old modifiers API
## v1.5.2
- fixed null restriction issue #737
- improved typings for modifiers
## v1.5.1
- fixed typing issues #738
## v1.5.0
- added `cursorChecker` option for drag and resize #736
- allowed restrictions larger than the target element #735
- added `interact.modifiers.restrictRect` with pre-set elementRect #735
## v1.4.14
- fixed issue with string restriction values that don't resolve to a rect
#731
- changed plugin order so that `pointer-events` is installed before `inertia`
## v1.4.13
- fixed restrictSize min and max function restrictions
## v1.4.12
- fixed errors from calling `interaction.stop()` in start event #725
## v1.4.11
- fixed hold events #730
## v1.4.10
- fixed regression of preventing native drag behaviour #729
## v1.4.9
- fixed modifiers with inertia action-resume #728
- fixed docs for snap grid limits #717
## v1.4.8
- fixed exports in generated typings #727
## v1.4.7
- fixed exports in generated typings #726
## v1.4.6
- fixed pointerEvents currentTarget
## v1.4.5
- @0xflotus fixed typos in docs #724
- fixed error on iOS #682
## v1.4.4
- fixed an issue with interactions lingering on removed elements #723
## v1.4.3
- destroy only relevant interactions on interactable.unset()
## v1.4.2
- @jf-m fixed memory leaks and a bug on interactions stop [PR #715](https://github.com/taye/interact.js/pull/715)
- fixed dropzones in shadow DOM [PR #722](https://github.com/taye/interact.js/pull/722)
## v1.4.1
- fixed scripts to run bundle optimizations and fix issues with browserify
# v1.4.0
Most notablly:
- `interactable.reflow(action)` to re-run modifiers, drop, etc [PR #610](https://github.com/taye/interact.js/pull/610)
- `dropEvent.reject()` [PR #613](https://github.com/taye/interact.js/pull/613)
- snapEdges modifier [PR #620](https://github.com/taye/interact.js/pull/620)
- per-action modifiers array [PR #625](https://github.com/taye/interact.js/pull/625)
- autoStart set cursor on both target and <html> [PR #639](https://github.com/taye/interact.js/pull/639)
- inertia: rename resume event to `${action}resume`
- `interactable.reflow(action)` to re-run modifiers, drop, etc [PR #610](https://github.com/taye/interact.js/pull/610)
- added `options.listeners` array/object for actions
- `snapEdges` modifier [PR #620](https://github.com/taye/interact.js/pull/620)
- fixed iOS preventDefault passive event issue ([issue #631](https://github.com/taye/interact.js/issues/631))
- added `console.warn` messages for common, easily detected issues
- improved docs
- various fixes
Full list of [changes on Github](https://github.com/taye/interact.js/compare/1.3.4...v1.4.0).
## v1.3.3
- fixed issues with action options ([PR #567](https://github.com/taye/interact.js/pull/567), [issue #570](https://github.com/taye/interact.js/issues/570))
## v1.3.2
- fixed iOS preventDefault passive event issue ([issue #561](https://github.com/taye/interact.js/issues/561))
## v1.3.1
- allowed calling `draggable.unset()` during `dragend` and `drop` event
listeners ([issue #560](https://github.com/taye/interact.js/issues/560))
- allowed snap to be enabled with falsey targets value [issue #562](https://github.com/taye/interact.js/issues/562)
## v1.3.0
Most notably:
- changed the npm and bower package names to "interactjs" ([issue
#399](https://github.com/taye/interact.js/issues/399)
- major refactor with [PR #231](https://github.com/taye/interact.js/pull/231).
- removed deprecated methods:
- `Interactable`: `squareResize`, `snap`, `restrict`, `inertia`,
`autoScroll`, `accept`
- `interact`: `enabbleDragging`, `enableResizing`, `enableGesturing`,
`margin`
- new `hold` option for starting actions
- new `interaction.end()` method
([df963b0](https://github.com/taye/interact.js/commit/df963b0))
- `snap.offset` `self` option ([issue
#204](https://github.com/taye/interact.js/issues/204/#issuecomment-154879052))
- `interaction.doMove()`
([3489ee1](https://github.com/taye/interact.js/commit/3489ee1))
([c5c658a](https://github.com/taye/interact.js/commit/c5c658a))
- snap grid limits
([d549672](https://github.com/taye/interact.js/commit/d549672))
- improved iframe support ([PR
#313](https://github.com/taye/interact.js/pull/313))
- `actionend` event dx/dy are now `0`, not the difference between start and
end coords ([cbfaf00](https://github.com/taye/interact.js/commit/cbfaf00))
- replaced drag `axis` option with `startAxis` and `lockAxis`
- added pointerEvents options:
- `holdDuration`
([1c58f92](https://github.com/taye/interact.js/commit/1c58f927)),
- `ignoreFrom` and `allowFrom`
([6cbaad6](https://github.com/taye/interact.js/commit/6cbaad6d))
- `origin` ([7823bb9](https://github.com/taye/interact.js/commit/7823bb95))
- action events set with action method options (eg.
`target.draggable({onmove})` are removed when that action is disabled with a
method call ([cca4e26](https://github.com/taye/interact.js/commit/cca4e260))
- `context` option now works for Element targets
([8f64a7a](https://github.com/taye/interact.js/commit/8f64a7a4))
- added an action `mouseButtons` option and allowed actions only with the left
mouse button by default
([54ebdc3](https://github.com/taye/interact.js/commit/54ebdc3e))
- added repeating `hold` events
([fe11a8e](https://github.com/taye/interact.js/commit/fe11a8e5))
- fixed `Interactable.off` ([PR
#477](https://github.com/taye/interact.js/pull/477))
- added `restrictEdges`, `restrictSize` and `snapSize` resize modifiers ([PR
#455](https://github.com/taye/interact.js/pull/455))
Full list of [changes on Github](https://github.com/taye/interact.js/compare/v1.2.6...v1.3.0).
## 1.2.6
### resize.preserveAspectRatio
```javascript
interact(target).resizable({ preserveAspectRatio: true })
```
See [PR #260](https://github.com/taye/interact.js/pull/260).
### Deprecated
- `interact.margin(number)` - Use `interact(target).resizable({ margin: number });` instead
### Fixed
- incorrect coordinates of the first movement of every action ([5e5a040](https://github.com/taye/interact.js/commit/5e5a040))
- warning about deprecated "webkitForce" event property ([0943290](https://github.com/taye/interact.js/commit/0943290))
- bugs with multiple concurrent interactions ([ed53aee](http://github.com/taye/interact.js/commit/ed53aee))
- iPad 1, iOS 5.1.1 error "undefined is not a function" when autoScroll is set
to true ([PR #194](https://github.com/taye/interact.js/pull/194))
Full list of [changes on Github](https://github.com/taye/interact.js/compare/v1.2.5...v1.2.6)
## 1.2.5
### Changed parameters to actionChecker and drop.checker
- Added `event` as the first argument to actionCheckers. See commit [88dc583](https://github.com/taye/interact.js/commit/88dc583)
- Added `dragEvent` as the first parameter to drop.checker functions. See
commits [16d74d4](https://github.com/taye/interact.js/commit/16d74d4) and [d0c4b69](https://github.com/taye/interact.js/commit/d0c4b69)
### Deprecated methods
interactable.accept - instead, use:
```javascript
interact(target).dropzone({ accept: stringOrElement })
```
interactable.dropChecker - instead, use:
```javascript
interact(target).dropzone({ checker: function () {} })
```
### Added resize.margin
See https://github.com/taye/interact.js/issues/166#issuecomment-91234390
### Fixes
- touch coords on Presto Opera Mobile - see commits [886e54c](https://github.com/taye/interact.js/commit/886e54c) and [5a3a850](https://github.com/taye/interact.js/commit/5a3a850)
- bug with multiple pointers - see commit [64882d3](https://github.com/taye/interact.js/commit/64882d3)
- accessing certain recently deprecated event properties in Blink - see
commits [e91fbc6](https://github.com/taye/interact.js/commit/e91fbc6) and [195cfe9](https://github.com/taye/interact.js/commit/195cfe9)
- dropzones with `accept: 'pointer'` in scrolled pages on iOS6 and lower - see
commit [0b94aac](https://github.com/taye/interact.js/commit/0b94aac)
- setting styleCursor through Interactable options object - see [PR
#270](https://github.com/taye/interact.js/pull/270)
- one missed interaction element on stop triggered - see [PR
#258](https://github.com/taye/interact.js/pull/258)
- pointer dt on touchscreen devices - see [PR
#215](https://github.com/taye/interact.js/pull/215)
- autoScroll with containers with fixed position - see commit [3635840](https://github.com/taye/interact.js/commit/3635840)
- autoScroll for mobile - see #180
- preventDefault - see commits [1984c80](https://github.com/taye/interact.js/commit/1984c80) and [6913959](https://github.com/taye/interact.js/commit/6913959)
- occasional error - see [issue
#183](https://github.com/taye/interact.js/issue/183)
- Interactable#unset - see [PR
#178](https://github.com/taye/interact.js/pull/178)
- coords of start event after manual start - see commit [fec73b2](https://github.com/taye/interact.js/commit/fec73b2)
- bug with touch and selector interactables - see commit [d8df3de](https://github.com/taye/interact.js/commit/d8df3de)
- touch doubletap bug - see [273f461](https://github.com/taye/interact.js/commit/273f461)
- event x0/y0 with origin - see [PR
#167](https://github.com/taye/interact.js/pull/167)
## 1.2.4
### Resizing from all edges
With the new [resize edges API](https://github.com/taye/interact.js/pull/145),
you can resize from the top and left edges of an element in addition to the
bottom and right. It also allows you to specify CSS selectors, regions or
elements as the resize handles.
### Better `dropChecker` arguments
The arguments to `dropChecker` functions have been expanded to include the
value of the default drop check and some other useful objects. See [PR
161](https://github.com/taye/interact.js/pull/161)
### Improved `preventDefault('auto')`
If manuanStart is `true`, default prevention will happen only while
interacting. Related to [Issue
138](https://github.com/taye/interact.js/issues/138).
### Fixed inaccurate snapping
This removes a small inaccuracy when snapping with one or more
`relativeOffsets`.
### Fixed bugs with multiple pointers
## 1.2.3
### ShadowDOM
Basic support for ShadowDOM was implemented in [PR
143](https://github.com/taye/interact.js/pull/143)
### Fixed some issues with events
Fixed Interactable#on({ type: listener }). b8a5e89
Added a `double` property to tap events. `tap.double === true` if the tap will
be followed by a `doubletap` event. See [issue
155](https://github.com/taye/interact.js/issues/155#issuecomment-71202352).
Fixed [issue 150](https://github.com/taye/interact.js/issues/150).
## 1.2.2
### Fixed DOM event removal
See [issue 149](https://github.com/taye/interact.js/issues/149).
## 1.2.1
### Fixed Gestures
Gestures were completely [broken in
v1.2.0](https://github.com/taye/interact.js/issues/146). They're fixed now.
### Restriction
Fixed restriction to an element when the element doesn't have a rect (`display: none`, not in DOM, etc.). [Issue
144](https://github.com/taye/interact.js/issues/144).
## 1.2.0
### Multiple interactions
Multiple interactions have been enabled by default. For example:
```javascript
interact('.drag-element').draggable({
enabled: true,
// max : Infinity, // default
// maxPerElement: 1, // default
})
```
will allow multiple `.drag-element` to be dragged simultaneously without having
to explicitly set <code>max: integerGreaterThan1</code>. The default
`maxPerElement` value is still 1 so only one drag would be able to happen on
each `.drag-element` unless the `maxPerElement` is changed.
If you don't want multiple interactions, call `interact.maxInteractions(1)`.
### Snapping
#### Unified snap modes
Snap modes have been
[unified](https://github.com/taye/interact.js/pull/127). A `targets` array
now holds all the snap objects and functions for snapping.
`interact.createSnapGrid(gridObject)` returns a function that snaps to the
dimensions of the given grid.
#### `relativePoints` and `origin`
```javascript
interact(target).draggable({
snap: {
targets: [{ x: 300, y: 300 }],
relativePoints: [
{ x: 0, y: 0 }, // snap relative to the top left of the element
{ x: 1, y: 1 }, // and also to the bottom right
],
// offset the snap target coordinates
// can be an object with x/y or 'startCoords'
offset: { x: 50, y: 50 },
},
})
```
#### snap function interaction arg
The current `Interaction` is now passed as the third parameter to snap functions.
```js
interact(target).draggable({
snap: {
targets: [
function (x, y, interaction) {
if (!interaction.dropTarget) {
return { x: 0, y: 0 }
}
},
],
},
})
```
#### snap.relativePoints and offset
The `snap.relativePoints` array succeeds the snap.elementOriign object. But
backwards compatibility with `elementOrigin` and the old snapping interface is
maintained.
`snap.offset` lets you offset all snap target coords.
See [this PR](https://github.com/taye/interact.js/pull/133) for more info.
#### slight change to snap range calculation
Snapping now occurs if the distance to the snap target is [less than or
equal](https://github.com/taye/interact.js/commit/430c28c) to the target's
range.
### Inertia
`inertia.zeroResumeDelta` is now `true` by default.
### Per-action settings
Snap, restrict, inertia, autoScroll can be different for drag, restrict and
gesture. See [PR 115](https://github.com/taye/interact.js/pull/115).
Methods for these settings on the `interact` object (`interact.snap()`,
`interact.autoScroll()`, etc.) have been removed.
### Space-separated string and array event list and eventType:listener object
```javascript
function logEventType(event) {
console.log(event.type, event.target)
}
interact(target).on('down tap dragstart gestureend', logEventType)
interact(target).on(['move', 'resizestart'], logEventType)
interact(target).on({
dragmove: logEvent,
keydown: logEvent,
})
```
### Interactable actionChecker
The expected return value from an action checker has changed from a string to
an object. The object should have a `name` and can also have an `axis`
property. For example, to resize horizontally:
```javascript
interact(target)
.resizeable(true)
.actionChecker(function (pointer, defaultAction, interactable, element) {
return {
name: 'resize',
axis: 'x',
}
})
```
### Plain drop event objects
All drop-related events are [now plain
objects](https://github.com/taye/interact.js/issues/122). The related drag
events are referenced in their `dragEvent` property.
### Interactable.preventDefault('always' || 'never' || 'auto')
The method takes one of the above string values. It will still accept
`true`/`false` parameters which are changed to `'always'`/`'never'`.
## 1.1.3
### Better Events
Adding a function as a listener for an InteractEvent or pointerEvent type
multiple times will cause that function to be fired multiple times for the
event. Previously, adding the event type + function combination again had no
effect.
Added new event types [down, move, up, cancel,
hold](https://github.com/taye/interact.js/pull/101).
Tap and doubletap with multiple pointers was improved.
Added a workaround for IE8's unusual [dblclick event
sequence](http://www.quirksmode.org/dom/events/click.html) so that doubletap
events are fired.
Fixed a [tapping issue](https://github.com/taye/interact.js/issues/104) on
Windows Phone/RT.
Fixed a bug that caused the origins of all elements with tap listeners to be
subtracted successively as a tap event propagated.
[Fixed delegated events](https://github.com/taye/interact.js/commit/e972154)
when different contexts have been used.
### iFrames
[Added basic support](https://github.com/taye/interact.js/pull/98) for sharing
one instance of interact.js between multiplie windows/frames. There are still
some issues.
================================================
FILE: ISSUE_TEMPLATE.md
================================================
If you have questions about the [API](http://interactjs.io/api) that aren't answered in the [docs](http://interactjs.io/docs) or [FAQ](http://interactjs.io/docs/faq), try asking in the [Gitter chatroom](https://gitter.im/taye/interact.js) or on [Stackoverflow](https://stackoverflow.com/questions/tagged/interact.js).
If you've found something that looks like a bug, include a link to a minimal demo on [JSFilddle](https://jsfiddle.net), [Codepen](https://codepen.io) with instructions to reproduce the bug with and roughly follow the following issue description format:
### Expected behavior
Tell us what should happen
### Actual behavior
Tell us what happens instead
### System configuration
**interact.js version**:
**Browser name and version**:
**Operating System**:
================================================
FILE: LICENSE
================================================
Copyright (c) 2012-present Taye Adeyemi <dev@taye.me>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to
whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall
be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: PULL_REQUEST_TEMPLATE.md
================================================
Make sure to include tests in your pull request.
================================================
FILE: README.md
================================================
<a href="http://interactjs.io"><img alt="interact.js" src="https://c4d6f7d727e094887e93-4ea74b676357550bd514a6a5b344c625.ssl.cf2.rackcdn.com/ijs-solid.svg" height="70px" width="100%"></a>
<h2>
JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+).
</h2>
<div align="center">
<a href="https://gitter.im/taye/interact.js"><img src="https://badges.gitter.im/taye/interact.js.svg" alt="Gitter"></a>
<a href="https://www.jsdelivr.com/package/npm/interactjs"><img src="https://data.jsdelivr.com/v1/package/npm/interactjs/badge" alt="jsDelivr"></a>
<a href="https://github.com/taye/interact.js/actions/workflows/workflow.yml"><img src="https://github.com/taye/interact.js/actions/workflows/workflow.yml/badge.svg" alt="Build Status"></a>
<a href="https://codeclimate.com/github/taye/interact.js/test_coverage"><img src="https://api.codeclimate.com/v1/badges/0168aeaeed781a949088/test_coverage"/></a>
</div>
<br>
Features include:
- **inertia** and **snapping**
- **multi-touch**, simultaneous interactions
- cross browser and device, supporting the **desktop and mobile** versions of
Chrome, Firefox and Opera as well as **Internet Explorer 9+**
- interaction with [**SVG**](http://interactjs.io/#use_in_svg_files) elements
- being **standalone and customizable**
- **not modifying the DOM** except to change the cursor (but you can disable
that)
## Installation
- [npm](https://www.npmjs.org/): `npm install interactjs`
- [jsDelivr CDN](https://cdn.jsdelivr.net/npm/interactjs/): `<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>`
- [unpkg CDN](https://unpkg.com/interactjs/): `<script src="https://unpkg.com/interactjs/dist/interact.min.js"></script>`
- [Rails 5.1+](https://rubyonrails.org/):
1. `yarn add interactjs`
2. `//= require interactjs/interact`
- [Webjars SBT/Play 2](https://www.webjars.org/): `libraryDependencies ++= Seq("org.webjars.npm" % "interactjs" % version)`
### Typescript definitions
The project is written in Typescript and the npm package includes the type
definitions, but if you need the typings alone, you can install them with:
```
npm install --save-dev @interactjs/types
```
## Documentation
http://interactjs.io/docs
## Example
```javascript
var pixelSize = 16;
interact('.rainbow-pixel-canvas')
.origin('self')
.draggable({
modifiers: [
interact.modifiers.snap({
// snap to the corners of a grid
targets: [
interact.snappers.grid({ x: pixelSize, y: pixelSize }),
],
})
],
listeners: {
// draw colored squares on move
move: function (event) {
var context = event.target.getContext('2d'),
// calculate the angle of the drag direction
dragAngle = 180 * Math.atan2(event.dx, event.dy) / Math.PI;
// set color based on drag angle and speed
context.fillStyle = 'hsl(' + dragAngle + ', 86%, '
+ (30 + Math.min(event.speed / 1000, 1) * 50) + '%)';
// draw squares
context.fillRect(event.pageX - pixelSize / 2, event.pageY - pixelSize / 2,
pixelSize, pixelSize);
}
}
})
// clear the canvas on doubletap
.on('doubletap', function (event) {
var context = event.target.getContext('2d');
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
});
function resizeCanvases () {
[].forEach.call(document.querySelectorAll('.rainbow-pixel-canvas'), function (canvas) {
canvas.width = document.body.clientWidth;
canvas.height = window.innerHeight * 0.7;
});
}
// interact.js can also add DOM event listeners
interact(document).on('DOMContentLoaded', resizeCanvases);
interact(window).on('resize', resizeCanvases);
```
See the above code in action at https://codepen.io/taye/pen/tCKAm
## License
interact.js is released under the [MIT License](http://taye.mit-license.org).
[ijs-twitter]: https://twitter.com/interactjs
[upcoming-changes]: https://github.com/taye/interact.js/blob/main/CHANGELOG.md#upcoming-changes
================================================
FILE: babel.config.cjs
================================================
module.exports = {
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
}
================================================
FILE: bin/_add_plugin_indexes
================================================
#!/usr/bin/env node
require('../scripts/bin/add_plugin_indexes')
================================================
FILE: bin/_bundle
================================================
#!/usr/bin/env node
require('../scripts/bin/bundle')
================================================
FILE: bin/_check_deps
================================================
#!/usr/bin/env node
require('../scripts/bin/_check_deps')
================================================
FILE: bin/_clean
================================================
#!/usr/bin/env node
require('../scripts/bin/clean')
================================================
FILE: bin/_link
================================================
#!/bin/bash
ROOT=$(dirname $(dirname $(readlink -f $0)))
if [ -z "$ROOT" ]
then
ROOT=$(dirname $(dirname $0))
fi
modules_scope_dir=node_modules/@interactjs
modules_bin_dir=node_modules/.bin
mkdir -p $modules_scope_dir $modules_bin_dir
rm $modules_scope_dir/* 2> /dev/null
# link _dev package
ln -sf $ROOT $modules_scope_dir/_dev
# link all scoped packages from CWD
for package in $(cd packages/@interactjs && ls -d *); do
ln -sf ../../packages/@interactjs/$package $modules_scope_dir
done
# link all packages from this repo
for package in $(cd $ROOT/packages/@interactjs && ls -d *); do
ln -sf $ROOT/packages/@interactjs/$package $modules_scope_dir
done
# link all bins from this repo and from CWD
cd node_modules/.bin && ln -sf $ROOT/bin/* ../../bin/* .
================================================
FILE: bin/_lint
================================================
#!/usr/bin/env node
require('../scripts/bin/lint')
================================================
FILE: bin/_release
================================================
#!/usr/bin/env node
require('../scripts/bin/release')
================================================
FILE: bin/_types
================================================
#!/usr/bin/env node
require('../scripts/bin/types')
================================================
FILE: bin/_version
================================================
#!/usr/bin/env node
require('../scripts/bin/version')
================================================
FILE: bundle.rollup.config.cjs
================================================
/* eslint-disable import/no-extraneous-dependencies */
const { resolve } = require('path')
const babel = require('@rollup/plugin-babel')
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
const replace = require('@rollup/plugin-replace')
const terser = require('@rollup/plugin-terser')
const { defineConfig } = require('rollup')
const headers = require('./scripts/headers')
const { extendBabelOptions, getModuleDirectories, isPro } = require('./scripts/utils')
const globals = {
react: 'React',
vue: 'Vue',
}
const external = Object.keys(globals)
const INPUT_EXTENSIONS = ['.ts', '.tsx', '.vue']
module.exports = defineConfig(async () => {
const variations = [
{ env: { NODE_ENV: 'development' }, ext: '.js', minify: isPro },
{ env: { NODE_ENV: 'production' }, ext: '.min.js', minify: true },
]
return variations.map(({ minify, ext, env }) => {
const babelConfig = extendBabelOptions({
babelrc: false,
configFile: false,
browserslistConfigFile: false,
targets: { ie: 9 },
babelHelpers: 'bundled',
skipPreflightCheck: true,
extensions: INPUT_EXTENSIONS,
plugins: [[require.resolve('@babel/plugin-transform-runtime'), { helpers: false, regenerator: true }]],
})
return defineConfig({
input: resolve(__dirname, 'packages', 'interactjs', 'index.ts'),
external,
plugins: [
nodeResolve({
modulePaths: getModuleDirectories(),
extensions: INPUT_EXTENSIONS,
}),
commonjs({ include: '**/node_modules/{rebound,symbol-tree}/**' }),
babel(babelConfig),
replace({
preventAssignment: true,
values: Object.entries({
npm_package_version: process.env.npm_package_version,
IJS_BUNDLE: '1',
...env,
}).reduce((acc, [key, value]) => {
acc[`process.env.${key}`] = JSON.stringify(value)
return acc
}, {}),
}),
minify &&
terser({
module: false,
mangle: true,
compress: {
ecma: 5,
unsafe: true,
unsafe_Function: true,
unsafe_arrows: false,
unsafe_methods: true,
},
format: {
preamble: headers?.min,
},
}),
],
context: 'window',
moduleContext: 'window',
output: {
file: resolve(__dirname, 'packages', 'interactjs', 'dist', `interact${ext}`),
format: 'umd',
name: 'interact',
banner: minify ? headers.min : headers.raw,
minifyInternalExports: true,
inlineDynamicImports: true,
sourcemap: true,
globals,
},
})
})
})
================================================
FILE: docs/action-options.md
================================================
---
title: Action Options
---
The `Interactable` methods `draggable()`, `resizable()` and `gesturable()` are
used to enable and configure actions for target elements. They all have some
common options as well as some action-specific options and event properties.
Drag, resizem and gesture interactions fire `InteractEvent`s which have the
following properties common to all action types:
| InteractEvent property | Description |
| ------------------------ | ------------------------------------------------ |
| `target` | The element that is being interacted with |
| `interactable` | The Interactable that is being interacted with |
| `interaction` | The Interaction that the event belongs to |
| `x0`, `y0` | Page x and y coordinates of the starting event |
| `clientX0`, `clientY0` | Client x and y coordinates of the starting event |
| `dx`, `dy` | Change in coordinates of the mouse/touch |
| `velocityX`, `velocityY` | The Velocity of the pointer |
| `speed` | The speed of the pointer |
| `timeStamp` | The time of creation of the event object |
## Common Action Options
The Interactable methods `draggable`, `resizable` and `gesturable` take either
`true` or `false` to simply allow/disallow the action or an object with
properties to change certain settings.
### `max`
`max` is used to limit the number of concurrent interactions that can target an
interactable. By default, any number of interactions can target an
interactable.
### `maxPerElement`
By default only 1 interaction can target the same interactable+element
combination. If you want to allow multiple interactions on the same target
element, set the `maxPerElement` property of your object to a value `>= 2`.
### `manualStart`
If this is changed to `true` then drag, resize and gesture actions will have to
be started with a call to [`Interaction#start`][interaction-start] as the usual
`down`, `move`, `<action>start`... sequence will not start an action. See
[auto-start](/docs/auto-start).
### `hold`
The action will start after the pointer is held down for the given number of milliseconds.
### `inertia`
Change inertia settings for drag, and resize. See [docs/inertia](/docs/inertia).
### `styleCursor`
If the [auto-start](/docs/auto-start) feature is enabled, interact will style
the cursor of draggable and resizable elements as you hover over them.
```js
interact(target).styleCursor(false)
```
To disable this for all actions, set the `styleCursor` option to `false`
### `cursorChecker`
```js
interact(target)
.resizable({
edges: { left: true, right: true },
cursorChecker (action, interactable, element, interacting) {
// the library uses biderectional arrows <-> by default,
// but we want specific arrows (<- or ->) for each diriection
if (action.edges.left) { return 'w-resize' }
if (action.edges.right) { return 'e-resize' }
},
})
.draggable({
cursorChecker () {
// don't set a cursor for drag actions
return null
},
})
```
You can disable default cursors with `interact(target).styleCursor(false)`, but
that will disable cursor styling for all actions. To disable or change the
cursor for each action, you can set a `cursorChecker` function which takes info
about the current interaction and returns the CSS cursor value to set on the
target element.
### `autoScroll`
```javascript
interact(element)
.draggable({
autoScroll: true,
})
.resizable({
autoScroll: {
container: document.body,
margin: 50,
distance: 5,
interval: 10,
speed: 300,
}
})
```
Scroll a container (`window` or an HTMLElement) when a drag or resize move
happens at the edge of the container.
### `allowFrom` (handle)
```html
<div class="movable-box">
<div class="drag-handle" />
Content
<div class="resize-handle" />
</div>
```
```javascript
interact('.movable-box')
.draggable({
allowFrom: '.drag-handle',
})
.resizable({
allowFrom: '.resize-handle',
})
.pointerEvents({
allowFrom: '*',
})
```
The `allowFrom` option lets you specify a target CSS selector or Element which
must be the target of the pointer down event in order for the action to start.
This option available for drag, resize and gesture, as well as `pointerEvents`
(down, move, hold, etc.). Using the `allowFrom` option, you may specify handles
for each action separately and for all your pointerEvents listeners.
The `allowFrom` elements **must** be children of the target interactable
element. {.notice .info}
### `ignoreFrom`
```html
<div id="movable-box">
<p class="content">Selectable text</p>
<div no-pointer-event>Should not fire tap, hold, etc. events</div>
</div>
```
```javascript
var movable = document.querySelector('#movable-box')
interact(movable)
.draggable({
ignoreFrom: '.content',
onmove: function (event) {
/* ... */
}
})
.pointerEvents({
ignoreFrom: '[no-pointer-event]',
})
.on('tap', function (event) {
})
```
The compliment to `allowFrom`, `ignoreFrom` lets you specify elements within
your target with which to avoid starting actions. This is useful when certain
elements need to maintain default behavior when interacted with. For example,
dragging around a text/contentEditable, by wrapping this object with a
draggable element and ignoring the editable content you maintain the ability to
highlight text without moving the element.
### `enabled`
Enable the action for the Interactable. If the options object has no `enabled`
property or the property value is `true` then the action is enabled. If
`enabled` is false, the action is disabled.
[interaction-start]: /docs/auto-start
================================================
FILE: docs/auto-start.md
================================================
---
title: 'AutoStart (manualStart: false)'
---
The [pre-bundled](/docs/installation) package includes the `auto-start` plugin
which will start interactions when the pointer goes down and then moves on
enabled target elements. You can disable this for an action by setting the
`manualStart` option to `true`.
```js
interact(target)
.draggable({
manualStart: true,
})
.on('doubletap', function (event) {
var interaction = event.interaction
if (!interaction.interacting()) {
interaction.start(
{ name: 'drag' },
event.interactable,
event.currentTarget,
)
}
})
```
With `manualStart: true`, you will need to start the action from a pointer event
listener by calling `event.interaction.start(actionInfo)`. Because the library
no longer decides when to start actions, the cursor will not be set
automatically.
================================================
FILE: docs/draggable.md
================================================
---
title: Draggable
---
Dragging is the simplest action interact.js provides. To make an element
draggable, create an interactable with your desired target then call the
`draggable` method with the options that you need.
<LiveDemo :demoHtml="import('@/demos/draggable/basic.html?raw')" :removeNext="3" hide-demo-only />
```html
<div class="draggable">Draggable Element</div>
```
```css
.draggable {
touch-action: none;
user-select: none;
}
```
```js
const position = { x: 0, y: 0 }
interact('.draggable').draggable({
listeners: {
start (event) {
console.log(event.type, event.target)
},
move (event) {
position.x += event.dx
position.y += event.dy
event.target.style.transform = `translate(${position.x}px, ${position.y}px)`
},
},
})
```
In addition to the common [`InteractEvent`](/docs/events#interactevents)
properties, `dragmove` events also have:
| Drag event property | Description |
| ------------------- | ------------------------------------------------- |
| `dragEnter` | The dropzone this Interactable was dragged over |
| `dragLeave` | The dropzone this Interactable was dragged out of |
Remember to use CSS `touch-action: none` to prevent the browser from panning
when the user drags with a touch pointer, and `user-select: none` to disable
text selection. {.notice .info}
## `lockAxis` and `startAxis`
```javascript
// lock the drag to the starting direction
interact(singleAxisTarget).draggable({
startAxis: 'xy'
lockAxis: 'start'
});
// only drag if the drag was started horizontally
interact(horizontalTarget).draggable({
startAxis: 'x'
lockAxis: 'x'
});
```
There are two options for controlling the axis of drag actions: `startAxis` and
`lockAxis`.
`startAxis` sets the direction that the initial movement must be in for the
action to start. Use `'x'` to require the user to start dragging horizontally or
`'y'` to start dragging vertically.
`lockAxis` causes the drag events to change only in the given axis. If a value
of `'start'` is used, then the drag will be locked to the starting direction.
================================================
FILE: docs/dropzone.md
================================================
---
title: Dropzone
---
Dropzones define elements that draggable targets can be "dropped" into and which
elements will be accepted. Like with drag events, drop events don't modify the
DOM to re-parent elements. You will have to do this in your own event listeners
if you need this.
```javascript
interact(dropTarget)
.dropzone({
ondrop: function (event) {
alert(event.relatedTarget.id
+ ' was dropped into '
+ event.target.id)
}
})
.on('dropactivate', function (event) {
event.target.classList.add('drop-activated')
})
```
## Dropzone Events
Dropzone events are plain objects with the following properties:
| Property | Description |
| --------------- | ----------------------------------------------- |
| `target` | The dropzone element |
| `dropzone` | The dropzone Interactable |
| `relatedTarget` | The element that's being dragged |
| `draggable` | The Interactable that's being dragged |
| `dragEvent` | The related drag event – `drag{start,move,end}` |
| `timeStamp` | Time of the event |
| `type` | The event type |
```javascript
interact('.dropzone').dropzone({
accept: '.drag0, .drag1',
});
```
## `accept`
The dropzone `accept` option is a CSS selector or element which must match the
dragged element in order for drop events to be fired.
```javascript
interact(target).dropzone({
overlap: 0.25
});
```
The `overlap` option sets how drops are checked for. The allowed values are:
- `'pointer'` – the pointer must be over the dropzone (default)
- `'center'` – the draggable element's center must be over the dropzone
- a number from 0-1 which is the (intersection area) / (draggable area). e.g.
`0.5` for drop to happen when half of the area of the draggable is over the
dropzone
## `checker`
The `checker` option is a function that you set to additionally check if a
dragged element can be dropped into a dropzone.
```javascript
interact(target).dropzone({
checker: function (
dragEvent, // related dragmove or dragend
event, // Touch, Pointer or Mouse Event
dropped, // bool default checker result
dropzone, // dropzone Interactable
dropzoneElement, // dropzone element
draggable, // draggable Interactable
draggableElement // draggable element
) {
// only allow drops into empty dropzone elements
return dropped && !dropElement.hasChildNodes();
}
});
```
The checker function takes the following arguments:
| Arg | Description |
| ------------------ | --------------------------------------------------- |
| `dragEvent` | related dragmove or dragend event |
| `event` | The user move/up/end Event related to the dragEvent |
| `dropped` | The value from the default drop checker |
| `dropzone` | The dropzone interactable |
| `dropElement` | The dropzone element |
| `draggable` | The Interactable being dragged |
| `draggableElement` | The actual element that's being dragged |
================================================
FILE: docs/events.md
================================================
---
title: Events
---
## InteractEvents
<LiveDemo :demoHtml="import('@/demos/events/actions.html?raw')" :removeNext="3"/>
```html
<div>Drag, resize, or perform a multi-touch gesture</div>
```
```css
.target {
display: inline-block;
min-height: 3rem;
background-color: #29e;
color: white;
padding: 1rem;
border-radius: 0.75rem;
}
```
```javascript
function listener(event) {
event.target.textContent = `${event.type} at ${event.pageX}, ${event.pageY}`
}
interact(target)
.on('dragstart', listener)
.on('dragmove dragend', listener)
.on(['resizemove', 'resizeend'], listener)
.on({
gesturestart: listener,
gestureend: listener,
})
interact(target).draggable({
onstart: listener,
onmove: listener,
onend: listener,
})
interact(target).resizable({
listeners: [
{
start: function (event) {
console.log(event.type, event.pageX, event.pageY)
},
},
],
})
```
`InteractEvent`s are fired for different actions. The event types include:
- Draggable: `dragstart`, `dragmove`, `draginertiastart`, `dragend`
- Resizable: `resizestart`, `resizemove`, `resizeinertiastart`, `resizeend`
- Gesturable: `gesturestart`, `gesturemove`, `gestureend`
To respond to `InteractEvent`s, you must add listeners for the event types on an
interactable that's configured for that action. The event object that was
created is passed to these functions as the first and only parameter.
`InteractEvent` properties include the usual properties of mouse/touch events
such as `pageX/Y`, `clientX/Y`, modifier keys etc. but also some properties
providing information about the change in coordinates and event specific data.
The table below displays all of these events.
### Common
| Property | Description |
| ------------------------ | ------------------------------------------------ |
| `target` | The element that is being interacted with |
| `interactable` | The Interactable that is being interacted with |
| `interaction` | The Interaction that the event belongs to |
| `x0`, `y0` | Page x and y coordinates of the starting event |
| `clientX0`, `clientY0` | Client x and y coordinates of the starting event |
| `dx`, `dy` | Change in coordinates of the mouse/touch |
| `velocityX`, `velocityY` | The Velocity of the pointer |
| `speed` | The speed of the pointer |
| `timeStamp` | The time of creation of the event object |
### Drag
| Property | Description |
| ------------ | ------------------------------------------------- |
| **dragmove** | |
| `dragEnter` | The dropzone this Interactable was dragged over |
| `dragLeave` | The dropzone this Interactable was dragged out of |
### Resize
| Property | Description |
| ----------- | ------------------------------------------------- |
| `edges` | The edges of the element that are being changed |
| `rect` | An object with the new dimensions of the target |
| `deltaRect` | The change in dimensions since the previous event |
### Gesture
| Property | Description |
| ---------- | --------------------------------------------------------------------------------- |
| `distance` | The distance between the event's first two touches |
| `angle` | The angle of the line made by the two touches |
| `da` | The change in angle since previous event |
| `scale` | The ratio of the distance of the start event to the distance of the current event |
| `ds` | The change in scale since the previous event |
| `box` | A box enclosing all touch points |
In gesture events, page and client coordinates are the averages of touch
coordinates and velocity is calculated from these averages.
## Drop Events
```javascript
interact(dropTarget)
.dropzone({
ondrop: function (event) {
alert(event.relatedTarget.id + ' was dropped into ' + event.target.id)
},
})
.on('dropactivate', function (event) {
event.target.classList.add('drop-activated')
})
```
Dropzones can receive the following events: `dropactivate`, `dropdeactivate`,
`dragenter`, `dragleave`, `dropmove`, `drop`.
The dropzone events are plain objects with the following properties:
| Property | Description |
| --------------- | ----------------------------------------------- |
| `target` | The dropzone element |
| `dropzone` | The dropzone Interactable |
| `relatedTarget` | The element that's being dragged |
| `draggable` | The Interactable that's being dragged |
| `dragEvent` | The related drag event – `drag{start,move,end}` |
| `timeStamp` | Time of the event |
| `type` | The event type |
## Pointer Events
```javascript
interact(target).on('hold', function (event) {
console.log(event.type, event.target)
})
```
- `down`
- `move`
- `up`
- `cancel`
- `tap`
- `doubletap`
- `hold`
I call these `pointerEvents` (with a lower case "p") because they present the
events roughly as the real `PointerEvent` interface does, specifically:
- `event.pointerId` provides the `TouchEvent#identifier` or
`PointerEvent#pointerId` or `undefined` for MouseEvents
- `event.pointerType` provides the pointer type
- There are no simulated mouse events after touch events
The properties of the events may vary across browsers and devices depending on
which event interfaces are supported. For Example, a `down` event from a
`touchstart` will not provide tilt or pressure as specified in the
`PointerEvent` interface. {.notice .info}
### Configuring pointer events
```javascript
interact(target).pointerEvents({
holdDuration: 1000,
ignoreFrom: '[no-pointer]',
allowFrom: '.handle',
origin: 'self',
})
```
`pointerEvent`s are not snapped or restricted, but can be modified with the
origin modifications. `tap` events have a `dt` property which is the time
between the related `down` and `up` events. For `doubletap` `dt` is the time
between the two previous taps. `dt` for `hold` events is the length of time
that the pointer has been held down for (around 600ms).
### Fast click
```javascript
// fast click
interact('a[href]').on('tap', function (event) {
window.location.href = event.currentTarget.href
event.preventDefault()
})
```
`tap` and `doubletap` don't have the delay that `click` events have on mobile
devices so it works great for fast buttons and anchor links. Also, unlike
regular click events, a tap isn’t fired if the pointer is moved before being
released.
================================================
FILE: docs/faq.md
================================================
---
title: FAQ
---
This page contains questions and issues that are frequently raised on [Gitter
chat][gitter] and [Github issues][gh-issues].
## Start action after hold
Use the `hold` option which takes the number of milliseconds that the pointer
must be held down for.
```javascript
interact(target)
.draggable({
// start dragging after the pointer is held down for 1 second
hold: 1000
})
```
If you are having problems with default browser behaviour like scrolling,
context menus, etc. have a look at the
[`Interactable#preventDefault`][prevent-default] method and this [thread on
Github](https://github.com/taye/interact.js/issues/138).
## Clone target draggable
```html
<div class="item"></div>
```
```javascript
interact('.item')
.draggable({ manualStart: true })
.on('move', function (event) {
var interaction = event.interaction
// if the pointer was moved while being held down
// and an interaction hasn't started yet
if (interaction.pointerIsDown && !interaction.interacting()) {
var original = event.currentTarget,
// create a clone of the currentTarget element
clone = event.currentTarget.cloneNode(true)
// insert the clone to the page
// TODO: position the clone appropriately
document.body.appendChild(clone)
// start a drag interaction targeting the clone
interaction.start({ name: 'drag' }, event.interactable, clone)
}
})
```
There's no direct API to drag a clone of the target element. However, you can
use [`Interaction#start`][interaction-start] to change the target of an
interaction to any element that you create.
## Remove / destroy / release
```javascript
interact(target).draggable(true).resizable(true)
interact.isSet(target) // true
interact(target).unset()
interact.isSet(target) // false
interact(target).draggable() // false
interact(target).resizable() // false
```
To remove an Interactable, use `interact(target).unset()`. That should remove
all event listeners and make interact.js forget completely about the target.
## Changing dropzones while dragging
```javascript
interact.dynamicDrop(true)
```
If you're adding or removing dropzone elements or changing their dimensions
while dragging, you may need to change the [`dynamicDrop`][dynamic-drop] setting
to true so that the dropzones rects are recalculated after every `dragmove`.
## Drag handle
```html
<div class="item">
A draggable item
<div class="handle">Handle</div>
</div>
```
```javascript
interact('.item').draggable({
allowFrom: '.handle',
})
```
To make an element be the handle of a parent draggable, use the allowFrom
setting option to allow an action to start only if the element matches a
certain CSS selector or is a specific element.
## Prevent actions on child
```html
<div class="resizable">
A resizable item
<textarea></textarea>
</div>
```
```javascript
interact('.item')
.draggable({
// don't drag from textarea elments
ignoreFrom: 'textarea',
});
```
Use the `ignoreFrom` option to prevent actions from starting if the pointer
went down on an element matching the given selector or HTMLElement.
## Revert / restore / undo drag position
There's no direct API to revert a dragged element to it's position before the
drag. To do this, you must store the position at `dragstart` and change the
element's style so that it returns to the start position on `dragend`. You can
use CSS transitions to animate change in position.
## Dragging scrolls instead
```css
.draggable, .resizable, .gesturable {
-ms-touch-action: none;
touch-action: none;
user-select: none;
}
```
To allow touch interactions without scrolling or zooming, use the [`touch-action` CSS
property][touch-action].
## Dragging between iFrames
There is [limited support][iframe-pr] for using interact.js across iFrames. There are
currently browser inconsistencies and other issues which have yet to be
addressed.
[gitter]: https://gitter.im/taye/interact.js
[gh-issues]: https://github.com/taye/interact.js/issues
[manual-start]: /docs#manualstart
[interaction-start]: /api/Interaction.html#start
[prevent-default]: /api/Interactable.html#preventDefault
[dynamic-drop]: /api/module-interact.html#.dynamicDrop
[touch-action]: https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action
[iframe-pr]: https://github.com/taye/interact.js/pull/98
================================================
FILE: docs/gesturable.md
================================================
---
title: Gesturable
---
```html
<div id="rotate-area">
<div id="angle-info">0°</div>
<svg id="arrow" viewbox="0 0 100 100">
<polygon points="50,0 75,25 62.5,25 62.5,100 37.5,100 37.5,25 25,25" fill="#29e"></polygon>
</svg>
</div>
```
```css
.draggable {
touch-action: none;
user-select: none;
}
```
```js
var angle = 0
interact('#rotate-area').gesturable({
onmove: function (event) {
var arrow = document.getElementById('arrow')
angle += event.da
arrow.style.webkitTransform =
arrow.style.transform =
'rotate(' + angle + 'deg)'
document.getElementById('angle-info').textContent =
angle.toFixed(2) + '\u00b0'
},
})
```
Gesture events are triggered when two pointers go down and are moved. In
gesture events, page and client coordinates are the averages of touch
coordinates and velocity is calculated from these averages. The events also have
the following properties:
| Gesture Event property | Description |
| ---------------------- | --------------------------------------------------------------------------------- |
| `distance` | The distance between the event's first two touches |
| `angle` | The angle of the line made by the two touches |
| `da` | The change in angle since previous event |
| `scale` | The ratio of the distance of the start event to the distance of the current event |
| `ds` | The change in scale since the previous event |
| `box` | A box enclosing all touch points |
Remember to use CSS `touch-action: none` to prevent the browser from panning
when the user drags with a touch pointer, and `user-select: none` to disable
text selection. {.notice .info}
================================================
FILE: docs/inertia.md
================================================
---
title: Inertia
---
```javascript
interact(target)
.draggable({
inertia: true
})
.resizable({
inertia: {
resistance: 30,
minSpeed: 200,
endSpeed: 100
}
})
```
Inertia allows drag and resize actions to continue after the user releases the
pointer at a fast enough speed. The required launch speed, end speed and
resistance can optionally be configured with the settings below.
If an action ends without inertia but is snapped or restricted with the
`endOnly` option, then the the coordinates are interpolated from the end coords
to the snapped/restricted coords.
## Options
- **`resistance`** is a number greater than zero which sets the rate at which
the action slows down. Higher values slow it down more quickly.
- **`endSpeed`** is the speed (pixels per second) at which the action is
considered to have stopped.
- **`allowResume`** is a `boolean` value which indicates whether the user
should be allowed to resume an action while it is in the inertia phase.
- **`smoothEndDuration`** is the duration (milliseconds) of the interpolated
movement from the actual end coords to the modified coords with `endOnly`.
Set the value to `0` to disable end transitions with `endOnly` snap/restrict.
When inertia is resumed, the difference between the start and resume coordinates
relative to the target's top left corner, isn't reflected in the next
`{action}move` events. Instead, an `{action}resume` event is fired when the
pointer goes back down during inertia before regular "{action}move" events are
fired again. If you need the difference in coords, you should listen to this
event and respond to it as you would to an `{action}move` event.
================================================
FILE: docs/installation.md
================================================
---
title: Installation
---
interact.js offers two sets of free packages that you can add to your project:
1. To get started quickly, you can use the package named `interactjs` on npm.
This package contains all the features of the library as an _ES5 bundled_.
2. If you'd like to keep your JS payload small, there are npm packages under
the `@interactjs/` scope which let you choose which features to include.
These packages are distributed as _ES6 modules_ and may need to be
transpiled for older browsers.
### npm pre-bundled
```sh
# install pre-bundled package with all features
$ npm install --save interactjs
```
```js
// es6 import
import interact from 'interactjs'
```
```js
// or if using commonjs or AMD
const interact = require('interactjs')
```
To use the pre-bundled package with [npm](https://docs.npmjs.com/about-npm/),
install the package as a dependency with `npm install interactjs` then import or
require the package in your JavaScript files.
### CDN pre-bundled
```html
<script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
<!-- or -->
<script src="https://unpkg.com/interactjs/dist/interact.min.js"></script>
```
You can also use the [jsDelivr](https://www.jsdelivr.com/package/npm/interactjs)
or [unpkg](https://unpkg.com/interactjs) CDNs by adding a `<script>` tag
pointing to their servers.
`interact` is exposed as a CommonJS module, an AMD module, or a global variable
depending on what the environment supports.
```sh
# install just the type definitions
$ npm install --save-dev @interactjs/types
```
If you're using the library only through a CDN and want the TypeScript type
definitions for development, you can install the `@interactjs/types` package as
a dev dependency.
### npm streamlined
```sh
# install only the features you need
$ npm install --save @interactjs/interact \
@interactjs/auto-start \
@interactjs/actions \
@interactjs/modifiers \
@interactjs/dev-tools
```
```js
import '@interactjs/auto-start'
import '@interactjs/actions/drag'
import '@interactjs/actions/resize'
import '@interactjs/modifiers'
import '@interactjs/dev-tools'
import interact from '@interactjs/interact'
interact('.item').draggable({
listeners: {
move (event) {
console.log(event.pageX, event.pageY)
},
},
})
```
For a more streamlined JS payload, you can install and import the package for
each feature you need:
| Package name | Description |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `@interactjs/interact` | **(required)** provides the `interact()` method |
| [`@interactjs/actions`](action-options) | Drag, resize, gesture actions |
| [`@interactjs/auto-start`](auto-start) | Start actions with pointer down, move sequence |
| [`@interactjs/modifiers`](modifiers) | Snap, restrict, etc. modifiers |
| `@interactjs/snappers` | Provides `interact.snappers.grid()` utility |
| [`@interactjs/inertia`](inertia) | Drag and resize inertia-like throwing |
| [`@interactjs/reflow`](reflow) | `interactable.reflow(action)` method to trigger modifiers and event listeners |
| [`@interactjs/dev-tools`](tooling#interactjsdev-tools) | Console warnings for common mistakes (optimized out when `NODE_ENV === 'production'`) and a babel plugin for optimized production builds |
### CDN streamlined
```html
<script type="module">
import 'https://cdn.interactjs.io/v1.9.20/auto-start/index.js'
import 'https://cdn.interactjs.io/v1.9.20/actions/drag/index.js'
import 'https://cdn.interactjs.io/v1.9.20/actions/resize/index.js'
import 'https://cdn.interactjs.io/v1.9.20/modifiers/index.js'
import 'https://cdn.interactjs.io/v1.9.20/dev-tools/index.js'
import interact from 'https://cdn.interactjs.io/v1.9.20/interactjs/index.js'
interact('.item').draggable({
onmove(event) {
console.log(event.pageX, event.pageY)
},
})
</script>
```
The packages above are also available on
`https://cdn.interactjs.io/v[VERSION]/[UNSCOPED_NAME]`. You can import them in
modern browser which support ES6 `import`s.
### Ruby on Rails
[Rails 5.1+](https://rubyonrails.org/) supports the [yarn](http://yarnpkg.com/)
package manager, so you can add interact.js to you app by running `yarn add interactjs`. Then require the library with:
```rb
//= require interactjs/interact
```
================================================
FILE: docs/introduction.md
================================================
---
title: Introduction
---
## What is interact.js?
interact.js is a JavaScript library for drag and drop, resizing and multi-touch
gestures for modern browsers. Its free and open source version comes with
powerful options like inertia and modifiers for snapping and restricting.
The library's aim is to **present pointer input data consistently** across
different browsers and devices and provide convenient ways to **pretend that the
user's pointer moved in a way that it wasn't really moved** (snapping, inertia,
etc.).
Note that by default **interact.js doesn't move elements for you**. Styling an
element so that it moves while a drag happens has to be done from your own event
listeners. This way, you’re in control of everything that happens.
<div class="notice"> 🌟 If you prefer to have feedback out-of-the-box, have
a look at <a href="/pro">interact.js Pro</a>. It comes with built-in hardware
accelerated feedback, list reordering, spring physics, Vue & React components
and more.
<div class="has-text-centered notice-cta">
<a href="/pro" class="button is-medium is-info has-text-white">Get Pro</a>
</div>
</div>
## Getting Started
After [installing the library](/docs/installation), the basic steps to setting
up your targets and interactions are:
1. Create an `Interactable` target.
2. Configure it to enable actions and add [modifiers](/docs/modifiers),
[inertia](/docs/inertia), etc.
3. Add event listeners to provide visual feedback and update your app's state.
For example, here's some code for [a very simple slider
input](https://codepen.io/taye/pen/GgpxNq):
<LiveDemo :demoHtml="import('@/demos/slider.html?raw')" :removeNext="1"/>
```js
// Step 1
const slider = interact('.slider') // target elements with the "slider" class
slider
// Step 2
.draggable({ // make the element fire drag events
origin: 'self', // (0, 0) will be the element's top-left
inertia: true, // start inertial movement if thrown
modifiers: [
interact.modifiers.restrict({
restriction: 'self', // keep the drag coords within the element
}),
],
})
// Step 3
.on('dragmove', function (event) { // call this listener on every dragmove
const sliderWidth = interact.getElementRect(event.target.parentNode).width
const value = event.pageX / sliderWidth
event.target.style.paddingLeft = (value * 100) + '%'
event.target.setAttribute('data-value', value.toFixed(2))
})
```
The `interact` function takes an element or a CSS selector string and returns an
`Interactable` object which has various methods to configure actions and event
listeners. Pointer interactions of down → move → up sequences begin drag,
resize, or gesture actions. By adding event listener functions for these action,
you can respond to `InteractEvent`s which provide pointer coordinates, speed,
element size, etc.
## Actions
interact.js supports 3 basic action types which are triggered by pointer down →
move → up sequences:
- [Draggable](/docs/draggable) for moving elements or drawing on a canvas.
This can be combined with [dropzones](/docs/dropzone) to implement drag and
drop applications.
- [Resizable](/docs/resizable) for watching the size and position of an
element while the pointer is used to move one or two of the element's edges.
- [Gesturable](/docs/gesturable) for 2-finger gestures with angle, scale, etc.
data.
Pro builds on the draggable action to provide [Sortable and
Swappable](/docs/sortable) feature for drag and drop rearranging of lists of
elements.
================================================
FILE: docs/migrating.md
================================================
---
title: Migrating from v1.2
---
The latest versions fix several bugs, allows setting more options on a
per-action basis, add configuration options to `pointerEvents` and add several
new methods and options. The [changelog][changelog] lists all the major changes.
### Per-action modifiers array
Modifiers are now created with `interact.modifiers[modifierName](options)`
methods. The return values returned by these methods go into the
`actionOptions.modifiers` array. The lets you more easily reuse modifier
configurations and specify their execution order.
```js
// create a restrict modifier to prevent dragging an element out of its parent
const restrictToParent = interact.modifiers.restrict({
restriction: 'parent',
elementRect: { left: 0, right: 0, top: 1, bottom: 1 },
})
// create a snap modifier which changes the event coordinates to the closest
// corner of a grid
const snap100x100 = interact.modifiers.snap({
targets: [interact.snappers.grid({ x: 100, y: 100 })],
relativePoints: [{ x: 0.5, y: 0.5 }],
})
interact(target)
.draggable({
// apply the restrict and then the snap modifiers to drag events
modifiers: [restrictToParent, snap100x100],
})
.on('dragmove', event => console.log(event.pageX, event.pageY))
```
### Improved resize snap and restrict
There are a few new snap and restrict modifiers for resize actions:
[Restrictions](/docs/restriction):
- pointer coordinate-based `restrict`
- element rect-based restriction `restrictRect`
- element size-based `restrictSize` (resize only)
- and element edge-based `restrictEdges` (resize only)
[Snapping](/docs/snapping):
- pointer coordinate-based `snap` which is best suited to drag actions,
- `snapSize` which works only on resize actions and let's you set targets for
the size of the target element,
- and `snapEdges` which is similar to `snapSize`, but let's you set the target
positions of the edges of the target element.
```js
interact(target).resize({
edges: { bottom: true, right: true },
// sizes at fixed grid points
snapSize: {
targets: [
interact.snappers.grid({ x: 25, y: 25, range: Infinity }),
],
},
// minimum size
restrictSize: {
min: { width: 100, height: 50 },
},
// keep the edges inside the parent
restrictEdges: {
outer: 'parent',
endOnly: true,
},
})
```
### Resize `aspectRatio` modifier
The resize `preserveAspectRatio` and `square` options have been replaced by an
`aspectRatio` modifier which can cooperate with other modifiers.
```js
interact(target).resizable({
edges: { left: true, bottom: true },
modifiers: [
interact.modifiers.aspectRatio({
// ratio may be the string 'preserve' to maintain the starting aspect ratio,
// or any number to force a width/height ratio
ratio: 'preserve',
// To add other modifiers that respect the aspect ratio,
// put them in the aspectRatio.modifiers array
modifiers: [interact.modifiers.restrictSize({ max: 'parent' })],
}),
],
})
```
```js
interact(target).resizable({
modifiers: [
interact.modifiers.aspectRatio({
// The equalDelta option replaces the old resize.square option
equalDelta: true,
}),
],
})
```
### Removed Methods
The methods in the table below were removed and replaced with action method
options and modifier methods for the new modifiers array API:
| Method | Replaced with |
| ---------------------------------------------------------- | ------------------------------------------------------ |
| `interactable.squareResize(bool)` | `interact.modifiers.aspectRatio({ equalDelta: true })` |
| `interactable.snap({ actions: ['drag'], ...snapOptions })` | `interact.modifiers.snap(snapOptions)` |
| `interactable.restrict(restrictOptions)` | `interact.modifiers.restrict(restrictOptions)` |
| `interactable.inertia(true)` | `interactable.draggable({ inertia: true })` |
| `interactable.accept('.can-be-dropped')` | `interactable.dropzone({ accept: '.can-be-dropped' })` |
| `interact.margin(50)` | `interactable.resizable({ margin: 50 })` |
### Action end event dx/dy
The `dx` and `dy` fields on `dragend`, `resizeend` and `gestureend` events were
formally the difference between the start and end coordinates. Now they are
always `0` (the difference between the end and the last move event). Use
`event.X0` and `event.Y0` (or `event.clientX0` and `event.clientY0`) to get the
starting coordinates and subtract them from the end event coordinates.
```js
interact(target).draggable({
onend: function (event) {
console.log(event.pageX - event.X0, event.pageY - event.Y0)
},
})
```
### Drop events
`dragend` events are now fired _before_ `drop` events. Use
`dragendEvent.relatedTarget` to get the dropzone element if there will be a drop
event.
### Mouse buttons
By default, only the left mouse button can start actions. The `mouseButtons`
action option can be used to change this.
[changelog]: https://github.com/taye/interact.js/blob/master/CHANGELOG.md
================================================
FILE: docs/modifiers.md
================================================
---
title: Modifiers
---
```js
// create a restrict modifier to prevent dragging an element out of its parent
const restrictToParent = interact.modifiers.restrict({
restriction: 'parent',
elementRect: { left: 0, right: 0, top: 1, bottom: 1 },
})
// create a snap modifier which changes the event coordinates to the closest
// corner of a grid
const snap100x100 = interact.modifiers.snap({
targets: [interact.snappers.grid({ x: 100, y: 100 })],
relativePoints: [{ x: 0.5, y: 0.5 }],
})
interact(target)
.draggable({
// apply the restrict and then the snap modifiers to drag events
modifiers: [restrictToParent, snap100x100],
})
.on('dragmove', event => console.log(event.pageX, event.pageY))
```
`interact`'s `modifiers` let you change the coordinates of action events. The
options object passed to action methods can have a `modifiers` array which will
be applied to events of that action type. **Modifiers in the array are applied
sequentially** and their order may affect the final result.
```js
const snapAtEnd = interact.modifiers.snap({
endOnly: true,
targets: [/* ... */],
})
```
Modifiers can be set to apply only to the last move event in an interaction by
setting their `endOnly` option to `true`. When an `endOnly` modifier is used
with an action that has `inertia` enabled, the event coordinates will be
smoothly moved from the up coords to the modified coords.
interact.js comes with a vew different types of modifiers for
[snapping](/docs/snapping) and [restricting](/docs/restriction) elements.
================================================
FILE: docs/reflow.md
================================================
---
title: Reflow
---
The reflow method lets you trigger an action start -> move -> end sequence which
runs modifiers and does drop calculations, etc. If your interactable target is a
CSS selector, an interaction will be run for each matching element.
<LiveDemo :demoHtml="import('@/demos/reflow.html?raw')"/>
If the elements have inertia, `endOnly` modifiers and `smoothEndDuration`, then
the interactions may not end immediately. The reflow method returns a `Promise`
which is resolved when all interactions are complete. So you can `await` or
`.then()` multiple reflows
```js
const interactable = interact(target).draggable({}).resizable({})
async function onWindowResize () {
// start a resize action and wait for inertia to finish
await interactable.reflow({ name: drag, axis: 'x' })
// start a drag action
await interactable.reflow({
name: 'resize',
edges: { left: true, bottom: true },
})
}
window.addEventListener(onWindowResize, 'resize')
```
================================================
FILE: docs/resizable.md
================================================
---
title: Resizable
---
```javascript
interact(target)
.resizable({
edges: {
top : true, // Use pointer coords to check for resize.
left : false, // Disable resizing from left edge.
bottom: '.resize-s',// Resize if pointer target matches selector
right : handleEl // Resize if pointer target is the given Element
}
})
```
Resize events have `rect` and `deltaRect` properties. `rect` is updated on each
`resizemove` event and the values in `deltaRect` reflect the changes. In
`resizestart`, `rect` will be identical to the rect returned by
`interactable.getRect(element)` and `deltaRect` will have all-zero properties.
| Resize Event property | Description |
| --------------------- | ------------------------------------------------- |
| `edges` | The edges of the element that are being changed |
| `rect` | An object with the new dimensions of the target |
| `deltaRect` | The change in dimensions since the previous event |
Resizable options have an `edges` property which specifies the edges of the
element which can be resized from (top, left, bottom or right).
<LiveDemo :demoHtml="import('@/demos/resizable/basic.html?raw')" :removeNext="2" />
```html
<div data-x="0" data-y="0" class="resizable">
<!-- top-left resize handle -->
<div class="resize-top resize-left"></div>
<!-- bottom-right resize handle -->
<div class="resize-bottom resize-right"></div>
</div>
```
```js
interact('.resizable').resizable({
edges: { top: true, left: true, bottom: true, right: true },
listeners: {
move (event) {
let { x, y } = event.target.dataset
x = (parseFloat(x) || 0) + event.deltaRect.left
y = (parseFloat(y) || 0) + event.deltaRect.top
Object.assign(event.target.style, {
width: `${event.rect.width}px`,
height: `${event.rect.height}px`,
transform: `translate(${x}px, ${y}px)`,
})
Object.assign(event.target.dataset, { x, y })
},
},
})
```
Remember to use CSS `touch-action: none` to prevent the browser from panning
when the user drags with a touch pointer, `user-select: none` to disable
text selection, and `box-sizing: border-box` if your elements have padding and
borders which affect their width. {.notice .info}
If you'd like an element to behave as a resize corner, let it match the
selectors of two adjacent edges.
Resize handle elements must be children of the resizable element. If you need
the handles to be outside the target element, then you will need to use
[`Interaction#start`](interaction-start).
### `invert`
```javascript
interact(target).resizable({
edges: { bottom: true, right: true },
invert: 'reposition'
})
```
By default, resize actions can't make the `event.rect` smaller than `0x0`. Use
the `invert` option to specify what should happen if the target would be resized
to dimensions less than `0x0`. The possible values are:
- `'none'` (default) will limit the resize rect to a minimum of `0x0`
- `'negate'` will allow the rect to have negative width/height
- `'reposition'` will keep the width/height positive by swapping the top and
bottom edges and/or swapping the left and right edges
<LiveDemo :demoHtml="import('@/demos/resizable/invert.html?raw')" />
### Aspect ratio
```js
interact(target).resizable({
modifiers: [
interact.modifiers.aspectRatio({
// make sure the width is always double the height
ratio: 2,
// also restrict the size by nesting another modifier
modifiers: [
interact.modifiers.restrictSize({ max: 'parent' }),
],
}),
],
})
```
interact.js comes with an `aspectRatio` modifier which can be used to force the
resized rect to maintain a certain aspect ratio. The modifier has 3 options:
| Prop | Type | Description |
| ------------ | -------------------- | --------------------------------------------------------------------------------------- |
| `ratio` | number or 'preserve' | The aspect ratio to maintain or the value 'preserve' to maintain the starting ratio |
| `equalDelta` | boolean | Increase edges by the same amount instead of maintaining the same ratio |
| `modifiers` | array of modifiers | Modifiers to apply to the resize which will be made to respect the aspect ratio options |
To guarantee that the aspect ratio options are respected by other modifiers,
those modifiers must be in the `aspectRatio.modifiers` array option, **not** in the
same `resize.modifiers` array as the `aspectRatio` one.
[interaction-start]: http://interactjs.io/api/#Interaction.start
================================================
FILE: docs/restriction.md
================================================
---
title: Restrict
---
interact.js has 3 restriction modifiers available through the
`interact.modifiers` object:
- pointer coordinate-based `restrict`
- element rect-based restriction `restrictRect`
- element size-based `restrictSize` (resize only)
- and element edge-based `restrictEdges` (resize only)
## `restrict()`
```javascript
interact(target).draggable({
modifiers: [
interact.modifiers.restrict({
restriction: 'parent',
endOnly: true
})
]
})
```
The `restriction` value specifies the area that the action will be confined to.
The value can be:
- a rect object with `top`, `left`, `bottom` and `right` or `x`, `y`,
`width` and `height`,
- an element whose dimensions will be used as the restriction area,
- a function which takes `(x, y, element)` and returns a rect or an element
- one of these strings:
- `'self'` – restrict to the target element's rect
- `'parent'` – restrict to the rect of the element's parentNode or
- a CSS selector string – if one of the parents of the target element matches
this selector, it's rect will be used as the restriction area.
### `restrictRect()`
With the `restrict` variant, restricting is by default relative to the pointer
coordinates so that the action coordinates, not the element's dimensions, will
be kept within the restriction area. You can use the `restrictRect` variant so
that the element's edges are considered while dragging.
```javascript
interact(target).draggable({
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent'
})
]
})
```
If the target element is larger than the restriction, then the element will be
allowed to move around the restriction.
### `elementRect`
`restrictRect` is identical to `restrict`, but the `elementRect` option is set
to a helpful default of `{ left: 0, right: 0, top: 1, bottom: 1 }`. The
`elementRect` option specifies the area of the element to consider as its edges
as scalar values from the top left edges to the bottom right.
For the `left` and `right` properties, `0` means the left edge of the element
and `1` means the right edge. For `top` and `bottom`, `0 means` the top edge of
the element and 1 means the bottom.
`{ top: 0.25, left: 0.25, bottom: 0.75, right: 0.75 }` would result in a quarter
of the element being allowed to hang over the restriction edges.
## `restrictSize()`
```javascript
interact(target).resizable({
modifiers: [
interact.modifiers.restrictSize({
min: { width: 100, height: 100 },
max: { width: 500, height: 500 }
})
]
})
```
`restrictSize` lets you specify the minimum and maximum dimensions that the
target element must have when resizing.
## `restrictEdges()`
```javascript
interact(target).resizable({
modifiers: [
interact.modifiers.restrictEdges({
inner: {
left: 100, // the left edge must be <= 100
right: 200 // the right edge must be >= 200
}
outer: {
left: 0, // the left edge must be >= 0
right: 300 // the right edge must be <= 300
}
})
]
})
```
`restrictEdges` lets you specify `inner` and `outer` dimensions that the target
element must have when resizing. You can think of `inner` as setting the minimum
size of the element and `outer` as the maximum size.
================================================
FILE: docs/snapping.md
================================================
---
title: Snapping
---
interact.js has 3 snap modifiers available through the `interact.modifiers`
object:
- pointer coordinate-based `snap` which is best suited to drag actions,
- `snapSize` which works only on resize actions and let's you set targets for
the size of the target element,
- and `snapEdges` which is similar to `snapSize`, but let's you set the target
positions of the edges of the target element.
When creating snap modifiers the options have an array of `targets`. The action
events will be snapped to the closest target of this array which is within
range.
## `snap()`
The `snap` modifier changes the pointer coordinates to specified targets when
they are within range.
```js
const mySnap = interact.modifiers.snap({
targets: [
{ x: 200, y: 200 },
{ x: 250, y: 350 },
],
})
```
Using the `snap` modifier while dragging, The coordinates of the pointer that
the drag event listeners receive will be modified to meet the coordinates of the
snap targets. This option may also be used with resizable targets, but may not
yield intuitive results.
`snap` targets have `x` and `y` number props and an optional `range` number
property.
### `relativePoints`
```javascript
interact(element).draggable({
modifiers: [
interact.modifiers.snap({
targets: [ { x: 300, y: 300 } ],
relativePoints: [
{ x: 0 , y: 0 }, // snap relative to the element's top-left,
{ x: 0.5, y: 0.5 }, // to the center
{ x: 1 , y: 1 } // and to the bottom-right
]
})
]
})
```
If you want to specify for `snap` (not `snapSize` or `snapEdges`) the points on
the element which snapping should be relative to, then use an array of
`relativePoints`. Each item in the array should be an object with `x` and `y`
properties which are scalars specifying the position on the element to which
snapping should be relative. If no `relativePoints` array is specified or the
array is empty then snapping is relative to the pointer coordinates (default).
There are effectively `targets.length * max( relativePoints.length, 1 )` snap
targets while snap calculations are done. Snap functions are called multiple
times with the coordinates at each `relativePoint`.
### `offset`
```javascript
interact(element1).draggable({
modifiers: [
interact.modifiers.snap({
targets: [ { x: 300, y: 300 } ],
offset: { x: 20, y: 20 }
})
]
})
interact(element2).resizable({
modifiers: [
interact.modifiers.snap({
targets: [ { x: 300, y: 300 } ],
offset: 'startCoords'
})
]
})
```
The `offset` option lets you shift the coordinates of the targets of a `snap`
modifier. The value may be:
- an object with `x` and `y` properties,
- `'startCoords'` which will then use the `pageX` and `pageY` at the start of
the action,
- `'self'` which will use the target element's top-left coordinates,
- or `'parent'` which will use the top-left coordinates of the target's parent
element
## `snapSize()`
```js
interact(target).resizable({
edges: { top: true, left: true },
modifiers: [
interact.modifiers.snapSize({
targets: [
{ width: 100 },
interact.snappers.grid({ width: 100, height: 100 }),
],
}),
],
})
```
The `snapSize` modifier snaps the _dimensions_ of targets when resizing. A
`snapSize` target is an object with `x` and `y` number props _or_ `width` and
`height` number props as well as an optional `range`. Its targets have `x` and
`y` number props _or_ `width` and `height` number props as well as an optional
`range`.
## `snapEdges()`
```js
interact(target).resizable({
edges: { top: true, left: true },
modifiers: [
interact.modifiers.snapEdges({
targets: [
interact.snappers.grid({ top: 100, left: 100 }),
],
}),
],
})
```
The `snapEdges` modifier snaps the _edges_ of targets when resizing. Its targets
have either `x` and `y` number props to snap the left/right and top/bottom edges
respectively, `top`, `left`, `width` and `height` number props to snap each edge
and an optional `range`.
### `targets` option
The coordinates of action events are compared to the targets of the provided snap
modifiers. If multiple targets are within range, the closest target is used.
```js
interact.modifiers.snap({
targets: [
function (
// the x and y page coordinates,
x,
y,
// the current interaction
interaction,
// the offset information with relativePoint if set
{ x: offsetX, y: offsetY, relativePoint, index: relativePointIndex },
// the index of this function in the options.targets array
index,
) {
return {
x: x,
y: 75 + 50 * Math.sin(x * 0.04),
range: 40,
}
},
],
})
```
You can use functions in the `targets` array. If a snap target is a function,
then it is called and given the `x` and `y` coordinates of the event as the
first two parameters and the interaction as the third parameter. The return
value of the function is used as a target.
If a target omits an axis or edge prop, then the corresponding axis will not be
changed. For example, if a target is defined as `{ y: 100, range Infinity }`
then the snapped movement will be horizontal at `(100, pointerEventPageX)`.
### Snap grids
```javascript
var gridTarget = interact.snappers.grid({
// can be a pair of x and y, left and top,
// right and bottom, or width, and height
x: 50,
y: 50,
// optional
range: 10,
// optional
offset: { x: 5, y: 10 },
// optional
limits: {
top: 0,
left: 0,
bottom: 500,
height: 500
}
})
interact(element).draggable({
modifiers: [
interact.modifiers.snap({ targets: [gridTarget] })
]
})
```
You can use the `interact.snappers.grid()` method to create a target that snaps
to a grid. The method takes an object describing a grid and returns a function
that snaps to the corners of that grid.
The properties of the grid are:
- `x`, `y`: the spacing between the horizontal and vertical grid lines.
- `range` (optional): the distance from the grid corners within which the
pointer coords will be snapped.
- `offset` (optional): an object with `x` and `y` props to offset the grid
lines
- `limits` (optional): an object with `top`, `left`, `bottom` and `right` props
to set the bounds of the grid
### `range`
```javascript
interact(element).draggable({
modifiers: [
interact.modifiers.snap({
targets: [
{ x: 20, y: 450, range: 50 }
{ x: 10, y: 0 /* use default range below */ }
],
range: 300 // for targets that don't specify a range
})
]
})
```
A range can be specified in the snap modifier options and each target may
optionally have its own range. The `range` of a snap target is the distance the
pointer must be from the target's coordinates for a snap to be possible.
i.e. `inRange = distance <= range`.
### Event snap info
```js
interact(target).draggable({
modifiers: [
interact.modifiers.snap({ targets: [(x, y) => ({ x: x + 20 })] }),
],
listeners: {
move (event) {
console.log(event.modifiers[0].target.source)
},
},
})
```
`InteractEvent.modifiers` will be an array with info on the modifiers that have
been set for the action. Snap modifiers provide an object with the closest
target with the calculated offset.
| Prop | Type | Description |
| ----------- | ------------------------- | ----------------------------------------------------------------------------- |
| `x` and `y` | number | The coords that were snapped to with origin, offset and relativePoint applied |
| `source` | target object or function | The target object or function in the targets array option |
| `index` | number | The index of the source in the targets array |
| `range` | number | The range of the target |
| `offset` | object | The offset applied to the source |
================================================
FILE: docs/tooling.md
================================================
---
title: Tooling & Optimization
---
## Feature selection
```sh
# install only the features you need
$ npm install --save @interactjs/interact \
@interactjs/auto-start \
@interactjs/actions \
@interactjs/modifiers \
@interactjs/dev-tools
```
```js
import '@interactjs/auto-start'
import '@interactjs/actions/drag'
import '@interactjs/actions/resize'
import '@interactjs/modifiers'
import '@interactjs/dev-tools'
import interact from '@interactjs/interact'
interact('.item').draggable({
listeners: {
move (event) {
console.log(event.pageX, event.pageY)
},
},
})
```
Adding the unscoped `interactjs` npm package to your project is the easiest way
to get started with the library as it includes all features already pre-bundled
and compiled to ES5 syntax. However, this might result in a lot of unused
features increasing the size of your JS payload.
For a more streamlined build, you can add import the packages for each feature
you need. See the [npm streamlined installation
docs](/docs/installation#npm-streamlined) for more details including a list of
available packages.
## `@interactjs/dev-tools`
The `@interactjs/dev-tools` package provides hints that can help you avoid
common issues (eg. missing event handlers and useful CSS styles) while
developing your application. Although these hints can be helpful, it's best to
avoid including them in your production deployment. There are some ways to do
this below.
## Optimizing for production
### Babel plugin
```json
// babel config
{
"env": {
"production": {
"plugins": [
"@interactjs/dev-tools/babel-plugin-prod",
]
}
}
}
```
```js
// source file
import '@interactjs/actions/drag'
import interact from '@interactjs/interact'
```
```js
// result
import '@interactjs/actions/drag/index.prod'
import interact from '@interactjs/interact/index.prod'
```
If you use babel in your deployment workflow, you can simply add
`@interactjs/dev-tools/babel-plugin-prod` to the plugins section of your
production babel config and all `@interactjs/**` imports will be changed to the
optimized, production versions with development hints optimized out.
### Without build tools
```js
import '@interactjs/actions/drag/index.prod'
import interact from '@interactjs/interact/index.prod'
```
If you're not using babel, then you'll need to change your imports to include
the `.prod` extension. For index files of directories you'll need to add the
filename (eg. `@interactjs/actions -> @interactjs/actions/index.prod`).
================================================
FILE: esnext.rollup.config.cjs
================================================
/* eslint-disable import/no-extraneous-dependencies */
const { resolve, basename, dirname, relative, extname } = require('path')
const { transformAsync } = require('@babel/core')
const babel = require('@rollup/plugin-babel')
const commonjs = require('@rollup/plugin-commonjs')
const nodeResolve = require('@rollup/plugin-node-resolve')
const replace = require('@rollup/plugin-replace')
const terser = require('@rollup/plugin-terser')
const { glob } = require('glob')
const { defineConfig } = require('rollup')
const headers = require('./scripts/headers')
const {
getPackages,
sourcesIgnoreGlobs,
extendBabelOptions,
getEsnextBabelOptions,
getModuleDirectories,
isPro,
} = require('./scripts/utils')
const BUNDLED_DEPS = ['rebound']
const INPUT_EXTENSIONS = ['.ts', '.tsx', '.vue']
const moduleDirectory = getModuleDirectories()
module.exports = defineConfig(async () => {
const packageDirs = (await getPackages()).map((dir) => resolve(__dirname, dir))
return (
await Promise.all(
packageDirs.map(async (packageDir) => {
const packageName = `${basename(dirname(packageDir))}/${basename(packageDir)}`
const external = (id_, importer) => {
const id = id_.startsWith('.') ? resolve(dirname(importer), id_) : id_
// not external if it's a dependency that's intented to be bundled
if (BUNDLED_DEPS.some((dep) => id === dep || id.includes(`/node_modules/${dep}/`))) return false
// not external if the id is in the current package dir
if (
[packageName, packageDir].some(
(prefix) =>
id.startsWith(prefix) && (id.length === prefix.length || id.charAt(prefix.length) === '/'),
)
)
return false
return true
}
const entryFiles = await glob('**/*.{ts,tsx}', {
cwd: packageDir,
ignore: sourcesIgnoreGlobs,
strict: false,
nodir: true,
absolute: true,
})
const input = Object.fromEntries(
entryFiles.map((file) => [
relative(packageDir, file.slice(0, file.length - extname(file).length)),
file,
]),
)
return [
// dev unminified
{ env: { NODE_ENV: 'development' }, ext: '.js', minify: isPro },
// prod minified
{ env: { NODE_ENV: 'production' }, ext: '.prod.js', minify: true },
].map(({ env, ext, minify }) =>
defineConfig({
external,
input,
plugins: [
commonjs({ include: '**/node_modules/{rebound,symbol-tree}/**' }),
nodeResolve({
modulePaths: moduleDirectory,
extensions: INPUT_EXTENSIONS,
}),
babel(
extendBabelOptions(
{
babelrc: false,
configFile: false,
babelHelpers: 'bundled',
skipPreflightCheck: true,
extensions: INPUT_EXTENSIONS,
plugins: [
[
require.resolve('@babel/plugin-transform-runtime'),
{ helpers: false, regenerator: false },
],
],
},
getEsnextBabelOptions(),
),
),
replace({
preventAssignment: true,
values: Object.entries({
npm_package_version: process.env.npm_package_version,
IJS_BUNDLE: '',
...env,
}).reduce((acc, [key, value]) => {
acc[`process.env.${key}`] = JSON.stringify(value)
return acc
}, {}),
}),
],
context: 'window',
moduleContext: 'window',
preserveEntrySignatures: 'strict',
output: [
{
dir: packageDir,
entryFileNames: `[name]${ext}`,
format: 'es',
banner: minify ? headers?.min : headers?.raw,
inlineDynamicImports: false,
sourcemap: true,
plugins: [
{
name: '@interactjs/_dev:output-transforms',
async renderChunk(code, chunk, outputOptions) {
return await transformAsync(code, {
babelrc: false,
configFile: false,
inputSourceMap: chunk.map,
filename: `${packageDir}/${chunk.fileName}`,
plugins: [
[
require.resolve('./scripts/babel/relative-imports'),
{ extension: ext, moduleDirectory },
],
[require.resolve('@babel/plugin-transform-class-properties'), { loose: true }],
],
})
},
},
minify &&
terser({
module: false,
mangle: true,
compress: {
ecma: '2019',
unsafe: true,
unsafe_Function: true,
unsafe_arrows: false,
unsafe_methods: true,
},
format: {
preamble: headers?.min,
},
}),
],
},
],
}),
)
}),
)
).flat()
})
================================================
FILE: examples/.eslintignore
================================================
js
================================================
FILE: examples/.eslintrc.cjs
================================================
module.exports = {
extends: '../.eslintrc.cjs',
globals: { interact: false, _: false, $: false },
rules: { 'no-console': 'off', 'import/no-unresolved': 'off', 'import/no-extraneous-dependencies': 'off' },
}
================================================
FILE: examples/dropzones/index.css
================================================
body { font-family: Helvetica, Arial, sans-serif; }
.dropzone-wrapper {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.dropzone {
overflow: hidden;
margin: .5em;
padding: 1em;
color: #666;
text-align: center;
background: #ccc;
line-height: 4em;
border: 4px dashed transparent;
transition: background .15s linear, border-color .15s linear;
}
.dropzone.-drop-possible { border-color: #666; }
.dropzone.-drop-over {
background: #666;
color: #fff;
}
.draggable {
position: relative;
z-index: 10;
width: 200px;
margin: .25em;
padding: 1em 2em;
background-color: #29e;
color: #fff;
text-align: center;
-ms-touch-action: none;
touch-action: none;
}
.draggable.-drop-possible { background-color: #42bd41; }
================================================
FILE: examples/dropzones/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Highlight dropzones with interact.js</title>
<script type="module" src="./index.js"></script>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="drag1" class="draggable js-drag">Drag me…</div>
<div id="drag2" class="draggable js-drag">Drag me…</div>
<div id="drag3" class="draggable js-drag">Drag me…</div>
<div id="drag4" class="draggable js-drag">Drag me…</div>
<div class="dropzone-wrapper">
<div id="drop1" class="dropzone js-drop">Dropzone</div>
<div id="drop2" class="dropzone js-drop">Dropzone</div>
<div id="drop3" class="dropzone js-drop">Dropzone</div>
</div>
</body>
</html>
================================================
FILE: examples/dropzones/index.js
================================================
/* eslint-disable import/no-absolute-path */
import interact from '@interactjs/interactjs'
let transformProp
const dragPositions = [1, 2, 3, 4].reduce((acc, n) => {
acc[`drag${n}`] = { x: 0, y: 0 }
return acc
}, {})
interact.maxInteractions(Infinity)
// setup draggable elements.
interact('.js-drag').draggable({
listeners: {
start(event) {
const position = dragPositions[event.target.id]
position.x = parseInt(event.target.getAttribute('data-x'), 10) || 0
position.y = parseInt(event.target.getAttribute('data-y'), 10) || 0
},
move(event) {
const position = dragPositions[event.target.id]
position.x += event.dx
position.y += event.dy
if (transformProp) {
event.target.style[transformProp] = 'translate(' + position.x + 'px, ' + position.y + 'px)'
} else {
event.target.style.left = position.x + 'px'
event.target.style.top = position.y + 'px'
}
},
end(event) {
const position = dragPositions[event.target.id]
event.target.setAttribute('data-x', position.x)
event.target.setAttribute('data-y', position.y)
},
},
})
// setup drop areas.
// dropzone #1 accepts draggable #1
setupDropzone('#drop1', '#drag1')
// dropzone #2 accepts draggable #1 and #2
setupDropzone('#drop2', '#drag1, #drag2')
// every dropzone accepts draggable #3
setupDropzone('.js-drop', '#drag3')
/**
* Setup a given element as a dropzone.
*
* @param {HTMLElement|String} target
* @param {String} accept
*/
function setupDropzone(target, accept) {
interact(target)
.dropzone({
accept,
ondropactivate: function (event) {
addClass(event.relatedTarget, '-drop-possible')
},
ondropdeactivate: function (event) {
removeClass(event.relatedTarget, '-drop-possible')
},
})
.on('dropactivate', (event) => {
const active = event.target.getAttribute('active') | 0
// change style if it was previously not active
if (active === 0) {
addClass(event.target, '-drop-possible')
event.target.textContent = 'Drop me here!'
}
event.target.setAttribute('active', active + 1)
})
.on('dropdeactivate', (event) => {
const active = event.target.getAttribute('active') | 0
// change style if it was previously active
// but will no longer be active
if (active === 1) {
removeClass(event.target, '-drop-possible')
event.target.textContent = 'Dropzone'
}
event.target.setAttribute('active', active - 1)
})
.on('dragenter', (event) => {
addClass(event.target, '-drop-over')
event.relatedTarget.textContent = "I'm in"
})
.on('dragleave', (event) => {
removeClass(event.target, '-drop-over')
event.relatedTarget.textContent = 'Drag me…'
})
.on('drop', (event) => {
removeClass(event.target, '-drop-over')
event.relatedTarget.textContent = 'Dropped'
})
}
function addClass(element, className) {
if (element.classList) {
return element.classList.add(className)
} else {
element.className += ' ' + className
}
}
function removeClass(element, className) {
if (element.classList) {
return element.classList.remove(className)
} else {
element.className = element.className.replace(new RegExp(className + ' *', 'g'), '')
}
}
/* eslint-disable multiline-ternary */
interact(document).on('ready', () => {
transformProp =
'transform' in document.body.style
? 'transform'
: 'webkitTransform' in document.body.style
? 'webkitTransform'
: 'mozTransform' in document.body.style
? 'mozTransform'
: 'oTransform' in document.body.style
? 'oTransform'
: 'msTransform' in document.body.style
? 'msTransform'
: null
})
/* eslint-enable multiline-ternary */
================================================
FILE: examples/events/index.css
================================================
#swipe {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: 0;
padding: 10%;
background-color: #29e;
color: #fff;
font-size: 8em;
font-size: 10vmin;
font-family: sans-serif;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
-webkit-touch-action: none;
-moz-touch-action: none;
-ms-touch-action: none;
touch-action: none;
}
.tolerance-slider {
position: absolute;
left: 0;
bottom: 0;
width: 80%;
height: 5%;
margin: 5% 10%;
}
#tolerance-display {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
margin: 2% 0%;
font-size: 2em;
font-size: 4vmin;
text-align: center;
color: #fff;
}
#tolerance-display::before {
content: "interact.pointerMoveTolerance( ";
}
#tolerance-display::after {
content: " )";
}
================================================
FILE: examples/events/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>interact.js events demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="Display events with interact.js"/>
<meta name="author" content="Taye Adeyemi" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./index.css">
<script type="module" src="./index.js"></script>
</head>
<body>
<div id="swipe">Tap, drag and swipe accros the screen</div>
<input class="tolerance-slider" type="range" value="1" step="1" min="1" max="100">
<pre id="tolerance-display">1</pre>
</body>
</html>
================================================
FILE: examples/events/index.js
================================================
/* eslint-disable import/no-absolute-path */
import interact from '@interactjs/interactjs'
const dirs = ['up', 'down', 'left', 'right']
interact('#swipe')
.draggable(true)
.on('dragend', (event) => {
if (!event.swipe) {
return
}
let str = 'swipe'
for (const dir of dirs) {
if (event.swipe[dir]) {
str += ' ' + dir
}
}
str += '<br>' + event.swipe.angle.toFixed(2) + '°' + '<br>' + event.swipe.speed.toFixed(2) + 'px/sec'
event.target.innerHTML = str
window.console.log(str.replace(/<br>/g, ' '))
})
const pointerEvents = ['tap', 'doubletap', 'hold', 'down', 'move', 'up']
function logEvent(event) {
event.currentTarget.innerHTML = event.pointerType
if (/tap|up|click|down/.test(event.type) && event.interaction.prevTap) {
window.console.log(
event.type + ' -- ' + event.dt + ', ' + (new Date().getTime() - event.interaction.prevTap.timeStamp),
)
}
if (interact.supportsTouch() || interact.supportsPointerEvent()) {
event.target.innerHTML += ' #' + event.pointerId
}
const interactionIndex = interact.debug().interactions.list.indexOf(event.interaction)
event.currentTarget.innerHTML +=
' ' +
event.type +
'<br>(' +
event.pageX +
', ' +
event.pageY +
')<br>' +
'interaction #' +
interactionIndex
// window.console.log(event.pointerType, event.pointerId, event.type, event.pageX, event.pageY, interactionIndex);
event.preventDefault()
}
for (let i = 0; i < pointerEvents.length; i++) {
const eventType = pointerEvents[i]
interact('#swipe').on(eventType, logEvent)
}
function changeTolerance(event) {
const value = event.target.value | 0
interact.pointerMoveTolerance(value)
document.getElementById('tolerance-display').textContent = value
}
interact('.tolerance-slider').on('input', changeTolerance)
interact('.tolerance-slider').on('change', changeTolerance)
================================================
FILE: examples/iframes/bottom.html
================================================
<meta charset="utf-8">
<link href="./index.css" rel="stylesheet" type="text/css"/>
<script type="module">
import setInteractables from './index.js'
window.interact = window.parent.interact;
setInteractables();
</script>
<div id="drag-me" class="draggable">
<p>An element in the BOTTOM frame</p>
</div>
================================================
FILE: examples/iframes/index.css
================================================
body {
margin: 0;
padding: 5% 10%;
font-family: sans-serif;
}
#drag-me {
width: 25%;
background-color: #29e;
color: white;
border: solid 0.4em #666;
border-radius: 0.75em;
padding: 3%;
touch-action: none;
position: absolute;
top: 0;
left: 0;
}
iframe {
width: 100%;
height: 75vh;
}
================================================
FILE: examples/iframes/index.html
================================================
<meta charset="utf-8">
<link href="./index.css" rel="stylesheet" type="text/css"/>
<iframe src="middle.html" style="border: solid 2px black"></iframe>
<script type="module">
import setInteractables from './index.js'
document.querySelector('iframe').onload = function (event) {
window.interact = frames[0].interact;
setInteractables();
};
</script>
<div id="drag-me" class="draggable">
<p>An element in the TOP frame</p>
</div>
================================================
FILE: examples/iframes/index.js
================================================
export default function setInteractables() {
interact('.draggable', { context: document }).draggable({
onmove: onMove,
inertia: { enabled: true },
restrict: {
drag: 'parent',
endOnly: true,
elementRect: { top: 0, left: 0, bottom: 1, right: 1 },
},
autoScroll: true,
})
function onMove(event) {
const target = event.target
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
if ('webkitTransform' in target.style || 'transform' in target.style) {
target.style.webkitTransform = target.style.transform = 'translate(' + x + 'px, ' + y + 'px)'
} else {
target.style.left = x + 'px'
target.style.top = y + 'px'
}
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
}
================================================
FILE: examples/iframes/middle.html
================================================
<meta charset="utf-8">
<link href="index.css" rel="stylesheet" type="text/css"/>
<script type="module">
import interact from '@interactjs/interactjs'
import setInteractables from './index.js'
window.interact = interact
setInteractables();
document.getElementById('iframe').src = 'bottom.html'
</script>
<iframe id="iframe" style="border: solid 2px black"></iframe>
<div id="drag-me" class="draggable">
<p>An element in the MIDDLE frame</p>
</div>
================================================
FILE: examples/snap/index.css
================================================
body {
margin: 0;
padding: 0;
border: 0;
font-family: "Arial", sans-serif;
}
canvas {
position: absolute;
top: 0;
left: 0;
margin: 20px;
padding: 0;
touch-action: none;
}
#status {
width: 20%;
height: 100%;
position: fixed;
right: 0;
top: 0;
padding: 5px 5px;
border: none;
border-left: solid 8px #3a6bff;
background-color: rgba(0, 143, 179, 0.298);
text-align: center;
font-size: 1.4em;
}
#status h3 {
font-size: 1.1em;
margin: 3px 0px 0px 0px;
padding: 0;
line-height: 22px;
text-transform: capitalize;
font-weight: normal
}
#status input[type=radio], #status input[type=checkbox] {
float: right;
}
#status [type=range] {
margin: auto;
width: 90%;
}
#status [disabled] {
cursor: default;
}
#status label {
float: left;
cursor: pointer;
width: 95%;
text-align: left;
}
#modes,#sliders {
overflow: hidden;
width: 100%;
margin: auto;
}
#modes.disabled label.snap-mode {
cursor: default;
color: gray;
}
================================================
FILE: examples/snap/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>interact.js drag snapping</title>
<meta name="description" content="A demonstration of interact.js drag snapping" />
<meta name="author" content="Taye Adeyemi" />
<script type="module" src="./index.js"></script>
<link rel="stylesheet" href="./index.css" type="text/css"/>
</head>
<body>
<canvas id="grid"> Your browser does not support the HTML5 canvas</canvas>
<canvas id="drag"> </canvas>
<div id="status">
<div id="controls">
<section id="sliders">
<h3> grid spacing </h3>
<input id="grid-x" type="range" value="300" min="20" max="500" title="x-axis">
<input id="grid-y" type="range" value="300" min="20" max="500" title="x-axis">
<br>
<h3> grid offset </h3>
<input id="offset-x" type="range" value="100" min="0" max="500" title="x-axis">
<input id="offset-y" type="range" value="100" min="0" max="500" title="x-axis">
<br>
<h3> snap range </h3>
<input id="snap-range" type="range" min="-1" value="100" max="150" title="snap range">
</section>
<br>
<section id="modes">
<h3> snap mode </h3>
<label for="off-mode" class="snap-mode">
Off
<input id="off-mode" type="radio" name="snap-mode">
</label> <br>
<label for="grid-mode" class="snap-mode">
Grid Mode
<input id="grid-mode" type="radio" name="snap-mode" checked="true">
</label> <br>
<label for="anchor-mode" class="snap-mode">
Anchor Mode
<input id="anchor-mode" type="radio" name="snap-mode">
</label>
<br>
<br>
<label for="end-only">
Snap at end only
<input id="end-only" type="checkbox">
</label>
<label for="inertia">
Inertia
<input id="inertia" type="checkbox">
</label>
<label for="relative">
Relative to "startCoords"
<input id="relative" type="checkbox">
</label>
<br>
<br>
<label for="drag-anchors" style="display: none">
Anchor drag mode
<input id="drag-anchors" type="checkbox" >
</label>
</section>
</div>
</div>
</body>
</html>
================================================
FILE: examples/snap/index.js
================================================
/* eslint-disable import/no-absolute-path */
import interact from '@interactjs/interactjs'
window.interact = interact
let canvas
let context
let guidesCanvas
let guidesContext
const width = 800
const height = 800
let status
const blue = '#2299ee'
const lightBlue = '#88ccff'
const tango = '#ff4400'
let draggingAnchor = null
const snapOffset = { x: 0, y: 0 }
const snapGrid = {
x: 10,
y: 10,
range: 10,
offset: { x: 0, y: 0 },
}
const gridFunc = interact.snappers.grid(snapGrid)
const anchors = [
{ x: 100, y: 100, range: 200 },
{ x: 600, y: 400, range: Infinity },
{ x: 500, y: 150, range: Infinity },
{ x: 250, y: 250, range: Infinity },
]
const prevCoords = { x: 0, y: 0 }
let prevClosest = { target: { x: 0, y: 0 }, range: 0 }
const cursorRadius = 10
function drawGrid(grid, gridOffset, range) {
if (!grid.x || !grid.y) return
const barLength = 16
const offset = {
x: gridOffset.x + snapOffset.x,
y: gridOffset.y + snapOffset.y,
}
guidesContext.clearRect(0, 0, width, height)
guidesContext.fillStyle = lightBlue
if (range < 0 || range === Infinity) {
guidesContext.fillRect(0, 0, width, height)
}
for (let i = -((1 + offset.x / grid.x) | 0), lenX = width / grid.x + 1; i < lenX; i++) {
for (let j = -((1 + offset.y / grid.y) | 0), lenY = height / grid.y + 1; j < lenY; j++) {
if (range > 0 && range !== Infinity) {
guidesContext.circle(i * grid.x + offset.x, j * grid.y + offset.y, range, blue).fill()
}
guidesContext.beginPath()
guidesContext.moveTo(i * grid.x + offset.x, j * grid.y + offset.y - barLength / 2)
guidesContext.lineTo(i * grid.x + offset.x, j * grid.y + offset.y + barLength / 2)
guidesContext.stroke()
guidesContext.beginPath()
guidesContext.moveTo(i * grid.x + offset.x - barLength / 2, j * grid.y + offset.y)
guidesContext.lineTo(i * grid.x + offset.x + barLength / 2, j * grid.y + offset.y)
guidesContext.stroke()
}
}
}
function drawAnchors(defaultRange) {
const barLength = 16
guidesContext.clearRect(0, 0, width, height)
if (status.range.value < 0 && status.range.value !== Infinity) {
guidesContext.fillStyle = lightBlue
guidesContext.fillRect(0, 0, width, height)
}
for (let i = 0, len = anchors.length; i < len; i++) {
const anchor = {
x: anchors[i].x + snapOffset.x,
y: anchors[i].y + snapOffset.y,
range: anchors[i].range,
}
const range = typeof anchor.range === 'number' ? anchor.range : defaultRange
if (range > 0 && range !== Infinity) {
guidesContext.circle(anchor.x, anchor.y, range, blue).fill()
}
guidesContext.beginPath()
guidesContext.moveTo(anchor.x, anchor.y - barLength / 2)
guidesContext.lineTo(anchor.x, anchor.y + barLength / 2)
guidesContext.stroke()
guidesContext.beginPath()
guidesContext.moveTo(anchor.x - barLength / 2, anchor.y)
guidesContext.lineTo(anchor.x + barLength / 2, anchor.y)
guidesContext.stroke()
}
}
function drawSnap(snap) {
context.clearRect(0, 0, width, height)
guidesContext.clearRect(0, 0, width, height)
if (status.gridMode.checked) {
drawGrid(snapGrid, snapGrid.offset, snapGrid.range)
} else if (status.anchorMode.checked) {
drawAnchors(snap.range)
}
}
function circle(x, y, radius, color) {
this.fillStyle = color || this.fillStyle
this.beginPath()
this.arc(x, y, radius, 0, 2 * Math.PI)
return this
}
window.CanvasRenderingContext2D.prototype.circle = circle
function dragMove(event) {
const snap = event._interaction.modification.states.find((m) => m.name === 'snap')
const closest = snap && snap.closest
const rect = interact.getElementRect(canvas)
context.clearRect(
prevCoords.x - cursorRadius - 2,
prevCoords.y - cursorRadius - 2,
cursorRadius * 2 + 4,
cursorRadius * 2 + 4,
)
context.clearRect(
prevClosest.target.x - prevClosest.range - rect.left - 2,
prevClosest.target.y - prevClosest.range - rect.top - 2,
prevClosest.range * 2 + 4 + rect.left,
prevClosest.range * 2 + 4 + rect.top,
)
if (closest && closest.range !== Infinity) {
const closestTarget = {
x: closest.target.x - rect.left,
y: closest.target.y - rect.top,
}
context.circle(closestTarget.x, closestTarget.y, closest.range + 1, 'rgba(102, 225, 117, 0.8)').fill()
}
context.circle(event.pageX, event.pageY, cursorRadius, tango).fill()
prevCoords.x = event.pageX
prevCoords.y = event.pageY
prevClosest = closest || prevClosest
}
function dragEnd(event) {
context.clearRect(0, 0, width, height)
context.circle(event.pageX, event.pageY, cursorRadius, tango).fill()
prevCoords.x = event.pageX
prevCoords.y = event.pageY
}
function anchorDragStart(event) {
if (event.snap.locked) {
interact(canvas).snap(false)
draggingAnchor = event.snap.anchors.closest
}
}
function anchorDragMove(event) {
if (draggingAnchor) {
const snap = interact(canvas).snap().drag
draggingAnchor.x += event.dx
draggingAnchor.y += event.dy
drawAnchors(snap.range)
}
}
function anchorDragEnd(event) {
interact(canvas).draggable(true)
draggingAnchor = null
}
function sliderChange() {
snapGrid.x = Number(status.gridX.value)
snapGrid.y = Number(status.gridY.value)
snapGrid.range = Number(status.range.value)
snapGrid.offset.x = Number(status.offsetX.value)
snapGrid.offset.y = Number(status.offsetY.value)
if (snapGrid.range < 0) {
snapGrid.range = Infinity
}
drawSnap(interact(canvas).draggable().snap)
}
function modeChange(event) {
if (status.anchorDrag.checked && !status.anchorMode.checked) {
status.anchorMode.checked = true
}
if (status.anchorDrag.checked) {
status.anchorMode.disabled = status.offMode.disabled = status.gridMode.disabled = true
status.modes.className += ' disabled'
interact(canvas)
.off('dragstart', dragMove)
.off('dragmove', dragMove)
.off('dragend', dragEnd)
.on('dragstart', anchorDragStart)
.on('dragmove', anchorDragMove)
.on('dragend', anchorDragEnd)
} else {
status.anchorMode.disabled = status.offMode.disabled = status.gridMode.disabled = false
status.modes.className = status.modes.className.replace(/ *\bdisabled\b/g, '')
interact(canvas)
.on('dragstart', dragMove)
.on('dragmove', dragMove)
.on('dragend', dragEnd)
.off('dragstart', anchorDragStart)
.off('dragmove', anchorDragMove)
.off('dragend', anchorDragEnd)
}
interact(canvas).draggable({
inertia: {
enabled: status.inertia.checked,
},
modifiers: [
interact.modifiers.restrict({ restriction: 'self' }),
interact.modifiers.snap({
targets: status.gridMode.checked ? [gridFunc] : status.anchorMode.checked ? anchors : null,
enabled: !status.offMode.checked,
endOnly: status.endOnly.checked,
offset: status.relative.checked ? 'startCoords' : null,
}),
interact.modifiers.spring(),
],
})
if (!status.relative.checked) {
snapOffset.x = snapOffset.y = 0
}
drawSnap(interact(canvas).draggable().snap)
}
function sliderInput(event) {
// eslint-disable-next-line no-mixed-operators
if (
(event.target.type === 'range' &&
// eslint-disable-next-line no-mixed-operators
Number(event.target.value) > Number(event.target.max)) ||
Number(event.target.value) < Number(event.target.min)
) {
return
}
sliderChange()
}
interact(document).on('DOMContentLoaded', () => {
canvas = document.getElementById('drag')
canvas.width = width
canvas.height = height
context = canvas.getContext('2d')
interact(canvas)
.on('move down', (event) => {
if ((event.type === 'down' || !event.interaction.pointerIsDown) && status.relative.checked) {
const rect = interact.getElementRect(canvas)
snapOffset.x = event.pageX - rect.left
snapOffset.y = event.pageY - rect.top
drawSnap(interact(canvas).draggable().snap)
}
})
.draggable({ origin: 'self' })
guidesCanvas = document.getElementById('grid')
guidesCanvas.width = width
guidesCanvas.height = height
guidesContext = guidesCanvas.getContext('2d')
status = {
container: document.getElementById('status'),
sliders: document.getElementById('sliders'),
gridX: document.getElementById('grid-x'),
gridY: document.getElementById('grid-y'),
offsetX: document.getElementById('offset-x'),
offsetY: document.getElementById('offset-y'),
range: document.getElementById('snap-range'),
modes: document.getElementById('modes'),
offMode: document.getElementById('off-mode'),
gridMode: document.getElementById('grid-mode'),
anchorMode: document.getElementById('anchor-mode'),
anchorDrag: document.getElementById('drag-anchors'),
endOnly: document.getElementById('end-only'),
inertia: document.getElementById('inertia'),
relative: document.getElementById('relative'),
}
interact('#sliders').on('change', sliderInput).on('input', sliderInput)
interact('#modes').on('change', modeChange)
sliderChange()
modeChange()
})
window.grid = {
drawGrid,
}
================================================
FILE: examples/sortable/index.html
================================================
<title>interact.js Sortable and Swappable demo</title>
<link rel="stylesheet" href="./style.css">
<body>
<div id="react-app"></div>
<div id="vue-app">
<div v-for="list of lists" class="box" :key="list.title">
<h1>{{ list.title }}</h1>
<pre>{{ list.items }}</pre>
<i-sortable class="container" :options="sortableOptions" v-model="list.items">
<div v-for="(item, index) of list.items" :key="index" disabled="!!(index % 2)" :id="`item-${index}-${item}`" class="item card">
<div class="card-content">{{ index }}. {{ item }}</div>
</div>
</i-sortable>
</div>
<pre>[ {{ tags.join(', ') }} ]</pre>
<i-swappable class="tags" v-model="tags" :options="swappableOptions">
<div v-for="tag of tags" :id="'tag-' + tag" class="tag is-info is-large" :key="tag">{{ tag }}</div>
</i-swappable>
</div>
<div id="no-parent"></div>
</body>
<script type="module" src="./vue.js"></script>
<script type="module" src="./react.js"></script>
================================================
FILE: examples/sortable/react.js
================================================
import '@interactjs/react'
import { createElement as h, useState } from 'react'
import { createRoot } from 'react-dom/client'
import interact from '@interactjs/interactjs'
import { getData } from './shared.js'
// eslint-disable-next-line no-undef
const data = getData()
const { Interactable, Sortable } = interact.react.components
const root = createRoot(document.getElementById('react-app'))
root.render(
h(() => {
return h(
'div',
{},
data.lists.map((list, index) => {
const [items, setItems] = useState(list.items)
return h('div', { key: list.title, className: 'box' }, [
list.title,
h('pre', {}, JSON.stringify(items, null, 2)),
h(
Sortable,
{ className: 'container', key: `list-${list.title}`, items, onUpdate: setItems },
items.map((item) =>
h(
Interactable,
{ key: item, onTap: (event) => console.log(event), className: 'item card' },
h('div', { className: 'card-content' }, item),
),
),
),
])
}),
)
}),
)
================================================
FILE: examples/sortable/shared.js
================================================
import interact from '@interactjs/interactjs'
function sortListener(event) {
console.log(event.type, event.position)
}
export function getData() {
return {
lists: [
{
title: 'Animals',
items: ['elephant', 'turtle', 'frog'],
},
{
title: 'Numbers',
items: ['first', 'second', 'third'],
},
],
tags: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
}
}
export const sortableOptions = {
draggable: {
// lockAxis: 'y',
inertia: true,
autoScroll: { container: '.container' },
listeners: [interact.feedback.pointers()],
modifiers: [
interact.modifiers.restrict({
restriction: 'html',
elementRect: { left: 0, top: 0, right: 1, bottom: 1 },
}),
interact.modifiers.transform(),
interact.modifiers.spring(),
],
},
_spillTo: document.getElementById('no-parent'),
mirror: false,
listeners: [
{
start: sortListener,
change: sortListener,
end: sortListener,
},
],
}
export const swappableOptions = {
draggable: {
// lockAxis: 'y',
inertia: true,
modifiers: [interact.modifiers.spring()],
listeners: interact.feedback.pointers(),
},
}
================================================
FILE: examples/sortable/style.css
================================================
@import "bulma/css/bulma.css";
body {
margin: 1em;
_font-size: 2em;
}
.container {
max-width: 500px;
}
.item.i-sorting {
z-index: 1;
}
*, *::before, *::after {
box-sizing: border-box;
}
body {
_margin: 0;
}
.box {
display: inline-flex;
flex-direction: column;
margin: 1em;
}
.container {
margin: 0;
transform-origin: 0 0;
_transform: rotate(0deg) scale(2);
_transform: rotate(10deg);
width: 50vw;
padding: 1em 0;
flex-direction: row-reverse;
}
.item {
margin: 1em 0;
background-color: #29e;
max-width: none;
}
.item:first-child {
width: 75%;
}
.item.disabled {
background-color: gray;
}
.container, .tags {
touch-action: none;
user-select: none;
}
.tags {
background-color: lightgray;
padding: 1em;
}
.tag {
font-size: 2em !important;
}
#no-parent {
position: absolute;
bottom: 2em;
right: 2em;
width: 300px;
}
.i-ghost {
opacity: 0.5;
}
.i-mirror {
z-index: 100;
}
.container {
height: 300px;
overflow: auto;
}
================================================
FILE: examples/sortable/vue.js
================================================
import '@interactjs/vue'
import { createApp } from 'vue/dist/vue.esm-bundler'
import interact from '@interactjs/interactjs'
import { getData, sortableOptions, swappableOptions } from './shared.js'
const app = createApp({
data() {
return {
...getData(),
sortableOptions,
swappableOptions,
}
},
})
app.use(interact.vue)
app.mount('#vue-app')
================================================
FILE: examples/star/index.css
================================================
.point-handle {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: -ms-grab;
cursor: grab;
touch-action: none;
}
.dragging, .dragging .point-handle {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: -ms-grabbing;
cursor: grabbing;
}
================================================
FILE: examples/star/index.js
================================================
document.addEventListener('DOMContentLoaded', () => {
const sns = 'http://www.w3.org/2000/svg'
const xns = 'http://www.w3.org/1999/xlink'
const root = document.getElementById('svg-edit-demo')
const star = document.getElementById('edit-star')
let rootMatrix
const originalPoints = []
let transformedPoints = []
for (let i = 0, len = star.points.numberOfItems; i < len; i++) {
const handle = document.createElementNS(sns, 'use')
const point = star.points.getItem(i)
const newPoint = root.createSVGPoint()
handle.setAttributeNS(xns, 'href', '#point-handle')
handle.setAttribute('class', 'point-handle')
handle.x.baseVal.value = newPoint.x = point.x
handle.y.baseVal.value = newPoint.y = point.y
handle.setAttribute('data-index', i)
originalPoints.push(newPoint)
root.appendChild(handle)
}
function applyTransforms(event) {
rootMatrix = root.getScreenCTM()
transformedPoints = originalPoints.map((point) => {
return point.matrixTransform(rootMatrix)
})
interact('.point-handle').draggable({
snap: {
targets: transformedPoints,
range: 20 * Math.max(rootMatrix.a, rootMatrix.d),
},
})
}
interact(root).on('mousedown', applyTransforms).on('touchstart', applyTransforms)
interact('.point-handle')
.draggable({
onstart: function (event) {
root.setAttribute('class', 'dragging')
},
onmove: function (event) {
const i = event.target.getAttribute('data-index') | 0
const point = star.points.getItem(i)
point.x += event.dx / rootMatrix.a
point.y += event.dy / rootMatrix.d
event.target.x.baseVal.value = point.x
event.target.y.baseVal.value = point.y
},
onend: function (event) {
root.setAttribute('class', '')
},
snap: {
targets: originalPoints,
range: 10,
relativePoints: [{ x: 0.5, y: 0.5 }],
},
restrict: { restriction: document.rootElement },
})
.styleCursor(false)
document.addEventListener('dragstart', (event) => {
event.preventDefault()
})
})
================================================
FILE: examples/svg-editor/index.html
================================================
<svg>
</svg>
<label>
Resize invert:
<select id="invert">
<option value="reposition">reposition</option>
<option value="negate">negate</option>
<option value="none">none</option>
</select>
</label>
<style>
svg {
width: 100%;
height: 240px;
background-color: #2e9;
-ms-touch-action: none;
touch-action: none;
}
.edit-rectangle {
fill: #92e;
stroke: #fff;
transition: fill 0.3s, stroke 0.3s;
}
.edit-rectangle.neg-w {
fill: #f40;
}
.edit-rectangle.neg-h {
stroke: #29e;
}
body { margin: 0; }
</style>
<script type="module" src="./index.js"></script>
================================================
FILE: examples/svg-editor/index.js
================================================
/* eslint-disable import/no-absolute-path */
import '@interactjs/actions'
import '@interactjs/modifiers'
import '@interactjs/inertia'
import '@interactjs/auto-start'
import '@interactjs/dev-tools'
import interact from '@interactjs/interact'
const svgCanvas = document.querySelector('svg')
const svgNS = 'http://www.w3.org/2000/svg'
const rectangles = []
class Rectangle {
constructor(x, y, w, h) {
this.x = x
this.y = y
this.w = w
this.h = h
this.scale = 1.0
this.stroke = 5
this.el = document.createElementNS(svgNS, 'rect')
this.el.setAttribute('data-index', rectangles.length)
this.el.setAttribute('class', 'edit-rectangle')
rectangles.push(this)
this.draw()
}
draw() {
let x = this.x
let y = this.y
let w = this.w
let h = this.h
let cssClass = 'edit-rectangle'
if (w < 0) {
x += w
w = Math.abs(w)
cssClass += ' neg-w'
}
if (h < 0) {
y += h
h = Math.abs(h)
cssClass += ' neg-h'
}
this.el.setAttribute('x', x + this.stroke / 2)
this.el.setAttribute('y', y + this.stroke / 2)
this.el.setAttribute('width', Math.max(w, 10) - this.stroke)
this.el.setAttribute('height', Math.max(h, 10) - this.stroke)
this.el.setAttribute('stroke-width', this.stroke)
this.el.style.transform = `scale(${this.scale})`
this.el.setAttribute('class', cssClass)
}
}
interact('.edit-rectangle')
// change how interact gets the
// dimensions of '.edit-rectangle' elements
.rectChecker((element) => {
// find the Rectangle object that the element belongs to
const { x, y, w, h, scale } = rectangles[element.getAttribute('data-index')]
// return a suitable object for interact.js
const left = x * scale
const top = y * scale
return {
left,
top,
right: left + w * scale,
bottom: top + h * scale,
}
})
.draggable({
// inertia: true,
modifiers: [
interact.modifiers.restrictRect({
// restrict to a parent element that matches this CSS selector
restriction: 'svg',
// only restrict before ending the drag
endOnly: true,
}),
interact.modifiers.transform(),
],
onmove: function (event) {
const rectangle = rectangles[event.target.getAttribute('data-index')]
rectangle.x += event.dx
rectangle.y += event.dy
rectangle.draw()
},
})
.resizable({
edges: { left: true, right: true, top: true, bottom: true },
invert: 'reposition',
modifiers: [
interact.modifiers.transform(),
interact.modifiers.restrictEdges({
restriction: 'svg',
}),
],
listeners: {
move(event) {
const rectangle = rectangles[event.target.getAttribute('data-index')]
rectangle.x = event.rect.left
rectangle.y = event.rect.top
rectangle.w = event.rect.width
rectangle.h = event.rect.height
rectangle.draw()
},
},
})
for (let i = 0; i < 5; i++) {
const r = new Rectangle(50 + 100 * i, 80, 80, 80)
svgCanvas.appendChild(r.el)
}
interact('#invert').on('input change', (event) => {
interact('.edit-rectangle').resizable({ invert: event.target.value })
console.log(event.target.value)
})
================================================
FILE: examples/transform/index.html
================================================
<head>
<title>interact.js transforms modifier demo</title>
<script type="module" src="./index.js"></script>
<link rel="stylesheet" href="../../node_modules/bulma/css/bulma.css">
</head>
<body>
<div id="container" _class="container box">
<div id="item1" class="item card">
<div class="card-content">item 1</div>
</div>
<div id="item2" class="item card">
<div class="card-content">item 2</div>
</div>
<div id="item3" class="item card">
<div class="card-content">item 3</div>
</div>
<div id="item4" class="item card">
<div class="card-content">item 4</div>
</div>
</div>
<style>
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
}
#container {
margin: 0;
transform-origin: 0 0;
transform: rotate(0deg) scale(2);
_transform: rotate(10deg);
width: 25vw;
}
.item {
background-color: #29e;
max-width: none;
touch-action: none;
user-select: none;
}
#item2 {
width: 200px;
height: 200px;
}
</style>
</body>
================================================
FILE: examples/transform/index.js
================================================
import interact from '@interactjs/interactjs'
// import Vue from '../../node_modules/vue/dist/vue.esm.browser.js'
interact('.item')
.draggable({
origin: 'parent',
// inertia: true,
modifiers: [
interact.modifiers.snap({
// enabled: false,
// targets: [interact.snappers.grid({ x: 20, y: 20 })],
targets: [interact.snappers.elements({ targets: '.item', range: 20 })],
relativePoints: [{ x: 0, y: 0 }],
}),
interact.modifiers.avoid({ targets: ['.item'] }),
interact.modifiers.spring({ allowResume: true }),
interact.modifiers.transform(),
],
})
.resizable({
enabled: true,
origin: 'self',
edges: { left: true, right: true, top: true, bottom: true },
modifiers: [
// interact.modifiers.snapSize({
// targets: [interact.snappers.grid({ x: 100, y: 100 })],
// }),
// interact.modifiers.aspectRatio({ ratio: 'preserve' }),
// interact.modifiers.restrictSize({
// max: { width: 350, y: 200 },
// }),
interact.modifiers.spring({ allowResume: true }),
// interact.modifiers.avoid({ targets: ['.item'] }),
interact.modifiers.transform(),
],
})
.on('resizemove', (event) => {
console.log(event.rect.width / event.rect.height)
})
.on('resize drag', interact.feedback.dragResize())
================================================
FILE: jest.config.ts
================================================
import type { Config } from '@jest/types'
import { sourcesGlob } from './scripts/utils'
const config: Config.InitialOptions = {
preset: 'vijest',
coverageThreshold: {
global: {
statements: 59,
branches: 48,
functions: 58,
lines: 59,
},
},
// collectCoverage: true,
collectCoverageFrom: [sourcesGlob],
coveragePathIgnorePatterns: ['[\\\\/]_', '\\.d\\.ts$', '@interactjs[\\\\/](rebound|symbol-tree)[\\\\/]'],
coverageReporters: ['json', 'text', ['lcov', { projectRoot: 'packages/@interactjs' }]],
}
export default config
================================================
FILE: lerna.json
================================================
{
"version": "0.0.0",
"packages": [
"@interactjs/*",
"./interactjs"
]
}
================================================
FILE: package.json
================================================
{
"name": "@interactjs/_dev",
"version": "1.10.27",
"private": true,
"directories": {
"bin": "./bin"
},
"scripts": {
"bootstrap": "yarn install --pure-lockfile --prefer-offline --silent && sh bin/_link",
"start": "_add_plugin_indexes && vite serve",
"build": "yarn build:docs && yarn build:bundle && _add_plugin_indexes && yarn build:types && yarn build:esnext",
"build:docs": "yarn typedoc",
"build:bundle": "rollup -c bundle.rollup.config.cjs",
"build:types": "_types",
"build:esnext": "_add_plugin_indexes && rollup -c esnext.rollup.config.cjs",
"test": "jest",
"test:debug": "node --inspect node_modules/.bin/jest --no-cache --runInBand ",
"tsc_lint_test": "_add_plugin_indexes && tsc -b -f && _lint && yarn test",
"prepare": "bin/_link; husky install"
},
"homepage": "https://interactjs.io/pro",
"description": "",
"devDependencies": {
"@babel/core": "^7.18.2",
"@babel/plugin-proposal-export-default-from": "^7.17.12",
"@babel/plugin-proposal-optional-catch-binding": "^7.16.7",
"@babel/plugin-proposal-optional-chaining": "^7.17.12",
"@babel/plugin-transform-class-properties": "^7.23.3",
"@babel/plugin-transform-runtime": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@babel/preset-typescript": "^7.17.12",
"@babel/runtime": "^7.18.3",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@testing-library/dom": "^9.3.3",
"@testing-library/user-event": "^14.5.1",
"@types/jest": "27",
"@types/node": "^17.0.42",
"@types/react": "^18.2.43",
"@types/shelljs": "^0.8.11",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"@vitejs/plugin-vue": "^4.5.2",
"@vue/babel-plugin-jsx": "^1.1.5",
"@vue/compiler-sfc": "^3.3.11",
"@vue/reactivity": "^3.3.11",
"@vue/runtime-dom": "^3.3.11",
"@vue/test-utils": "^2.4.2",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-plugin-syntax-jsx": "^6.18.0",
"bulma": "^0.9.4",
"del": "^7.1.0",
"eslint": "^8.17.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-standard": "^17.0.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-markdown": "^3.0.1",
"eslint-plugin-n": "^16.3.1",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-require-path-exists": "^1.1.9",
"eslint-plugin-tsdoc": "^0.2.17",
"eslint-plugin-vue": "^9.1.1",
"fs-extra": "^11.2.0",
"glob": "^10.3.10",
"hash-sum": "^2.0.0",
"husky": "8.0.3",
"jest": "27",
"lint-staged": "^15.2.0",
"mkdirp": "^3.0.1",
"path-browserify": "^1.0.1",
"prettier": "^3.1.1",
"promise-polyfill": "^8.2.3",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"rebound": "^0.1.0",
"resolve": "^1.22.0",
"rollup": "4.7.0",
"semver": "^7.3.7",
"serve-index": "^1.9.1",
"shelljs": "^0.8.5",
"stylelint": "^16.0.1",
"stylelint-config-css-modules": "^4.2.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.2.0",
"stylelint-config-standard": "^35.0.0",
"temp": "^0.9.4",
"ts-node": "^10.9.2",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "^3.17.1",
"typescript": "^5.3.3",
"vijest": "^0.0.2",
"vite": "^5.0.7",
"vue": "^3.3.11",
"yargs": "^17.5.1"
},
"resolutions": {
"jackspeak": "2.1.1",
"query-string": "7.1.3"
},
"sideEffects": false,
"lint-staged": {
"**/*.((ts|js|cjs)?(x)|vue|md)": "bin/_lint --fix",
"**/*.(yaml|yml|json|css)": "prettier --check --write",
"**/*.css": [
"stylelint --fix"
]
},
"license": "MIT"
}
================================================
FILE: packages/.eslintrc.cjs
================================================
module.exports = {
extends: '../.eslintrc.cjs',
env: { browser: true, node: false },
rules: {
'no-console': 2,
strict: [2, 'never'],
'no-restricted-syntax': ['error', 'Generator', 'ExperimentalRestProperty', 'ExperimentalSpreadProperty'],
},
overrides: [
{
files: '**/*.spec.ts',
env: { browser: true, node: true },
rules: { 'no-restricted-syntax': 'off', 'no-console': 'off' },
},
],
}
================================================
FILE: packages/@interactjs/actions/README.md
================================================
<h2>
This package is an internal part of <a
href="https://www.npmjs.com/package/interactjs">interactjs</a> and is not meant
to be used independently as each update may introduce breaking changes
</h2>
================================================
FILE: packages/@interactjs/actions/actions.spec.ts
================================================
import type { Scope } from '@interactjs/core/scope'
import * as helpers from '@interactjs/core/tests/_helpers'
import type { ActionName } from '@interactjs/core/types'
import * as pointerUtils from '@interactjs/utils/pointerUtils'
import actions from './plugin'
describe('actions integration', () => {
const scope: Scope = helpers.mockScope()
const event = pointerUtils.coordsToEvent(pointerUtils.newCoords())
const element = scope.document.body
scope.usePlugin(actions)
const interactable = scope.interactables.new(element)
// make a dropzone
scope.interactables.new(scope.document.documentElement).dropzone({})
const interaction1 = scope.interactions.new({})
interaction1.pointerDown(event, event, element)
for (const name in scope.actions.map) {
test(`${name} interaction starts and stops as expected`, () => {
interaction1.start({ name: name as ActionName }, interactable, element)
interaction1.stop()
expect(() => {
interaction1.interacting()
}).not.toThrow()
expect(interaction1.interacting()).toBe(false)
})
}
const actionNames = Object.keys(scope.actions.map)
for (const order of [actionNames, [...actionNames].reverse()] as ActionName[][]) {
const interaction2 = scope.interactions.new({})
for (const name of order) {
test(`${name} interaction starts, moves and ends as expected`, () => {
expect(() => {
interaction2.start({ name }, interactable, element)
interaction2.pointerMove(event, event, element)
interaction2.pointerUp(event, event, element, element)
}).not.toThrow()
expect(interaction2.interacting()).toBe<boolean>(false)
})
}
}
})
================================================
FILE: packages/@interactjs/actions/drag/drag.spec.ts
================================================
import type { Interactable } from '@interactjs/core/Interactable'
import type { InteractEvent } from '@interactjs/core/InteractEvent'
import * as helpers from '@interactjs/core/tests/_helpers'
import extend from '@interactjs/utils/extend'
import * as pointerUtils from '@interactjs/utils/pointerUtils'
import drag from './plugin'
describe('actions/drag', () => {
test('drag action init', () => {
const scope = helpers.mockScope()
scope.usePlugin(drag)
expect(scope.actions.map.drag).toBeTruthy()
expect(scope.actions.methodDict.drag).toBe('draggable')
expect(typeof scope.Interactable.prototype.draggable).toBe('function')
})
describe('interactable.draggable method', () => {
const interactable = {
options: {
drag: {},
},
draggable: drag.draggable,
setPerAction: () => {
calledSetPerAction = true
},
setOnEvents: () => {
calledSetOnEvents = true
},
} as unknown as Interactable
let calledSetPerAction = false
let calledSetOnEvents = false
test('args types', () => {
expect(interactable.draggable()).toEqual(interactable.options.drag)
interactable.draggable(true)
expect(interactable.options.drag.enabled).toBe(true)
interactable.draggable(false)
expect(interactable.options.drag.enabled).toBe(false)
interactable.draggable({})
expect(interactable.options.drag.enabled).toBe(true)
expect(calledSetOnEvents).toBe(true)
expect(calledSetPerAction).toBe(true)
interactable.draggable({ enabled: false })
expect(interactable.options.drag.enabled).toBe(false)
})
const axisSettings = {
lockAxis: ['x', 'y', 'xy', 'start'],
startAxis: ['x', 'y', 'xy'],
}
for (const axis in axisSettings) {
for (const value of axisSettings[axis]) {
test(`\`${axis}: ${value}\` is set correctly`, () => {
interactable.draggable({ [axis]: value })
expect(interactable.options.drag[axis]).toBe(value)
})
}
}
})
describe('drag axis', () => {
const scope = helpers.mockScope()
scope.usePlugin(drag)
const interaction = scope.interactions.new({})
const element = {}
const interactable = {
options: {
drag: {},
},
target: element,
} as Interactable
const iEvent = { page: {}, client: {}, delta: {}, type: 'dragmove' } as InteractEvent
const opposites = { x: 'y', y: 'x' }
const eventCoords = {
page: { x: -1, y: -2 },
client: { x: -3, y: -4 },
delta: { x: -5, y: -6 },
timeStamp: 0,
}
const coords = helpers.newCoordsSet()
resetCoords()
interaction.prepared = { name: 'drag', axis: 'xy' }
interaction.interactable = interactable
test('xy (any direction)', () => {
scope.fire('interactions:before-action-move', { interaction } as any)
expect(interaction.coords.start).toEqual(coords.start)
expect(interaction.coords.delta).toEqual(coords.delta)
scope.fire('interactions:action-move', { iEvent, interaction } as any)
expect(iEvent.page).toEqual(eventCoords.page)
expect(iEvent.delta).toEqual(eventCoords.delta)
})
for (const axis in opposites) {
const opposite = opposites[axis]
test(`${axis}-axis`, () => {
resetCoords()
interaction.prepared.axis = axis as any
scope.fire('interactions:action-move', { iEvent, interaction } as any)
expect(iEvent.delta).toEqual({
[opposite]: 0,
[axis]: eventCoords.delta[axis],
})
expect(iEvent.page).toEqual({
[opposite]: coords.start.page[opposite],
[axis]: eventCoords.page[axis],
})
expect(iEvent.page[axis]).toBe(eventCoords.page[axis])
expect(iEvent.client[opposite]).toBe(coords.start.client[opposite])
expect(iEvent.client[axis]).toBe(eventCoords.client[axis])
})
}
function resetCoords() {
pointerUtils.copyCoords(iEvent, eventCoords)
extend(iEvent.delta, eventCoords.delta)
for (const prop in coords) {
pointerUtils.copyCoords(interaction.coords[prop], coords[prop])
}
}
})
})
================================================
FILE: packages/@interactjs/actions/drag/plugin.ts
================================================
import type { Interactable } from '@interactjs/core/Interactable'
import type { InteractEvent } from '@interactjs/core/InteractEvent'
import type { PerActionDefaults } from '@interactjs/core/options'
import type { Scope, Plugin } from '@interactjs/core/scope'
import type { ListenersArg, OrBoolean } from '@interactjs/core/types'
import is from '@interactjs/utils/is'
declare module '@interactjs/core/Interactable' {
interface Interactable {
draggable(options: Partial<OrBoolean<DraggableOptions>> | boolean): this
draggable(): DraggableOptions
/**
* ```js
* interact(element).draggable({
* onstart: function (event) {},
* onmove : function (event) {},
* onend : function (event) {},
*
* // the axis in which the first movement must be
* // for the drag sequence to start
* // 'xy' by default - any direction
* startAxis: 'x' || 'y' || 'xy',
*
* // 'xy' by default - don't restrict to one axis (move in any direction)
* // 'x' or 'y' to restrict movement to either axis
* // 'start' to restrict movement to the axis the drag started in
* lockAxis: 'x' || 'y' || 'xy' || 'start',
*
* // max number of drags that can happen concurrently
* // with elements of this Interactable. Infinity by default
* max: Infinity,
*
* // max number of drags that can target the same element+Interactable
* // 1 by default
* maxPerElement: 2
* })
*
* var isDraggable = interact('element').draggable(); // true
* ```
*
* Get or set whether drag actions can be performed on the target
*
* @param options - true/false or An object with event
* listeners to be fired on drag events (object makes the Interactable
* draggable)
*/
draggable(options?: Partial<OrBoolean<DraggableOptions>> | boolean): this | DraggableOptions
}
}
declare module '@interactjs/core/options' {
interface ActionDefaults {
drag: DraggableOptions
}
}
declare module '@interactjs/core/types' {
interface ActionMap {
drag?: typeof drag
}
}
export type DragEvent = InteractEvent<'drag'>
export interface DraggableOptions extends PerActionDefaults {
startAxis?: 'x' | 'y' | 'xy'
lockAxis?: 'x' | 'y' | 'xy' | 'start'
oninertiastart?: ListenersArg
onstart?: ListenersArg
onmove?: ListenersArg
onend?: ListenersArg
}
function install(scope: Scope) {
const { actions, Interactable, defaults } = scope
Interactable.prototype.draggable = drag.draggable
actions.map.drag = drag
actions.methodDict.drag = 'draggable'
defaults.actions.drag = drag.defaults
}
function beforeMove({ interaction }) {
if (interaction.prepared.name !== 'drag') return
const axis = interaction.prepared.axis
if (axis === 'x') {
interaction.coords.cur.page.y = interaction.coords.start.page.y
interaction.coords.cur.client.y = interaction.coords.start.client.y
interaction.coords.velocity.client.y = 0
interaction.coords.velocity.page.y = 0
} else if (axis === 'y') {
interaction.coords.cur.page.x = interaction.coords.start.page.x
interaction.coords.cur.client.x = interaction.coords.start.client.x
interaction.coords.velocity.client.x = 0
interaction.coords.velocity.page.x = 0
}
}
function move({ iEvent, interaction }) {
if (interaction.prepared.name !== 'drag') return
const axis = interaction.prepared.axis
if (axis === 'x' || axis === 'y') {
const opposite = axis === 'x' ? 'y' : 'x'
iEvent.page[opposite] = interaction.coords.start.page[opposite]
iEvent.client[opposite] = interaction.coords.start.client[opposite]
iEvent.delta[opposite] = 0
}
}
const draggable: Interactable['draggable'] = function draggable(
this: Interactable,
options?: DraggableOptions | boolean,
): any {
if (is.object(options)) {
this.options.drag.enabled = options.enabled !== false
this.setPerAction('drag', options)
this.setOnEvents('drag', options)
if (/^(xy|x|y|start)$/.test(options.lockAxis)) {
this.options.drag.lockAxis = options.lockAxis
}
if (/^(xy|x|y)$/.test(options.startAxis)) {
this.options.drag.startAxis = options.startAxis
}
return this
}
if (is.bool(options)) {
this.options.drag.enabled = options
return this
}
return this.options.drag as DraggableOptions
}
const drag: Plugin = {
id: 'actions/drag',
install,
listeners: {
'interactions:before-action-move': beforeMove,
'interactions:action-resume': beforeMove,
// dragmove
'interactions:action-move': move,
'auto-start:check': (arg) => {
const { interaction, interactable, buttons } = arg
const dragOptions = interactable.options.drag
if (
!(dragOptions && dragOptions.enabled) ||
// check mouseButton setting if the pointer is down
(interaction.pointerIsDown &&
/mouse|pointer/.test(interaction.pointerType) &&
(buttons & interactable.options.drag.mouseButtons) === 0)
) {
return undefined
}
arg.action = {
name: 'drag',
axis: dragOptions.lockAxis === 'start' ? dragOptions.startAxis : dragOptions.lockAxis,
}
return false
},
},
draggable,
beforeMove,
move,
defaults: {
startAxis: 'xy',
lockAxis: 'xy',
} as DraggableOptions,
getCursor() {
return 'move'
},
filterEventType: (type: string) => type.search('drag') === 0,
}
export default drag
================================================
FILE: packages/@interactjs/actions/drop/DropEvent.spec.ts
================================================
import type { InteractEvent } from '@interactjs/core/InteractEvent'
import extend from '@interactjs/utils/extend'
import { DropEvent } from '../drop/DropEvent'
const dz1: any = {
target: 'dz1',
fire: jest.fn(),
}
const dz2: any = {
target: 'dz2',
fire: jest.fn(),
}
const el1: any = Symbol('el1')
const el2: any = Symbol('el2')
const interactable: any = Symbol('interactable')
const dragElement: any = Symbol('drag-el')
describe('DropEvent', () => {
describe('constructor', () => {
const interaction: any = { dropState: {} }
const dragEvent = Object.freeze({
interactable,
_interaction: interaction,
target: dragElement,
timeStamp: 10,
}) as InteractEvent
extend(interaction.dropState, {
activeDrops: [
{ dropzone: dz1, element: el1 },
{ dropzone: dz2, element: el2 },
],
cur: { dropzone: dz1, element: el1 },
prev: { dropzone: dz2, element: el2 },
events: {},
})
test('dropmove target, dropzone, relatedTarget props', () => {
const dropmove = new DropEvent(interaction.dropState, dragEvent, 'dropmove')
expect(dropmove.target).toBe(el1)
expect(dropmove.dropzone).toBe(dz1)
expect(dropmove.relatedTarget).toBe(dragElement)
})
test('dragleave target, dropzone, relatedTarget props', () => {
const dragleave = new DropEvent(interaction.dropState, dragEvent, 'dragleave')
expect(dragleave.target).toBe(el2)
expect(dragleave.dropzone).toBe(dz2)
expect(dragleave.relatedTarget).toBe(dragElement)
})
})
describe('reject', () => {
const interaction: any = { dropState: {} }
const dragEvent = Object.freeze({
interactable,
_interaction: interaction,
target: dragElement,
timeStamp: 10,
}) as InteractEvent
test('dropactivate.reject()', () => {
extend(interaction.dropState, {
activeDrops: [
{ dropzone: dz1, element: el1 },
{ dropzone: dz2, element: el2 },
],
cur: { dropzone: null, element: null },
prev: { dropzone: null, element: null },
events: {},
})
const dropactivate = new DropEvent(interaction.dropState, dragEvent, 'dropactivate')
dropactivate.dropzone = dz1
dropactivate.target = el1
dropactivate.reject()
// immediate propagation stopped on reject
expect(dropactivate.propagationStopped && dropactivate.immediatePropagationStopped).toBe(true)
// dropdeactivate is fired on rejected dropzone
expect(dz1.fire).toHaveBeenLastCalledWith(expect.objectContaining({ type: 'dropdeactivate' }))
// activeDrop of rejected dropactivate event is removed
expect(interaction.dropState.activeDrops).toEqual([{ dropzone: dz2, element: el2 }])
expect(interaction.dropState.cur).toEqual({ dropzone: null, element: null })
})
test('dropmove.reject()', () => {
extend(interaction.dropState, {
cur: { dropzone: dz1, element: el1 },
prev: { dropzone: null, element: null },
events: {},
})
const dropmove = new DropEvent(interaction.dropState, dragEvent, 'dropmove')
dropmove.reject()
// dropState.cur remains the same after rejecting non activate event,
expect(interaction.dropState.cur).toEqual({ dropzone: dz1, element: el1 })
expect(interaction.dropState.rejected).toBe(true)
// dragleave is fired on rejected dropzone
expect(dz1.fire).toHaveBeenLastCalledWith(expect.objectContaining({ type: 'dragleave' }))
})
})
test('stop[Immediate]Propagation()', () => {
const dropEvent = new DropEvent({ cur: {} } as any, {} as any, 'dragmove')
expect(dropEvent.propagationStopped || dropEvent.immediatePropagationStopped).toBe(false)
dropEvent.stopPropagation()
expect(dropEvent.propagationStopped).toBe(true)
expect(dropEvent.immediatePropagationStopped).toBe(false)
dropEvent.propagationStopped = false
dropEvent.stopImmediatePropagation()
expect(dropEvent.propagationStopped && dropEvent.immediatePropagationStopped).toBe(true)
})
})
================================================
FILE: packages/@interactjs/actions/drop/DropEvent.ts
================================================
import { BaseEvent } from '@interactjs/core/BaseEvent'
import type { Interactable } from '@interactjs/core/Interactable'
import type { InteractEvent } from '@interactjs/core/InteractEvent'
import type { Element } from '@interactjs/core/types'
import * as arr from '@interactjs/utils/arr'
import type { DropState } from './plugin'
export class DropEvent extends BaseEvent<'drag'> {
declare target: Element
dropzone: Interactable
dragEvent: InteractEvent<'drag'>
relatedTarget: Element
draggable: Interactable
propagationStopped = false
immediatePropagationStopped = false
/**
* Class of events fired on dropzones during drags with acceptable targets.
*/
constructor(dropState: DropState, dragEvent: InteractEvent<'drag'>, type: string) {
super(dragEvent._interaction)
const { element, dropzone } = type === 'dragleave' ? dropState.prev : dropState.cur
this.type = type
this.target = element
this.currentTarget = element
this.dropzone = dropzone
this.dragEvent = dragEvent
this.relatedTarget = dragEvent.target
this.draggable = dragEvent.interactable
this.timeStamp = dragEvent.timeStamp
}
/**
* If this is a `dropactivate` event, the dropzone element will be
* deactivated.
*
* If this is a `dragmove` or `dragenter`, a `dragleave` will be fired on the
* dropzone element and more.
*/
reject() {
const { dropState } = this._interaction
if (
this.type !== 'dropactivate' &&
(!this.dropzone || dropState.cur.dropzone !== this.dropzone || dropState.cur.element !== this.target)
) {
return
}
dropState.prev.dropzone = this.dropzone
dropState.prev.element = this.target
dropState.rejected = true
dropState.events.enter = null
this.stopImmediatePropagation()
if (this.type === 'dropactivate') {
const activeDrops = dropState.activeDrops
const index = arr.findIndex(
activeDrops,
({ dropzone, element }) => dropzone === this.dropzone && element === this.target,
)
dropState.activeDrops.splice(index, 1)
const deactivateEvent = new DropEvent(dropState, this.dragEvent, 'dropdeactivate')
deactivateEvent.dropzone = this.dropzone
deactivateEvent.target = this.target
this.dropzone.fire(deactivateEvent)
} else {
this.dropzone.fire(new DropEvent(dropState, this.dragEvent, 'dragleave'))
}
}
preventDefault() {}
stopPropagation() {
this.propagationStopped = true
}
stopImmediatePropagation() {
this.immediatePropagationStopped = this.propagationStopped = true
}
}
================================================
FILE: packages/@interactjs/actions/drop/drop.spec.ts
================================================
import type Interaction from '@interactjs/core/Interaction'
import * as helpers from '@interactjs/core/tests/_helpers'
import drop from '../drop/plugin'
describe('actions/drop', () => {
afterEach(() => {
document.body.innerHTML = ''
})
test('options', () => {
const { interactable } = helpers.testEnv({ plugins: [drop] })
const funcs = Object.freeze({
drop() {},
activate() {},
deactivate() {},
dropmove() {},
dragenter() {},
dragleave() {},
})
interactable.dropzone({
listeners: [funcs],
})
expect(interactable.events.types.drop[0]).toBe(funcs.drop)
expect(interactable.events.types.dropactivate[0]).toBe(funcs.activate)
expect(interactable.events.types.dropdeactivate[0]).toBe(funcs.deactivate)
expect(interactable.events.types.dropmove[0]).toBe(funcs.dropmove)
expect(interactable.events.types.dragenter[0]).toBe(funcs.dragenter)
expect(interactable.events.types.dragleave[0]).toBe(funcs.dragleave)
})
test('dynamicDrop', () => {
const { scope, interactable, down, start, move, interaction } = helpers.testEnv({ plugins: [drop] })
interactable.draggable({})
// no error with dynamicDrop === false
expect(() => {
scope.interactStatic.dynamicDrop(false)
down()
start({ name: 'drag' })
move()
interaction.end()
}).not.toThrow()
// no error with dynamicDrop === true
expect(() => {
scope.interactStatic.dynamicDrop(true)
down()
start({ name: 'drag' })
move()
interaction.end()
}).not.toThrow()
})
test('start', () => {
const { scope, interactable, down, start, move, interaction } = helpers.testEnv({ plugins: [drop] })
interactable.draggable({})
const dropzone = scope.interactables.new('[data-drop]').dropzone({})
const [dropEl1, dropEl2, dropEl3] = ['a', 'b', 'c'].map((id) => {
const dropEl = scope.document.createElement('div')
dropEl.dataset.drop = id
scope.document.body.appendChild(dropEl)
return dropEl
})
// rejet imeediately on activate
dropzone.on('dropactivate', (event) => {
if (event.target === dropEl1 || event.target === dropEl2) {
event.reject()
}
})
const onActionsDropStart = jest.fn((arg: { interaction: Interaction }) => {
const activeDrops = [...arg.interaction.dropState!.activeDrops]
// actions/drop:start is fired with all activeDrops
expect(activeDrops.map((activeDrop) => activeDrop.element)).toEqual([dropEl3])
})
scope.addListeners({ 'actions/drop:start': onActionsDropStart })
const onDeactivate = jest.fn()
dropzone.on('dropdeactivate', onDeactivate)
down()
start({ name: 'drag' })
move()
expect(onActionsDropStart).toHaveBeenCalledTimes(1)
// rejected dropzones are removed from activeDrops
expect(interaction.dropState!.activeDrops.map((d) => d.element)).toEqual([dropEl3])
// rejected dropzones are deactivated
expect(onDeactivate.mock.calls.map((arg) => arg[0].target)).toEqual([dropEl1, dropEl2])
interaction.end()
})
test('targeting', () => {
const interactionTarget = document.body.appendChild(document.createElement('div'))
interactionTarget.id = 'target'
const { scope, interactable, down, start, move, up, coords } = helpers.testEnv({
plugins: [drop],
target: interactionTarget,
})
interactable.draggable({})
const [dropElA, dropElB, dropElC] = ['a', 'b', 'c'].map((id) => {
const dropEl = scope.document.createElement('div')
dropEl.dataset.drop = id
scope.document.body.appendChild(dropEl)
return dropEl
})
const onActivate = jest.fn((event) => event.target)
const onDeactivate = jest.fn((event) => event.target)
const onDragenter = jest.fn()
const dropzone = scope.interactables
.new('[data-drop]')
.dropzone({
checker: () => true,
})
.on({ dropactivate: onActivate, dropdeactivate: onDeactivate, dragenter: onDragenter })
down()
start({ name: 'drag' })
expect(onActivate.mock.results.map(({ value }) => value)).toEqual([dropElA, dropElB, dropElC])
expect(onDeactivate.mock.calls).toEqual([])
expect(onDragenter.mock.calls).toEqual([])
coords.page.x++
move()
expect(onDragenter.mock.calls.map(([{ target, relatedTarget }]) => [target, relatedTarget])).toEqual([
[dropElC, interactionTarget],
])
onDragenter.mockClear()
// only b drop
dropzone.dropzone({
checker: (_dragEvent, _event, _dropped, _dropzone, dropElement) => dropElement.dataset.drop === 'b',
})
coords.page.x++
move()
expect(onDragenter.mock.calls.map((args) => [args[0].target, args[0].relatedTarget])).toEqual([
[dropElB, interactionTarget],
])
up()
// all dropzones are deactivated
expect(onDeactivate.mock.results.map(({ value }) => value)).toEqual([dropElA, dropElB, dropElC])
})
})
================================================
FILE: packages/@interactjs/actions/drop/plugin.ts
================================================
import type { Interactable } from '@interactjs/core/Interactable'
import type { EventPhase, InteractEvent } from '@interactjs/core/InteractEvent'
import type { Interaction, DoPhaseArg } from '@interactjs/core/Interaction'
import type { PerActionDefaults } from '@interactjs/core/options'
import type { Scope, Plugin } from '@interactjs/core/scope'
import type { Element, PointerEventType, Rect, ListenersArg } from '@interactjs/core/types'
import * as domUtils from '@interactjs/utils/domUtils'
import extend from '@interactjs/utils/extend'
import getOriginXY from '@interactjs/utils/getOriginXY'
import is from '@interactjs/utils/is'
import normalizeListeners from '@interactjs/utils/normalizeListeners'
import * as pointerUtils from '@interactjs/utils/pointerUtils'
/* eslint-disable import/no-duplicates -- for typescript module augmentations */
import '../drag/plugin'
import type { DragEvent } from '../drag/plugin'
import drag from '../drag/plugin'
/* eslint-enable import/no-duplicates */
import { DropEvent } from './DropEvent'
export type DropFunctionChecker = (
dragEvent: any, // related drag operation
event: any, // touch or mouse EventEmitter
dropped: boolean, // default checker result
dropzone: Interactable, // dropzone interactable
dropElement: Element, // drop zone element
draggable: Interactable, // draggable's Interactable
draggableElement: Element, // dragged element
) => boolean
export interface DropzoneOptions extends PerActionDefaults {
accept?:
| string
| Element
| (({ dropzone, draggableElement }: { dropzone: Interactable; draggableElement: Element }) => boolean)
// How the overlap is checked on the drop zone
overlap?: 'pointer' | 'center' | number
checker?: DropFunctionChecker
ondropactivate?: ListenersArg
ondropdeactivate?: ListenersArg
ondragenter?: ListenersArg
ondragleave?: ListenersArg
ondropmove?: ListenersArg
ondrop?: ListenersArg
}
export interface DropzoneMethod {
(this: Interactable, options: DropzoneOptions | boolean): Interactable
(): DropzoneOptions
}
declare module '@interactjs/core/Interactable' {
interface Interactable {
/**
*
* ```js
* interact('.drop').dropzone({
* accept: '.can-drop' || document.getElementById('single-drop'),
* overlap: 'pointer' || 'center' || zeroToOne
* }
* ```
*
* Returns or sets whether draggables can be dropped onto this target to
* trigger drop events
*
* Dropzones can receive the following events:
* - `dropactivate` and `dropdeactivate` when an acceptable drag starts and ends
* - `dragenter` and `dragleave` when a draggable enters and leaves the dropzone
* - `dragmove` when a draggable that has entered the dropzone is moved
* - `drop` when a draggable is dropped into this dropzone
*
* Use the `accept` option to allow only elements that match the given CSS
* selector or element. The value can be:
*
* - **an Element** - only that element can be dropped into this dropzone.
* - **a string**, - the element being dragged must match it as a CSS selector.
* - **`null`** - accept options is cleared - it accepts any element.
*
* Use the `overlap` option to set how drops are checked for. The allowed
* values are:
*
* - `'pointer'`, the pointer must be over the dropzone (default)
* - `'center'`, the draggable element's center must be over the dropzone
* - a number from 0-1 which is the `(intersection area) / (draggable area)`.
* e.g. `0.5` for drop to happen when half of the area of the draggable is
* over the dropzone
*
* Use the `checker` option to specify a function to check if a dragged element
* is over this Interactable.
*
* @param options - The new options to be set
*/
dropzone(options: DropzoneOptions | boolean): Interactable
/** @returns The current setting */
dropzone(): DropzoneOptions
/**
* ```js
* interact(target)
* .dropChecker(function(dragEvent, // related dragmove or dragend event
* event, // TouchEvent/PointerEvent/MouseEvent
* dropped, // bool result of the default checker
* dropzone, // dropzone Interactable
* dropElement, // dropzone elemnt
* draggable, // draggable Interactable
* draggableElement) {// draggable element
*
* return dropped && event.target.hasAttribute('allow-drop')
* }
* ```
*/
dropCheck(
dragEvent: InteractEvent,
event: PointerEventType,
draggable: Interactable,
draggableElement: Element,
dropElemen: Element,
rect: any,
): boolean
}
}
declare module '@interactjs/core/Interaction' {
interface Interaction {
dropState?: DropState
}
}
declare module '@interactjs/core/InteractEvent' {
interface InteractEvent {
/** @internal */
prevDropzone?: Interactable
dropzone?: Interactable
dragEnter?: Element
dragLeave?: Element
}
}
declare module '@interactjs/core/options' {
interface ActionDefaults {
drop: DropzoneOptions
}
}
declare module '@interactjs/core/scope' {
interface Scope {
dynamicDrop?: boolean
}
interface SignalArgs {
'actions/drop:start': DropSignalArg
'actions/drop:move': DropSignalArg
'actions/drop:end': DropSignalArg
}
}
declare module '@interactjs/core/types' {
interface ActionMap {
drop?: typeof drop
}
}
declare module '@interactjs/core/InteractStatic' {
interface InteractStatic {
/**
* Returns or sets whether the dimensions of dropzone elements are calculated
* on every dragmove or only on dragstart for the default dropChecker
*
* @param {boolean} [newValue] True to check on each move. False to check only
* before start
* @return {boolean | interact} The current setting or interact
*/
dynamicDrop: (newValue?: boolean) => boolean | this
}
}
interface DropSignalArg {
interaction: Interaction<'drag'>
dragEvent: DragEvent
}
export interface ActiveDrop {
dropzone: Interactable
element: Element
rect: Rect
}
export interface DropState {
cur: {
// the dropzone a drag target might be dropped into
dropzone: Interactable
// the element at the time of checking
element: Element
}
prev: {
// the dropzone that was recently dragged away from
dropzone: Interactable
// the element at the time of checking
element: Element
}
// wheather the potential drop was rejected from a listener
rejected: boolean
// the drop events related to the current drag event
events: FiredDropEvents
activeDrops: ActiveDrop[]
}
function install(scope: Scope) {
const { actions, interactStatic: interact, Interactable, defaults } = scope
scope.usePlugin(drag)
Interactable.prototype.dropzone = function (this: Interactable, options) {
return dropzoneMethod(this, options)
} as Interactable['dropzone']
Interactable.prototype.dropCheck = function (
this: Interactable,
dragEvent,
event,
draggable,
draggableElement,
dropElement,
rect,
) {
return dropCheckMethod(this, dragEvent, event, draggable, draggableElement, dropElement, rect)
}
interact.dynamicDrop = function (newValue?: boolean) {
if (is.bool(newValue)) {
// if (dragging && scope.dynamicDrop !== newValue && !newValue) {
// calcRects(dropzones)
// }
scope.dynamicDrop = newValue
return interact
}
return scope.dynamicDrop!
}
extend(actions.phaselessTypes, {
dragenter: true,
dragleave: true,
dropactivate: true,
dropdeactivate: true,
dropmove: true,
drop: true,
})
actions.methodDict.drop = 'dropzone'
scope.dynamicDrop = false
defaults.actions.drop = drop.defaults
}
function collectDropzones({ interactables }: Scope, draggableElement: Element) {
const drops: ActiveDrop[] = []
// collect all dropzones and their elements which qualify for a drop
for (const dropzone of interactables.list) {
if (!dropzone.options.drop.enabled) {
continue
}
const accept = dropzone.options.drop.accept
// test the draggable draggableElement against the dropzone's accept setting
if (
(is.element(accept) && accept !== draggableElement) ||
(is.string(accept) && !domUtils.matchesSelector(draggableElement, accept)) ||
(is.func(accept) && !accept({ dropzone, draggableElement }))
) {
continue
}
for (const dropzoneElement of dropzone.getAllElements()) {
if (dropzoneElement !== draggableElement) {
drops.push({
dropzone,
element: dropzoneElement,
rect: dropzone.getRect(dropzoneElement),
})
}
}
}
return drops
}
function fireActivationEvents(activeDrops: ActiveDrop[], event: DropEvent) {
// loop through all active dropzones and trigger event
for (const { dropzone, element } of activeDrops.slice()) {
event.dropzone = dropzone
// set current element as event target
event.target = element
dropzone.fire(event)
event.propagationStopped = event.immediatePropagationStopped = false
}
}
// return a new array of possible drops. getActiveDrops should always be
// called when a drag has just started or a drag event happens while
// dynamicDrop is true
function getActiveDrops(scope: Scope, dragElement: Element) {
// get dropzones and their elements that could receive the draggable
const activeDrops = collectDropzones(scope, dragElement)
for (const activeDrop of activeDrops) {
activeDrop.rect = activeDrop.dropzone.getRect(activeDrop.element)
}
return activeDrops
}
function getDrop(
{ dropState, interactable: draggable, element: dragElement }: Interaction,
dragEvent,
pointerEvent,
) {
const validDrops: Element[] = []
// collect all dropzones and their elements which qualify for a drop
for (const { dropzone, element: dropzoneElement, rect } of dropState.activeDrops) {
const isValid = dropzone.dropCheck(
dragEvent,
pointerEvent,
draggable!,
dragElement!,
dropzoneElement,
rect,
)
validDrops.push(isValid ? dropzoneElement : null)
}
// get the most appropriate dropzone based on DOM depth and order
const dropIndex = domUtils.indexOfDeepestElement(validDrops)
return dropState!.activeDrops[dropIndex] || null
}
function getDropEvents(interaction: Interaction, _pointerEvent, dragEvent: DragEvent) {
const dropState = interaction.dropState!
const dropEvents: Record<string, DropEvent | null> = {
enter: null,
leave: null,
activate: null,
deactivate: null,
move: null,
drop: null,
}
if (dragEvent.type === 'dragstart') {
dropEvents.activate = new DropEvent(dropState, dragEvent, 'dropactivate')
dropEvents.activate.target = null as never
dropEvents.activate.dropzone = null as never
}
if (dragEvent.type === 'dragend') {
dropEvents.deactivate = new DropEvent(dropState, dragEvent, 'dropdeactivate')
dropEvents.deactivate.target = null as never
dropEvents.deactivate.dropzone = null as never
}
if (dropState.rejected) {
return dropEvents
}
if (dropState.cur.element !== dropState.prev.element) {
// if there was a previous dropzone, create a dragleave event
if (dropState.prev.dropzone) {
dropEvents.leave = new DropEvent(dropState, dragEvent, 'dragleave')
dragEvent.dragLeave = dropEvents.leave.target = dropState.prev.element
dragEvent.prevDropzone = dropEvents.leave.dropzone = dropState.prev.dropzone
}
// if dropzone is not null, create a dragenter event
if (dropState.cur.dropzone) {
dropEvents.enter = new DropEvent(dropState, dragEvent, 'dragenter')
dragEvent.dragEnter = dropState.cur.element
dragEvent.dropzone = dropState.cur.dropzone
}
}
if (dragEvent.type === 'dragend' && dropState.cur.dropzone) {
dropEvents.drop = new DropEvent(dropState, dragEvent, 'drop')
dragEvent.dropzone = dropState.cur.dropzone
dragEvent.relatedTarget = dropState.cur.element
}
if (dragEvent.type === 'dragmove' && dropState.cur.dropzone) {
dropEvents.move = new DropEvent(dropState, dragEvent, 'dropmove')
dragEvent.dropzone = dropState.cur.dropzone
}
return dropEvents
}
type FiredDropEvents = Partial<
Record<'leave' | 'enter' | 'move' | 'drop' | 'activate' | '
gitextract_w464gyf3/ ├── .browserslistrc ├── .codeclimate.yml ├── .eslintignore ├── .eslintrc.cjs ├── .github/ │ ├── stale.yml │ └── workflows/ │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .husky/ │ ├── .gitignore │ └── pre-commit ├── .npmignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .stylelintrc.cjs ├── .yarnrc ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── babel.config.cjs ├── bin/ │ ├── _add_plugin_indexes │ ├── _bundle │ ├── _check_deps │ ├── _clean │ ├── _link │ ├── _lint │ ├── _release │ ├── _types │ └── _version ├── bundle.rollup.config.cjs ├── docs/ │ ├── action-options.md │ ├── auto-start.md │ ├── draggable.md │ ├── dropzone.md │ ├── events.md │ ├── faq.md │ ├── gesturable.md │ ├── inertia.md │ ├── installation.md │ ├── introduction.md │ ├── migrating.md │ ├── modifiers.md │ ├── reflow.md │ ├── resizable.md │ ├── restriction.md │ ├── snapping.md │ └── tooling.md ├── esnext.rollup.config.cjs ├── examples/ │ ├── .eslintignore │ ├── .eslintrc.cjs │ ├── dropzones/ │ │ ├── index.css │ │ ├── index.html │ │ └── index.js │ ├── events/ │ │ ├── index.css │ │ ├── index.html │ │ └── index.js │ ├── iframes/ │ │ ├── bottom.html │ │ ├── index.css │ │ ├── index.html │ │ ├── index.js │ │ └── middle.html │ ├── snap/ │ │ ├── index.css │ │ ├── index.html │ │ └── index.js │ ├── sortable/ │ │ ├── index.html │ │ ├── react.js │ │ ├── shared.js │ │ ├── style.css │ │ └── vue.js │ ├── star/ │ │ ├── index.css │ │ └── index.js │ ├── svg-editor/ │ │ ├── index.html │ │ └── index.js │ └── transform/ │ ├── index.html │ └── index.js ├── jest.config.ts ├── lerna.json ├── package.json ├── packages/ │ ├── .eslintrc.cjs │ ├── @interactjs/ │ │ ├── actions/ │ │ │ ├── README.md │ │ │ ├── actions.spec.ts │ │ │ ├── drag/ │ │ │ │ ├── drag.spec.ts │ │ │ │ └── plugin.ts │ │ │ ├── drop/ │ │ │ │ ├── DropEvent.spec.ts │ │ │ │ ├── DropEvent.ts │ │ │ │ ├── drop.spec.ts │ │ │ │ └── plugin.ts │ │ │ ├── gesture/ │ │ │ │ ├── gesture.spec.ts │ │ │ │ └── plugin.ts │ │ │ ├── package.json │ │ │ ├── plugin.ts │ │ │ └── resize/ │ │ │ ├── plugin.ts │ │ │ └── resize.spec.ts │ │ ├── auto-scroll/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── auto-start/ │ │ │ ├── InteractableMethods.ts │ │ │ ├── README.md │ │ │ ├── autoStart.spec.ts │ │ │ ├── base.ts │ │ │ ├── dragAxis.ts │ │ │ ├── hold.spec.ts │ │ │ ├── hold.ts │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── core/ │ │ │ ├── BaseEvent.ts │ │ │ ├── Eventable.spec.ts │ │ │ ├── Eventable.ts │ │ │ ├── InteractEvent.ts │ │ │ ├── InteractStatic.ts │ │ │ ├── Interactable.spec.ts │ │ │ ├── Interactable.ts │ │ │ ├── InteractableSet.ts │ │ │ ├── Interaction.spec.ts │ │ │ ├── Interaction.ts │ │ │ ├── NativeTypes.ts │ │ │ ├── PointerInfo.ts │ │ │ ├── README.md │ │ │ ├── events.ts │ │ │ ├── interactablePreventDefault.spec.ts │ │ │ ├── interactablePreventDefault.ts │ │ │ ├── interactionFinder.spec.ts │ │ │ ├── interactionFinder.ts │ │ │ ├── interactions.spec.ts │ │ │ ├── interactions.ts │ │ │ ├── options.ts │ │ │ ├── package.json │ │ │ ├── scope.spec.ts │ │ │ ├── scope.ts │ │ │ ├── tests/ │ │ │ │ └── _helpers.ts │ │ │ └── types.ts │ │ ├── dev-tools/ │ │ │ ├── README.md │ │ │ ├── babel-plugin-prod.js │ │ │ ├── babel-plugin-prod.spec.ts │ │ │ ├── devTools.spec.ts │ │ │ ├── package.json │ │ │ ├── plugin.ts │ │ │ └── visualizer/ │ │ │ ├── plugin.stub.ts │ │ │ ├── plugin.ts │ │ │ ├── visualizer.spec.stub.ts │ │ │ ├── visualizer.spec.ts │ │ │ ├── vueModules.stub.ts │ │ │ └── vueModules.ts │ │ ├── inertia/ │ │ │ ├── README.md │ │ │ ├── inertia.spec.ts │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── interact/ │ │ │ ├── README.md │ │ │ ├── index.ts │ │ │ ├── interact.spec.ts │ │ │ └── package.json │ │ ├── interactjs/ │ │ │ ├── index.stub.ts │ │ │ ├── index.ts │ │ │ └── package.json │ │ ├── modifiers/ │ │ │ ├── Modification.ts │ │ │ ├── README.md │ │ │ ├── all.ts │ │ │ ├── aspectRatio.spec.ts │ │ │ ├── aspectRatio.ts │ │ │ ├── avoid/ │ │ │ │ ├── avoid.stub.ts │ │ │ │ └── avoid.ts │ │ │ ├── base.spec.ts │ │ │ ├── base.ts │ │ │ ├── noop.ts │ │ │ ├── package.json │ │ │ ├── plugin.ts │ │ │ ├── restrict/ │ │ │ │ ├── edges.spec.ts │ │ │ │ ├── edges.ts │ │ │ │ ├── pointer.spec.ts │ │ │ │ ├── pointer.ts │ │ │ │ ├── rect.ts │ │ │ │ ├── size.spec.ts │ │ │ │ └── size.ts │ │ │ ├── rubberband/ │ │ │ │ ├── rubberband.stub.ts │ │ │ │ └── rubberband.ts │ │ │ ├── snap/ │ │ │ │ ├── edges.spec.ts │ │ │ │ ├── edges.ts │ │ │ │ ├── pointer.spec.ts │ │ │ │ ├── pointer.ts │ │ │ │ ├── size.spec.ts │ │ │ │ └── size.ts │ │ │ ├── spring/ │ │ │ │ ├── spring.stub.ts │ │ │ │ └── spring.ts │ │ │ ├── transform/ │ │ │ │ ├── transform.stub.ts │ │ │ │ └── transform.ts │ │ │ └── types.ts │ │ ├── offset/ │ │ │ ├── offset.spec.ts │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── pointer-events/ │ │ │ ├── PointerEvent.spec.ts │ │ │ ├── PointerEvent.ts │ │ │ ├── README.md │ │ │ ├── base.spec.ts │ │ │ ├── base.ts │ │ │ ├── holdRepeat.spec.ts │ │ │ ├── holdRepeat.ts │ │ │ ├── interactableTargets.ts │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── reflow/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── plugin.ts │ │ │ └── reflow.spec.ts │ │ ├── snappers/ │ │ │ ├── all.ts │ │ │ ├── edgeTarget.stub.ts │ │ │ ├── edgeTarget.ts │ │ │ ├── elements.stub.ts │ │ │ ├── elements.ts │ │ │ ├── grid.ts │ │ │ ├── package.json │ │ │ └── plugin.ts │ │ ├── types/ │ │ │ ├── README.md │ │ │ ├── index.ts │ │ │ ├── package.json │ │ │ └── types.spec.ts │ │ └── utils/ │ │ ├── ElementState.stub.ts │ │ ├── ElementState.ts │ │ ├── README.md │ │ ├── arr.ts │ │ ├── browser.ts │ │ ├── center.ts │ │ ├── clone.ts │ │ ├── displace.stub.ts │ │ ├── displace.ts │ │ ├── domObjects.ts │ │ ├── domUtils.spec.ts │ │ ├── domUtils.ts │ │ ├── exchange.stub.ts │ │ ├── exchange.ts │ │ ├── extend.ts │ │ ├── getOriginXY.ts │ │ ├── hypot.ts │ │ ├── is.ts │ │ ├── isNonNativeEvent.ts │ │ ├── isWindow.ts │ │ ├── misc.ts │ │ ├── normalizeListeners.spec.ts │ │ ├── normalizeListeners.ts │ │ ├── package.json │ │ ├── pointerExtend.ts │ │ ├── pointerUtils.ts │ │ ├── raf.ts │ │ ├── rect.ts │ │ ├── shallowEqual.ts │ │ └── window.ts │ └── interactjs/ │ ├── .npmignore │ ├── LICENSE │ ├── README.md │ ├── bower.json │ ├── index.ts │ └── package.json ├── scripts/ │ ├── .eslintrc.cjs │ ├── addPluginIndexes.js │ ├── babel/ │ │ ├── absolute-imports.js │ │ ├── inline-env-vars.js │ │ ├── relative-imports.js │ │ └── vue-sfc.js │ ├── bin/ │ │ ├── _check_deps.js │ │ ├── add_plugin_indexes.js │ │ ├── bundle.js │ │ ├── clean.js │ │ ├── lint.js │ │ ├── release.js │ │ ├── types.js │ │ └── version.js │ ├── execTypes.js │ ├── getVersion.js │ ├── headers.js │ └── utils.js ├── shims.d.ts ├── test/ │ ├── .eslintrc.cjs │ └── fixtures/ │ ├── babelPluginProject/ │ │ ├── index.js │ │ └── node_modules/ │ │ └── @interactjs/ │ │ └── a/ │ │ ├── a.js │ │ ├── b/ │ │ │ ├── b.js │ │ │ └── index.js │ │ ├── package-main-file.js │ │ └── package.json │ └── dependentTsProject/ │ ├── index.ts │ └── tsconfig.json ├── tsconfig.json ├── typedoc.config.cjs ├── types.tsconfig.json ├── vijest.config.js └── vite.config.ts
SYMBOL INDEX (664 symbols across 104 files)
FILE: bundle.rollup.config.cjs
constant INPUT_EXTENSIONS (line 19) | const INPUT_EXTENSIONS = ['.ts', '.tsx', '.vue']
FILE: esnext.rollup.config.cjs
constant BUNDLED_DEPS (line 23) | const BUNDLED_DEPS = ['rebound']
constant INPUT_EXTENSIONS (line 24) | const INPUT_EXTENSIONS = ['.ts', '.tsx', '.vue']
method renderChunk (line 125) | async renderChunk(code, chunk, outputOptions) {
FILE: examples/dropzones/index.js
method start (line 15) | start(event) {
method move (line 20) | move(event) {
method end (line 32) | end(event) {
function setupDropzone (line 54) | function setupDropzone(target, accept) {
function addClass (line 102) | function addClass(element, className) {
function removeClass (line 110) | function removeClass(element, className) {
FILE: examples/events/index.js
function logEvent (line 29) | function logEvent(event) {
function changeTolerance (line 66) | function changeTolerance(event) {
FILE: examples/iframes/index.js
function setInteractables (line 1) | function setInteractables() {
FILE: examples/snap/index.js
function drawGrid (line 38) | function drawGrid(grid, gridOffset, range) {
function drawAnchors (line 74) | function drawAnchors(defaultRange) {
function drawSnap (line 108) | function drawSnap(snap) {
function circle (line 119) | function circle(x, y, radius, color) {
function dragMove (line 128) | function dragMove(event) {
function dragEnd (line 163) | function dragEnd(event) {
function anchorDragStart (line 171) | function anchorDragStart(event) {
function anchorDragMove (line 178) | function anchorDragMove(event) {
function anchorDragEnd (line 189) | function anchorDragEnd(event) {
function sliderChange (line 194) | function sliderChange() {
function modeChange (line 209) | function modeChange(event) {
function sliderInput (line 261) | function sliderInput(event) {
FILE: examples/sortable/shared.js
function sortListener (line 3) | function sortListener(event) {
function getData (line 7) | function getData() {
FILE: examples/sortable/vue.js
method data (line 9) | data() {
FILE: examples/star/index.js
function applyTransforms (line 28) | function applyTransforms(event) {
FILE: examples/svg-editor/index.js
class Rectangle (line 14) | class Rectangle {
method constructor (line 15) | constructor(x, y, w, h) {
method draw (line 31) | draw() {
method move (line 107) | move(event) {
FILE: packages/@interactjs/actions/drag/drag.spec.ts
function resetCoords (line 135) | function resetCoords() {
FILE: packages/@interactjs/actions/drag/plugin.ts
type Interactable (line 9) | interface Interactable {
type ActionDefaults (line 52) | interface ActionDefaults {
type ActionMap (line 58) | interface ActionMap {
type DragEvent (line 63) | type DragEvent = InteractEvent<'drag'>
type DraggableOptions (line 65) | interface DraggableOptions extends PerActionDefaults {
function install (line 74) | function install(scope: Scope) {
function beforeMove (line 85) | function beforeMove({ interaction }) {
function move (line 105) | function move({ iEvent, interaction }) {
method getCursor (line 186) | getCursor() {
FILE: packages/@interactjs/actions/drop/DropEvent.ts
class DropEvent (line 9) | class DropEvent extends BaseEvent<'drag'> {
method constructor (line 21) | constructor(dropState: DropState, dragEvent: InteractEvent<'drag'>, ty...
method reject (line 43) | reject() {
method preventDefault (line 81) | preventDefault() {}
method stopPropagation (line 83) | stopPropagation() {
method stopImmediatePropagation (line 87) | stopImmediatePropagation() {
FILE: packages/@interactjs/actions/drop/drop.spec.ts
method drop (line 15) | drop() {}
method activate (line 16) | activate() {}
method deactivate (line 17) | deactivate() {}
method dropmove (line 18) | dropmove() {}
method dragenter (line 19) | dragenter() {}
method dragleave (line 20) | dragleave() {}
FILE: packages/@interactjs/actions/drop/plugin.ts
type DropFunctionChecker (line 23) | type DropFunctionChecker = (
type DropzoneOptions (line 33) | interface DropzoneOptions extends PerActionDefaults {
type DropzoneMethod (line 50) | interface DropzoneMethod {
type Interactable (line 56) | interface Interactable {
type Interaction (line 127) | interface Interaction {
type InteractEvent (line 133) | interface InteractEvent {
type ActionDefaults (line 143) | interface ActionDefaults {
type Scope (line 149) | interface Scope {
type SignalArgs (line 153) | interface SignalArgs {
type ActionMap (line 161) | interface ActionMap {
type InteractStatic (line 167) | interface InteractStatic {
type DropSignalArg (line 180) | interface DropSignalArg {
type ActiveDrop (line 185) | interface ActiveDrop {
type DropState (line 191) | interface DropState {
function install (line 211) | function install(scope: Scope) {
function collectDropzones (line 260) | function collectDropzones({ interactables }: Scope, draggableElement: El...
function fireActivationEvents (line 294) | function fireActivationEvents(activeDrops: ActiveDrop[], event: DropEven...
function getActiveDrops (line 309) | function getActiveDrops(scope: Scope, dragElement: Element) {
function getDrop (line 320) | function getDrop(
function getDropEvents (line 346) | function getDropEvents(interaction: Interaction, _pointerEvent, dragEven...
type FiredDropEvents (line 406) | type FiredDropEvents = Partial<
function fireDropEvents (line 410) | function fireDropEvents(interaction: Interaction, events: FiredDropEvent...
function onEventCreated (line 435) | function onEventCreated({ interaction, iEvent, event }: DoPhaseArg<'drag...
function dropzoneMethod (line 464) | function dropzoneMethod(interactable: Interactable, options?: DropzoneOp...
function dropCheckMethod (line 533) | function dropCheckMethod(
FILE: packages/@interactjs/actions/gesture/gesture.spec.ts
function getGestureProps (line 9) | function getGestureProps(event: GestureEvent) {
FILE: packages/@interactjs/actions/gesture/plugin.ts
type Interaction (line 11) | interface Interaction {
type Interactable (line 23) | interface Interactable {
type ActionDefaults (line 52) | interface ActionDefaults {
type ActionMap (line 58) | interface ActionMap {
type GesturableOptions (line 63) | interface GesturableOptions extends PerActionDefaults {
type GestureEvent (line 69) | interface GestureEvent extends InteractEvent<'gesture'> {
type GestureSignalArg (line 79) | interface GestureSignalArg extends DoPhaseArg<'gesture', EventPhase> {
function install (line 84) | function install(scope: Scope) {
function updateGestureProps (line 114) | function updateGestureProps({ interaction, iEvent, phase }: GestureSigna...
method getCursor (line 199) | getCursor() {
FILE: packages/@interactjs/actions/plugin.ts
method install (line 17) | install(scope: Scope) {
FILE: packages/@interactjs/actions/resize/plugin.ts
type EdgeName (line 20) | type EdgeName = 'top' | 'left' | 'bottom' | 'right'
type Interactable (line 23) | interface Interactable {
type Interaction (line 76) | interface Interaction<T extends ActionName | null = ActionName> {
type ActionDefaults (line 85) | interface ActionDefaults {
type ActionMap (line 91) | interface ActionMap {
type ResizableOptions (line 96) | interface ResizableOptions extends PerActionDefaults {
type ResizeEvent (line 110) | interface ResizeEvent<P extends EventPhase = EventPhase> extends Interac...
function install (line 115) | function install(scope: Scope) {
function resizeChecker (line 138) | function resizeChecker(arg) {
function resizable (line 203) | function resizable(interactable: Interactable, options: OrBoolean<Resiza...
function checkResizeEdge (line 231) | function checkResizeEdge(
function initCursors (line 300) | function initCursors(browser: typeof import('@interactjs/utils/browser')...
function start (line 333) | function start({ iEvent, interaction }: { iEvent: InteractEvent<any, any...
function move (line 360) | function move({ iEvent, interaction }: { iEvent: InteractEvent<any, any>...
function end (line 412) | function end({ iEvent, interaction }: { iEvent: InteractEvent<any, any>;...
function updateEventAxes (line 422) | function updateEventAxes({
method getCursor (line 496) | getCursor({ edges, axis, name }: ActionProps) {
FILE: packages/@interactjs/actions/resize/resize.spec.ts
function hasResizeProps (line 141) | function hasResizeProps(event: ResizeEvent) {
FILE: packages/@interactjs/auto-scroll/plugin.ts
type Scope (line 12) | interface Scope {
type Interaction (line 18) | interface Interaction {
type PerActionDefaults (line 24) | interface PerActionDefaults {
type AutoScrollOptions (line 29) | interface AutoScrollOptions {
function install (line 38) | function install(scope: Scope) {
method start (line 74) | start(interaction: Interaction) {
method stop (line 84) | stop() {
method scroll (line 93) | scroll() {
method check (line 147) | check(interactable: Interactable, actionName: ActionName) {
method onInteractionMove (line 152) | onInteractionMove<T extends ActionName>({
function getContainer (line 207) | function getContainer(value: any, interactable: Interactable, element: E...
function getScroll (line 213) | function getScroll(container: any) {
function getScrollSize (line 221) | function getScrollSize(container: any) {
function getScrollSizeDelta (line 229) | function getScrollSizeDelta<T extends ActionName>(
FILE: packages/@interactjs/auto-start/InteractableMethods.ts
type Interactable (line 9) | interface Interactable {
function install (line 120) | function install(scope: Scope) {
function defaultActionChecker (line 154) | function defaultActionChecker(
function styleCursor (line 184) | function styleCursor(this: Interactable, newValue?: boolean) {
function actionChecker (line 200) | function actionChecker(this: Interactable, checker?: any) {
FILE: packages/@interactjs/auto-start/base.ts
type InteractStatic (line 23) | interface InteractStatic {
type Scope (line 38) | interface Scope {
type SignalArgs (line 42) | interface SignalArgs {
type BaseDefaults (line 52) | interface BaseDefaults {
type PerActionDefaults (line 58) | interface PerActionDefaults {
type CheckSignalArg (line 73) | interface CheckSignalArg {
type AutoStart (line 81) | interface AutoStart {
function install (line 88) | function install(scope: Scope) {
function prepareOnDown (line 118) | function prepareOnDown(
function prepareOnMove (line 128) | function prepareOnMove(
function startOnMove (line 138) | function startOnMove(arg: SignalArgs['interactions:move'], scope: Scope) {
function clearCursorOnStop (line 169) | function clearCursorOnStop({ interaction }: { interaction: Interaction }...
function validateAction (line 179) | function validateAction<T extends ActionName>(
function validateMatches (line 197) | function validateMatches(
function getActionInfo (line 229) | function getActionInfo(
function prepare (line 272) | function prepare(
function withinInteractionLimit (line 298) | function withinInteractionLimit<T extends ActionName>(
function maxInteractions (line 352) | function maxInteractions(newValue: any, scope: Scope) {
function setCursor (line 362) | function setCursor(element: Element, cursor: string, scope: Scope) {
function setInteractionCursor (line 374) | function setInteractionCursor<T extends ActionName>(interaction: Interac...
FILE: packages/@interactjs/auto-start/dragAxis.ts
function beforeStart (line 10) | function beforeStart({ interaction, eventTarget, dx, dy }: SignalArgs['i...
function checkStartAxis (line 73) | function checkStartAxis(startAxis: string, interactable: Interactable) {
FILE: packages/@interactjs/auto-start/hold.ts
type PerActionDefaults (line 10) | interface PerActionDefaults {
type Interaction (line 17) | interface Interaction {
function install (line 22) | function install(scope: Scope) {
function getHoldDuration (line 31) | function getHoldDuration(interaction: Interaction) {
FILE: packages/@interactjs/auto-start/plugin.ts
method install (line 15) | install(scope: Scope) {
FILE: packages/@interactjs/core/BaseEvent.ts
class BaseEvent (line 5) | class BaseEvent<T extends ActionName | null = never> {
method constructor (line 16) | constructor(interaction: Interaction<T>) {
method preventDefault (line 20) | preventDefault() {}
method stopPropagation (line 25) | stopPropagation() {
method stopImmediatePropagation (line 32) | stopImmediatePropagation() {
type BaseEvent (line 39) | interface BaseEvent<T extends ActionName | null = never> {
method constructor (line 16) | constructor(interaction: Interaction<T>) {
method preventDefault (line 20) | preventDefault() {}
method stopPropagation (line 25) | stopPropagation() {
method stopImmediatePropagation (line 32) | stopImmediatePropagation() {
method get (line 46) | get(this: BaseEvent) {
method set (line 49) | set(this: BaseEvent) {}
FILE: packages/@interactjs/core/Eventable.ts
function fireUntilImmediateStopped (line 8) | function fireUntilImmediateStopped(event: any, listeners: Listener[]) {
class Eventable (line 18) | class Eventable {
method constructor (line 25) | constructor(options?: { [index: string]: any }) {
method fire (line 29) | fire<T extends { type: string; propagationStopped?: boolean }>(event: ...
method on (line 45) | on(type: string, listener: ListenersArg) {
method off (line 53) | off(type: string, listener: ListenersArg) {
method getRect (line 73) | getRect(_element: Element): Rect {
FILE: packages/@interactjs/core/InteractEvent.ts
type EventPhase (line 11) | type EventPhase = keyof PhaseMap
type PhaseMap (line 13) | interface PhaseMap {
type InteractEvent (line 21) | interface InteractEvent {
method constructor (line 69) | constructor(
method getSwipe (line 145) | getSwipe() {
method preventDefault (line 179) | preventDefault() {}
method stopImmediatePropagation (line 184) | stopImmediatePropagation() {
method stopPropagation (line 191) | stopPropagation() {
class InteractEvent (line 35) | class InteractEvent<
method constructor (line 69) | constructor(
method getSwipe (line 145) | getSwipe() {
method preventDefault (line 179) | preventDefault() {}
method stopImmediatePropagation (line 184) | stopImmediatePropagation() {
method stopPropagation (line 191) | stopPropagation() {
method get (line 200) | get() {
method set (line 203) | set(value) {
method get (line 208) | get() {
method set (line 211) | set(value) {
method get (line 217) | get() {
method set (line 220) | set(value) {
method get (line 225) | get() {
method set (line 228) | set(value) {
method get (line 234) | get() {
method set (line 237) | set(value) {
method get (line 242) | get() {
method set (line 245) | set(value) {
method get (line 251) | get() {
method set (line 254) | set(value) {
method get (line 259) | get() {
method set (line 262) | set(value) {
FILE: packages/@interactjs/core/InteractStatic.ts
type InteractStatic (line 37) | interface InteractStatic {
function createInteractStatic (line 98) | function createInteractStatic(scope: Scope): InteractStatic {
FILE: packages/@interactjs/core/Interactable.spec.ts
function addToFired (line 101) | function addToFired(event: any) {
FILE: packages/@interactjs/core/Interactable.ts
type IgnoreValue (line 30) | type IgnoreValue = string | Element | boolean
type DeltaSource (line 31) | type DeltaSource = 'page' | 'client'
type OnOffMethod (line 33) | const enum OnOffMethod {
class Interactable (line 50) | class Interactable implements Partial<Eventable> {
method _defaults (line 51) | get _defaults(): Defaults {
method constructor (line 68) | constructor(
method setOnEvents (line 84) | setOnEvents(actionName: ActionName, phases: NonNullable<any>) {
method updatePerActionListeners (line 101) | updatePerActionListeners(actionName: ActionName, prev: Listeners | und...
method setPerAction (line 116) | setPerAction(actionName: ActionName, options: OrBoolean<Options>) {
method getRect (line 168) | getRect(element: Element) {
method rectChecker (line 188) | rectChecker(checker?: (element: Element) => any) {
method _backCompatOption (line 214) | _backCompatOption(optionName: keyof Options, newValue: any) {
method origin (line 238) | origin(newValue: any) {
method deltaSource (line 252) | deltaSource(newValue?: DeltaSource) {
method getAllElements (line 263) | getAllElements(): Element[] {
method context (line 283) | context() {
method inContext (line 287) | inContext(element: Document | Node) {
method testIgnoreAllow (line 292) | testIgnoreAllow(
method testAllow (line 305) | testAllow(this: Interactable, allowFrom: IgnoreValue | undefined, targ...
method testIgnore (line 324) | testIgnore(this: Interactable, ignoreFrom: IgnoreValue | undefined, ta...
method fire (line 346) | fire<E extends { type: string }>(iEvent: E) {
method _onOff (line 353) | _onOff(
method on (line 412) | on(types: EventTypes, listener?: ListenersArg, options?: any) {
method off (line 426) | off(types: string | string[] | EventTypes, listener?: ListenersArg, op...
method set (line 436) | set(options: OptionsArg) {
method unset (line 472) | unset() {
FILE: packages/@interactjs/core/InteractableSet.ts
type SignalArgs (line 12) | interface SignalArgs {
class InteractableSet (line 22) | class InteractableSet {
method constructor (line 32) | constructor(scope: Scope) {
method new (line 47) | new(target: Target, options?: any): Interactable {
method getExisting (line 82) | getExisting(target: Target, options?: Options) {
method forEachMatch (line 98) | forEachMatch<T>(node: Node, callback: (interactable: Interactable) => ...
FILE: packages/@interactjs/core/Interaction.spec.ts
method start (line 432) | start(event) {
FILE: packages/@interactjs/core/Interaction.ts
type _ProxyValues (line 26) | enum _ProxyValues {
type _ProxyMethods (line 35) | enum _ProxyMethods {
type PointerArgProps (line 43) | type PointerArgProps<T extends {} = {}> = {
type DoPhaseArg (line 52) | interface DoPhaseArg<T extends ActionName, P extends EventPhase> {
type DoAnyPhaseArg (line 61) | type DoAnyPhaseArg = DoPhaseArg<ActionName, EventPhase>
type SignalArgs (line 64) | interface SignalArgs {
type InteractionProxy (line 101) | type InteractionProxy<T extends ActionName | null = never> = Pick<
class Interaction (line 108) | class Interaction<T extends ActionName | null = ActionName> {
method pointerMoveTolerance (line 167) | get pointerMoveTolerance() {
method constructor (line 190) | constructor({ pointerType, scopeFire }: { pointerType?: string; scopeF...
method pointerDown (line 215) | pointerDown(pointer: PointerType, event: PointerEventType, eventTarget...
method start (line 261) | start<A extends ActionName>(action: ActionProps<A>, interactable: Inte...
method pointerMove (line 290) | pointerMove(pointer: PointerType, event: PointerEventType, eventTarget...
method move (line 364) | move(signalArg?: any) {
method pointerUp (line 388) | pointerUp(pointer: PointerType, event: PointerEventType, eventTarget: ...
method documentBlur (line 416) | documentBlur(event: Event) {
method end (line 439) | end(event?: PointerEventType) {
method currentAction (line 459) | currentAction() {
method interacting (line 463) | interacting() {
method stop (line 467) | stop() {
method getPointerIndex (line 478) | getPointerIndex(pointer: any) {
method getPointerInfo (line 488) | getPointerInfo(pointer: any) {
method updatePointer (line 493) | updatePointer(pointer: PointerType, event: PointerEventType, eventTarg...
method removePointer (line 548) | removePointer(pointer: PointerType, event: PointerEventType) {
method _updateLatestPointer (line 569) | _updateLatestPointer(pointer: PointerType, event: PointerEventType, ev...
method destroy (line 575) | destroy() {
method _createPreparedEvent (line 582) | _createPreparedEvent<P extends EventPhase>(
method _fireEvent (line 592) | _fireEvent<P extends EventPhase>(iEvent: InteractEvent<T, P>) {
method _doPhase (line 601) | _doPhase<P extends EventPhase>(
method _now (line 637) | _now() {
FILE: packages/@interactjs/core/NativeTypes.ts
type NativeEventTarget (line 2) | type NativeEventTarget = EventTarget
type NativeElement (line 3) | type NativeElement = Element
FILE: packages/@interactjs/core/PointerInfo.ts
class PointerInfo (line 3) | class PointerInfo {
method constructor (line 10) | constructor(id: number, pointer: PointerType, event: PointerEventType,...
FILE: packages/@interactjs/core/events.ts
type Scope (line 13) | interface Scope {
type EventOptions (line 18) | interface EventOptions {
type PartialEventTarget (line 23) | type PartialEventTarget = Partial<NativeEventTarget>
type ListenerEntry (line 25) | type ListenerEntry = { func: (event: Event | FakeEvent) => any; options:...
function install (line 27) | function install(scope: Scope) {
class FakeEvent (line 295) | class FakeEvent implements Partial<Event> {
method constructor (line 300) | constructor(originalEvent: Event) {
method preventOriginalDefault (line 306) | preventOriginalDefault() {
method stopPropagation (line 310) | stopPropagation() {
method stopImmediatePropagation (line 314) | stopImmediatePropagation() {
function getOptions (line 319) | function getOptions(param: { [index: string]: any } | boolean): { captur...
function optionsMatch (line 330) | function optionsMatch(a: Partial<EventOptions> | boolean, b: Partial<Eve...
FILE: packages/@interactjs/core/interactablePreventDefault.ts
type PreventDefaultValue (line 10) | type PreventDefaultValue = 'always' | 'never' | 'auto'
type Interactable (line 13) | interface Interactable {
function checkAndPreventDefault (line 45) | function checkAndPreventDefault(interactable: Interactable, scope: Scope...
function onInteractionEvent (line 85) | function onInteractionEvent({ interaction, event }: { interaction: Inter...
function install (line 91) | function install(scope: Scope) {
FILE: packages/@interactjs/core/interactionFinder.spec.ts
method pointerId (line 12) | get pointerId(): number {
method pointerType (line 15) | get pointerType(): string {
FILE: packages/@interactjs/core/interactionFinder.ts
type SearchDetails (line 7) | interface SearchDetails {
method search (line 20) | search(details: SearchDetails) {
method simulationResume (line 33) | simulationResume({ pointerType, eventType, eventTarget, scope }: SearchD...
method mouseOrPen (line 60) | mouseOrPen({ pointerId, pointerType, eventType, scope }: SearchDetails) {
method hasPointer (line 104) | hasPointer({ pointerId, scope }: SearchDetails) {
method idle (line 115) | idle({ pointerType, scope }: SearchDetails) {
function hasPointerId (line 140) | function hasPointerId(interaction: Interaction, pointerId: number) {
FILE: packages/@interactjs/core/interactions.ts
type Scope (line 18) | interface Scope {
type SignalArgs (line 30) | interface SignalArgs {
function install (line 47) | function install(scope: Scope) {
function doOnInteractions (line 141) | function doOnInteractions(method: string, scope: Scope) {
function getInteraction (line 221) | function getInteraction(searchDetails: SearchDetails) {
function onDocSignal (line 232) | function onDocSignal<T extends 'scope:add-document' | 'scope:remove-docu...
FILE: packages/@interactjs/core/options.ts
type Defaults (line 3) | interface Defaults {
type ActionDefaults (line 10) | interface ActionDefaults {}
type BaseDefaults (line 12) | interface BaseDefaults {
type PerActionDefaults (line 19) | interface PerActionDefaults {
type Options (line 27) | type Options = Partial<BaseDefaults> &
type OptionsArg (line 32) | interface OptionsArg extends BaseDefaults, OrBoolean<Partial<ActionDefau...
FILE: packages/@interactjs/core/scope.ts
type SignalArgs (line 26) | interface SignalArgs {
type ListenerName (line 34) | type ListenerName = keyof SignalArgs
type ListenerMap (line 36) | type ListenerMap = {
type DocSignalArg (line 40) | interface DocSignalArg {
type Plugin (line 47) | interface Plugin {
class Scope (line 56) | class Scope {
method constructor (line 103) | constructor() {
method addListeners (line 134) | addListeners(map: ListenerMap, id?: string) {
method fire (line 138) | fire<T extends ListenerName>(name: T, arg: SignalArgs[T]): void | false {
method init (line 150) | init(window: Window | typeof globalThis) {
method pluginIsInstalled (line 154) | pluginIsInstalled(plugin: Plugin) {
method usePlugin (line 159) | usePlugin(plugin: Plugin, options?: { [key: string]: any }) {
method addDocument (line 202) | addDocument(doc: Document, options?: any): void | false {
method removeDocument (line 224) | removeDocument(doc: Document) {
method getDocIndex (line 238) | getDocIndex(doc: Document) {
method getDocOptions (line 248) | getDocOptions(doc: Document) {
method now (line 254) | now() {
type Scope (line 260) | interface Scope {
method constructor (line 103) | constructor() {
method addListeners (line 134) | addListeners(map: ListenerMap, id?: string) {
method fire (line 138) | fire<T extends ListenerName>(name: T, arg: SignalArgs[T]): void | false {
method init (line 150) | init(window: Window | typeof globalThis) {
method pluginIsInstalled (line 154) | pluginIsInstalled(plugin: Plugin) {
method usePlugin (line 159) | usePlugin(plugin: Plugin, options?: { [key: string]: any }) {
method addDocument (line 202) | addDocument(doc: Document, options?: any): void | false {
method removeDocument (line 224) | removeDocument(doc: Document) {
method getDocIndex (line 238) | getDocIndex(doc: Document) {
method getDocOptions (line 248) | getDocOptions(doc: Document) {
method now (line 254) | now() {
function initScope (line 265) | function initScope(scope: Scope, window: Window | typeof globalThis) {
function pluginIdRoot (line 286) | function pluginIdRoot(id: string) {
FILE: packages/@interactjs/core/tests/_helpers.ts
function unique (line 12) | function unique() {
function uniqueProps (line 16) | function uniqueProps(obj: any) {
function newCoordsSet (line 30) | function newCoordsSet(n = 0) {
function newPointer (line 60) | function newPointer(n = 50) {
function mockScope (line 70) | function mockScope({ document = window.document } = {} as any) {
function getProps (line 80) | function getProps<T extends { [key: string]: any }, K extends keyof T>(s...
function testEnv (line 93) | function testEnv<T extends Target = HTMLElement>({
function timeout (line 143) | function timeout(n: number) {
function ltrbwh (line 147) | function ltrbwh(
FILE: packages/@interactjs/core/types.ts
type OrBoolean (line 7) | type OrBoolean<T> = {
type Element (line 11) | type Element = HTMLElement | SVGElement
type Context (line 12) | type Context = Document | Element
type EventTarget (line 13) | type EventTarget = Window | Document | Element
type Target (line 14) | type Target = EventTarget | string
type Point (line 16) | interface Point {
type Size (line 21) | interface Size {
type Rect (line 26) | interface Rect {
type FullRect (line 35) | type FullRect = Required<Rect>
type RectFunction (line 37) | type RectFunction<T extends any[]> = (...args: T) => Rect | Element
type RectResolvable (line 39) | type RectResolvable<T extends any[]> = Rect | string | Element | RectFun...
type Dimensions (line 41) | type Dimensions = Point & Size
type CoordsSetMember (line 43) | interface CoordsSetMember {
type CoordsSet (line 49) | interface CoordsSet {
type HasGetRect (line 57) | interface HasGetRect {
type ActionMap (line 62) | interface ActionMap {}
type ActionName (line 64) | type ActionName = keyof ActionMap
type Actions (line 66) | interface Actions {
type ActionProps (line 73) | interface ActionProps<T extends ActionName | null = never> {
type InertiaOption (line 79) | interface InertiaOption {
type InertiaOptions (line 86) | type InertiaOptions = InertiaOption | boolean
type EdgeOptions (line 88) | interface EdgeOptions {
type CursorChecker (line 95) | type CursorChecker = (
type ActionMethod (line 102) | interface ActionMethod<T> {
type OptionMethod (line 107) | interface OptionMethod<T> {
type ActionChecker (line 113) | type ActionChecker = (
type OriginFunction (line 121) | type OriginFunction = (target: Element) => Rect
type PointerEventsOptions (line 123) | interface PointerEventsOptions {
type RectChecker (line 130) | type RectChecker = (element: Element) => Rect
type NativePointerEventType (line 132) | type NativePointerEventType = typeof NativePointerEvent_
type PointerEventType (line 133) | type PointerEventType = MouseEvent | TouchEvent | Partial<NativePointerE...
type PointerType (line 134) | type PointerType = MouseEvent | Touch | Partial<NativePointerEventType> ...
type EventTypes (line 136) | type EventTypes = string | ListenerMap | Array<string | ListenerMap>
type Listener (line 138) | type Listener = (...args: any[]) => any
type Listeners (line 139) | type Listeners = ListenerMap | ListenerMap[]
type ListenersArg (line 140) | type ListenersArg = Listener | ListenerMap | Array<Listener | ListenerMap>
type ListenerMap (line 141) | interface ListenerMap {
type ArrayElementType (line 145) | type ArrayElementType<T> = T extends Array<infer P> ? P : never
FILE: packages/@interactjs/dev-tools/babel-plugin-prod.js
constant PROD_EXT (line 4) | const PROD_EXT = '.prod'
function fixImportSource (line 6) | function fixImportSource ({ node: { source } }, { filename }) {
function babelPluginInteractjsProd (line 25) | function babelPluginInteractjsProd () {
function shouldIgnoreImport (line 43) | function shouldIgnoreImport (source) {
FILE: packages/@interactjs/dev-tools/devTools.spec.ts
method warn (line 22) | warn(...args: any[]) {
method log (line 25) | log(...args: any[]) {
method error (line 28) | error(...args: any[]) {
function log (line 50) | function log(args: any, type: any) {
FILE: packages/@interactjs/dev-tools/plugin.ts
type Scope (line 13) | interface Scope {
type BaseDefaults (line 19) | interface BaseDefaults {
type Interactable (line 25) | interface Interactable {
type DevToolsOptions (line 30) | interface DevToolsOptions {
type Logger (line 34) | interface Logger {
type Check (line 40) | interface Check {
type CheckName (line 47) | enum CheckName {
function install (line 62) | function install(scope: Scope, { logger }: { logger?: Logger } = {}) {
method perform (line 109) | perform({ element }) {
method getInfo (line 112) | getInfo({ element }) {
method perform (line 120) | perform(interaction) {
method getInfo (line 130) | getInfo({ element }) {
method perform (line 137) | perform(interaction) {
method getInfo (line 143) | getInfo(interaction) {
function hasStyle (line 150) | function hasStyle(element: HTMLElement, prop: keyof CSSStyleDeclaration,...
function parentHasStyle (line 155) | function parentHasStyle(element: Element, prop: keyof CSSStyleDeclaratio...
FILE: packages/@interactjs/inertia/inertia.spec.ts
method set (line 19) | set({ coords: modifierCoords, phase }: any) {
method set (line 93) | set({ coords: modifiedCoords, phase }) {
function downStartMoveUp (line 160) | function downStartMoveUp({ x, y, dt }: any) {
function lastEvent (line 177) | function lastEvent() {
FILE: packages/@interactjs/inertia/plugin.ts
type PhaseMap (line 19) | interface PhaseMap {
type Interaction (line 26) | interface Interaction {
type PerActionDefaults (line 32) | interface PerActionDefaults {
type SignalArgs (line 45) | interface SignalArgs {
function install (line 55) | function install(scope: Scope) {
class InertiaState (line 73) | class InertiaState {
method constructor (line 97) | constructor(interaction: Interaction) {
method start (line 101) | start(event: PointerEventType) {
method startInertia (line 164) | startInertia() {
method startSmoothEnd (line 199) | startSmoothEnd() {
method onNextFrame (line 210) | onNextFrame(tickFn: () => void) {
method inertiaTick (line 218) | inertiaTick() {
method smoothEndTick (line 264) | smoothEndTick() {
method resume (line 296) | resume({ pointer, event, eventTarget }: SignalArgs['interactions:down'...
method end (line 319) | end() {
method stop (line 325) | stop() {
function start (line 332) | function start({ interaction, event }: DoPhaseArg<ActionName, 'end'>) {
function resume (line 345) | function resume(arg: SignalArgs['interactions:down']) {
function stop (line 365) | function stop({ interaction }: { interaction: Interaction }) {
function getOptions (line 373) | function getOptions({ interactable, prepared }: Interaction) {
function _getQBezierValue (line 408) | function _getQBezierValue(t: number, p1: number, p2: number, p3: number) {
function getQuadraticCurvePoint (line 413) | function getQuadraticCurvePoint(
function easeOutQuad (line 429) | function easeOutQuad(t: number, b: number, c: number, d: number) {
FILE: packages/@interactjs/interact/interact.spec.ts
method install (line 67) | install() {
method install (line 74) | install() {
FILE: packages/@interactjs/modifiers/Modification.ts
type ModificationResult (line 10) | interface ModificationResult {
type MethodArg (line 19) | interface MethodArg {
class Modification (line 28) | class Modification {
method constructor (line 38) | constructor(interaction: Interaction) {
method start (line 49) | start({ phase }: { phase: EventPhase }, pageCoords: Point) {
method fillArg (line 73) | fillArg(arg: Partial<ModifierArg>) {
method startAll (line 86) | startAll(arg: MethodArg & Partial<ModifierArg>) {
method setAll (line 95) | setAll(arg: MethodArg & Partial<ModifierArg>): ModificationResult {
method applyToInteraction (line 151) | applyToInteraction(arg: { phase: EventPhase; rect?: Rect }) {
method setAndApply (line 185) | setAndApply(
method beforeEnd (line 232) | beforeEnd(arg: Omit<DoAnyPhaseArg, 'iEvent'> & { state?: ModifierState...
method stop (line 262) | stop(arg: { interaction: Interaction }) {
method prepareStates (line 293) | prepareStates(modifierList: Modifier[]) {
method restoreInteractionCoords (line 310) | restoreInteractionCoords({ interaction: { coords, rect, modification }...
method shouldDo (line 334) | shouldDo(options, preEnd?: boolean, phase?: string, requireEndOnly?: b...
method copyFrom (line 352) | copyFrom(other: Modification) {
method destroy (line 361) | destroy() {
function createResult (line 368) | function createResult(coords?: Point, rect?: FullRect): ModificationResu...
function getModifierList (line 384) | function getModifierList(interaction) {
function getRectOffset (line 407) | function getRectOffset(rect, coords) {
FILE: packages/@interactjs/modifiers/aspectRatio.spec.ts
method move (line 28) | move(e) {
function downStartMoveUp (line 75) | function downStartMoveUp({ x, y, edges }: { x: number; y: number; edges:...
FILE: packages/@interactjs/modifiers/aspectRatio.ts
type AspectRatioOptions (line 27) | interface AspectRatioOptions {
type AspectRatioState (line 34) | type AspectRatioState = ModifierState<
method start (line 52) | start(arg) {
method set (line 103) | set(arg) {
function setEqualDelta (line 153) | function setEqualDelta({ startCoords, edgeSign }: AspectRatioState, xIsP...
function setRatio (line 161) | function setRatio(
FILE: packages/@interactjs/modifiers/base.spec.ts
method start (line 126) | start({ state }: any) {
method set (line 129) | set({ state, coords }: any) {
method stop (line 137) | stop({ state }: any) {
method start (line 145) | start() {}
method set (line 146) | set({ coords }: any) {
FILE: packages/@interactjs/modifiers/base.ts
type Interaction (line 9) | interface Interaction {
type InteractEvent (line 15) | interface InteractEvent {
type PerActionDefaults (line 24) | interface PerActionDefaults {
function makeModifier (line 29) | function makeModifier<
function addEventModifiers (line 81) | function addEventModifiers({
FILE: packages/@interactjs/modifiers/plugin.ts
type InteractStatic (line 13) | interface InteractStatic {
method install (line 20) | install(scope) {
FILE: packages/@interactjs/modifiers/restrict/edges.spec.ts
method getRect (line 59) | getRect() {
FILE: packages/@interactjs/modifiers/restrict/edges.ts
type RestrictEdgesOptions (line 22) | interface RestrictEdgesOptions {
type RestrictEdgesState (line 30) | type RestrictEdgesState = ModifierState<
function start (line 42) | function start({ interaction, startOffset, state }: ModifierArg<Restrict...
function set (line 62) | function set({ coords, edges, interaction, state }: ModifierArg<Restrict...
function fixRect (line 88) | function fixRect(rect: Rect, defaults: Rect) {
FILE: packages/@interactjs/modifiers/restrict/pointer.ts
type RestrictOptions (line 10) | interface RestrictOptions {
type RestrictState (line 21) | type RestrictState = ModifierState<
function start (line 28) | function start({ rect, startOffset, state, interaction, pageCoords }: Mo...
function set (line 68) | function set({ coords, interaction, state }: ModifierArg<RestrictState>) {
function getRestrictionRect (line 81) | function getRestrictionRect(
FILE: packages/@interactjs/modifiers/restrict/rect.ts
method elementRect (line 9) | get elementRect() {
method elementRect (line 12) | set elementRect(_) {}
FILE: packages/@interactjs/modifiers/restrict/size.ts
type RestrictSizeOptions (line 16) | interface RestrictSizeOptions {
function start (line 23) | function start(arg: ModifierArg<RestrictEdgesState>) {
type RestrictSizeState (line 27) | type RestrictSizeState = RestrictEdgesState &
function set (line 36) | function set(arg: ModifierArg<RestrictSizeState>) {
FILE: packages/@interactjs/modifiers/snap/edges.ts
type SnapEdgesOptions (line 39) | type SnapEdgesOptions = Pick<SnapOptions, 'targets' | 'range' | 'offset'...
function start (line 41) | function start(arg: ModifierArg<SnapState>) {
FILE: packages/@interactjs/modifiers/snap/pointer.ts
type Offset (line 12) | interface Offset {
type SnapPosition (line 19) | interface SnapPosition {
type SnapFunction (line 27) | type SnapFunction = (
type SnapTarget (line 34) | type SnapTarget = SnapPosition | SnapFunction
type SnapOptions (line 35) | interface SnapOptions {
type SnapState (line 49) | type SnapState = ModifierState<
function start (line 58) | function start(arg: ModifierArg<SnapState>) {
function set (line 98) | function set(arg: ModifierArg<SnapState>) {
function getOrigin (line 194) | function getOrigin(arg: Partial<ModifierArg<SnapState>>) {
FILE: packages/@interactjs/modifiers/snap/size.ts
type SnapSizeOptions (line 13) | type SnapSizeOptions = Pick<SnapOptions, 'targets' | 'offset' | 'endOnly...
function start (line 15) | function start(arg: ModifierArg<SnapState>) {
function set (line 49) | function set(arg) {
FILE: packages/@interactjs/modifiers/types.ts
type Modifier (line 6) | interface Modifier<
type ModifierState (line 24) | type ModifierState<Defaults = unknown, StateProps = unknown, Name extend...
type ModifierArg (line 31) | interface ModifierArg<State extends ModifierState = ModifierState> {
type ModifierModule (line 47) | interface ModifierModule<
type ModifierFunction (line 59) | interface ModifierFunction<
FILE: packages/@interactjs/offset/plugin.ts
type Interaction (line 8) | interface Interaction {
type _ProxyMethods (line 16) | enum _ProxyMethods {
function addTotal (line 23) | function addTotal(interaction: Interaction) {
function beforeAction (line 34) | function beforeAction({ interaction }: { interaction: Interaction }) {
function beforeEnd (line 38) | function beforeEnd({ interaction }: { interaction: Interaction }): boole...
function end (line 49) | function end({ interaction }: { interaction: Interaction }) {
function applyPending (line 56) | function applyPending(interaction: Interaction) {
function offsetBy (line 73) | function offsetBy(this: Interaction, { x, y }: Point) {
function addToCoords (line 81) | function addToCoords({ page, client }, { x, y }: Point) {
function hasPending (line 88) | function hasPending(interaction: Interaction) {
method install (line 95) | install(scope) {
FILE: packages/@interactjs/pointer-events/PointerEvent.ts
class PointerEvent (line 6) | class PointerEvent<T extends string = any> extends BaseEvent<never> {
method constructor (line 20) | constructor(
method _subtractOrigin (line 60) | _subtractOrigin({ x: originX, y: originY }: Point) {
method _addOrigin (line 69) | _addOrigin({ x: originX, y: originY }: Point) {
method preventDefault (line 81) | preventDefault() {
FILE: packages/@interactjs/pointer-events/base.spec.ts
function onCollect (line 93) | function onCollect({ targets }: { targets?: EventTargetList }) {
FILE: packages/@interactjs/pointer-events/base.ts
type EventTargetList (line 12) | type EventTargetList = Array<{
type PointerEventOptions (line 18) | interface PointerEventOptions extends PerActionDefaults {
type Scope (line 27) | interface Scope {
type Interaction (line 33) | interface Interaction {
type PointerInfo (line 40) | interface PointerInfo {
type ActionDefaults (line 49) | interface ActionDefaults {
type SignalArgs (line 55) | interface SignalArgs {
function fire (line 123) | function fire<T extends string>(
function collectEventTargets (line 202) | function collectEventTargets<T extends string>(
function addInteractionProps (line 259) | function addInteractionProps({ interaction }) {
function addHoldInfo (line 264) | function addHoldInfo({ down, pointerInfo }: SignalArgs['interactions:upd...
function clearHold (line 272) | function clearHold({ interaction, pointerIndex }) {
function moveAndClearHold (line 281) | function moveAndClearHold(arg: SignalArgs['interactions:move'], scope: S...
function downAndStartHold (line 302) | function downAndStartHold(
function tapAfterUp (line 352) | function tapAfterUp(
function install (line 361) | function install(scope: Scope) {
FILE: packages/@interactjs/pointer-events/holdRepeat.ts
type Interaction (line 11) | interface Interaction {
type PointerEvent (line 17) | interface PointerEvent<T extends string = any> {
type PointerEventOptions (line 23) | interface PointerEventOptions {
function install (line 28) | function install(scope: Scope) {
function onNew (line 38) | function onNew({ pointerEvent }: { pointerEvent: PointerEvent<any> }) {
function onFired (line 44) | function onFired(
function endHoldRepeat (line 71) | function endHoldRepeat({ interaction }: { interaction: Interaction }) {
FILE: packages/@interactjs/pointer-events/interactableTargets.ts
type Interactable (line 9) | interface Interactable {
function install (line 16) | function install(scope: Scope) {
FILE: packages/@interactjs/pointer-events/plugin.ts
method install (line 15) | install(scope) {
FILE: packages/@interactjs/reflow/plugin.ts
type SignalArgs (line 11) | interface SignalArgs {
type Interactable (line 19) | interface Interactable {
type Interaction (line 41) | interface Interaction {
type PhaseMap (line 48) | interface PhaseMap {
function install (line 53) | function install(scope: Scope) {
function doReflow (line 63) | function doReflow<T extends ActionName>(
function startReflow (line 121) | function startReflow<T extends ActionName>(
FILE: packages/@interactjs/snappers/grid.ts
type GridOptionsBase (line 4) | interface GridOptionsBase {
type GridOptionsXY (line 9) | interface GridOptionsXY extends GridOptionsBase {
type GridOptionsTopLeft (line 13) | interface GridOptionsTopLeft extends GridOptionsBase {
type GridOptionsBottomRight (line 17) | interface GridOptionsBottomRight extends GridOptionsBase {
type GridOptionsWidthHeight (line 21) | interface GridOptionsWidthHeight extends GridOptionsBase {
type GridOptions (line 26) | type GridOptions = GridOptionsXY | GridOptionsTopLeft | GridOptionsBotto...
FILE: packages/@interactjs/snappers/plugin.ts
type InteractStatic (line 7) | interface InteractStatic {
method install (line 15) | install(scope) {
FILE: packages/@interactjs/types/index.ts
type ActionProps (line 20) | type ActionProps<T extends ActionName = ActionName> = _ActionProps<T>
type Interaction (line 21) | type Interaction<T extends ActionName = ActionName> = interaction.Intera...
type InteractionProxy (line 22) | type InteractionProxy<T extends ActionName = ActionName> = interaction.I...
type PointerArgProps (line 23) | type PointerArgProps<T extends {} = {}> = interaction.PointerArgProps<T>
type InteractEvent (line 24) | type InteractEvent<T extends ActionName = never, P extends EventPhase = ...
FILE: packages/@interactjs/utils/arr.ts
type Filter (line 1) | type Filter<T> = (element: T, index: number, array: T[]) => boolean
FILE: packages/@interactjs/utils/browser.ts
function init (line 24) | function init(window: any) {
FILE: packages/@interactjs/utils/clone.ts
function clone (line 5) | function clone<T extends Object>(source: T): Partial<T> {
FILE: packages/@interactjs/utils/domObjects.ts
function blank (line 27) | function blank() {}
function init (line 31) | function init(window: Window) {
FILE: packages/@interactjs/utils/domUtils.spec.ts
type MockNode (line 4) | interface MockNode {
FILE: packages/@interactjs/utils/domUtils.ts
function nodeContains (line 8) | function nodeContains(parent: Node, child: Node) {
function closest (line 24) | function closest(element: Node, selector: string) {
function parentNode (line 36) | function parentNode(node: Node | Document) {
function matchesSelector (line 52) | function matchesSelector(element: Element, selector: string) {
function indexOfDeepestElement (line 64) | function indexOfDeepestElement(elements: Element[] | NodeListOf<globalTh...
function getNodeParents (line 164) | function getNodeParents(node: Node, limit?: Node) {
function zIndexIsHigherThan (line 177) | function zIndexIsHigherThan(higherNode: Node, lowerNode: Node) {
function matchesUpTo (line 184) | function matchesUpTo(element: Element, selector: string, limit: Node) {
function getActualElement (line 200) | function getActualElement(element: Element) {
function getScrollXY (line 204) | function getScrollXY(relevantWindow?: Window) {
function getElementClientRect (line 212) | function getElementClientRect(element: Element): Required<Rect> {
function getElementRect (line 228) | function getElementRect(element: Element) {
function getPath (line 243) | function getPath(node: Node | Document) {
function trySelector (line 254) | function trySelector(value: Target) {
FILE: packages/@interactjs/utils/extend.ts
function extend (line 1) | function extend<T, U extends object>(dest: U & Partial<T>, source: T): T...
FILE: packages/@interactjs/utils/getOriginXY.ts
function getOriginXY (line 6) | function getOriginXY(
FILE: packages/@interactjs/utils/isNonNativeEvent.ts
function isNonNativeEvent (line 3) | function isNonNativeEvent(type: string, actions: Actions) {
FILE: packages/@interactjs/utils/misc.ts
function warnOnce (line 5) | function warnOnce<T>(this: T, method: (...args: any[]) => any, message: ...
function copyAction (line 18) | function copyAction<T extends ActionName>(dest: ActionProps<any>, src: A...
FILE: packages/@interactjs/utils/normalizeListeners.ts
type NormalizedListeners (line 5) | interface NormalizedListeners {
function normalize (line 9) | function normalize(
function split (line 51) | function split(type: string) {
FILE: packages/@interactjs/utils/pointerExtend.ts
constant VENDOR_PREFIXES (line 1) | const VENDOR_PREFIXES = ['webkit', 'moz']
function pointerExtend (line 3) | function pointerExtend<T>(dest: Partial<T & { __set?: Partial<T> }>, sou...
FILE: packages/@interactjs/utils/pointerUtils.ts
function copyCoords (line 11) | function copyCoords(dest: CoordsSetMember, src: CoordsSetMember) {
function setCoordDeltas (line 23) | function setCoordDeltas(targetObj: CoordsSetMember, prev: CoordsSetMembe...
function setCoordVelocity (line 31) | function setCoordVelocity(targetObj: CoordsSetMember, delta: CoordsSetMe...
function setZeroCoords (line 41) | function setZeroCoords(targetObj: CoordsSetMember) {
function isNativePointer (line 48) | function isNativePointer(pointer: any) {
function getXY (line 53) | function getXY(type: string, pointer: PointerType | InteractEvent, xy: P...
function getPageXY (line 63) | function getPageXY(pointer: PointerType | InteractEvent, page?: Point) {
function getClientXY (line 79) | function getClientXY(pointer: PointerType, client: Point) {
function getPointerId (line 92) | function getPointerId(pointer: { pointerId?: number; identifier?: number...
function setCoords (line 96) | function setCoords(dest: CoordsSetMember, pointers: any[], timeStamp: nu...
function getTouchPair (line 105) | function getTouchPair(event: TouchEvent | PointerType[]) {
function pointerAverage (line 132) | function pointerAverage(pointers: PointerType[]) {
function touchBBox (line 156) | function touchBBox(event: PointerType[]) {
function touchDistance (line 179) | function touchDistance(event: PointerType[] | TouchEvent, deltaSource: s...
function touchAngle (line 190) | function touchAngle(event: PointerType[] | TouchEvent, deltaSource: stri...
function getPointerType (line 201) | function getPointerType(pointer: { pointerType?: string; identifier?: nu...
function getEventTargets (line 214) | function getEventTargets(event: Event) {
function newCoords (line 225) | function newCoords(): CoordsSetMember {
function coordsToEvent (line 233) | function coordsToEvent(coords: MockCoords) {
type MockCoords (line 278) | interface MockCoords {
FILE: packages/@interactjs/utils/raf.ts
function init (line 5) | function init(global: Window | typeof globalThis) {
FILE: packages/@interactjs/utils/rect.ts
function getStringOptionResult (line 15) | function getStringOptionResult(value: any, target: HasGetRect, element: ...
function resolveRectLike (line 27) | function resolveRectLike<T extends any[]>(
function toFullRect (line 47) | function toFullRect(rect: Rect): FullRect {
function rectToXY (line 55) | function rectToXY(rect: Rect | Point) {
function xywhToTlbr (line 64) | function xywhToTlbr<T extends Partial<Rect & Point>>(rect: T) {
function tlbrToXywh (line 77) | function tlbrToXywh(rect: Rect & Partial<Point>) {
function addEdges (line 90) | function addEdges(edges: EdgeOptions, rect: Rect, delta: Point) {
FILE: packages/@interactjs/utils/shallowEqual.ts
function shallowEqual (line 1) | function shallowEqual(left: any, right: any) {
FILE: packages/@interactjs/utils/window.ts
function init (line 8) | function init(window: Window & { wrap?: (...args: any[]) => any }) {
function getWindow (line 29) | function getWindow(node: any) {
FILE: scripts/babel/inline-env-vars.js
method MemberExpression (line 6) | MemberExpression(path, { opts: { include, exclude, env } = {} }) {
FILE: scripts/babel/vue-sfc.js
method parserOverride (line 7) | parserOverride(source, options, babelParse) {
function compileSfc (line 25) | function compileSfc(source, { filename, isProd = true }) {
function getStyleStatement (line 51) | function getStyleStatement(styles) {
FILE: scripts/bin/_check_deps.js
function checkDeps (line 5) | async function checkDeps () {
FILE: scripts/bin/lint.js
function main (line 16) | async function main() {
function formatWithPrettier (line 45) | async function formatWithPrettier(filepath) {
function getSources (line 55) | async function getSources() {
function isGenerated (line 64) | function isGenerated(source) {
FILE: scripts/bin/release.js
function main (line 22) | async function main(ps) {
function configGitUser (line 36) | function configGitUser() {
function ensureCleanIndex (line 41) | function ensureCleanIndex() {
function checkVersion (line 50) | function checkVersion() {
function gitDetatch (line 64) | function gitDetatch() {
function clean (line 68) | function clean() {
function runBuild (line 72) | async function runBuild() {
function commit (line 121) | function commit() {
function pushAndPublish (line 130) | async function pushAndPublish() {
function editPackageJsons (line 157) | async function editPackageJsons(func) {
FILE: scripts/execTypes.js
method modular (line 7) | modular(modulesDir) {
method combined (line 10) | async combined(outDir) {
FILE: scripts/utils.js
function getEsnextBabelOptions (line 37) | function getEsnextBabelOptions(presetEnvOptions) {
function getDevPackageDir (line 71) | function getDevPackageDir() {
function getModuleName (line 75) | function getModuleName(tsName) {
function getModuleDirectories (line 79) | function getModuleDirectories() {
function getPackages (line 83) | async function getPackages(options) {
function getPackageJsons (line 93) | async function getPackageJsons(packages = getPackages()) {
function shouldIgnoreImport (line 103) | function shouldIgnoreImport(sourceValue) {
function extendBabelOptions (line 110) | function extendBabelOptions(
function getPackageDir (line 123) | function getPackageDir(filename) {
function getRelativeToRoot (line 137) | function getRelativeToRoot(filename, moduleDirectory, prefix = '/') {
function withBestRoot (line 158) | function withBestRoot(func, moduleDirectory) {
function resolveImport (line 178) | function resolveImport(specifier, basedir, moduleDirectory) {
function getShims (line 189) | function getShims() {
function errorExit (line 197) | function errorExit(error) {
FILE: test/fixtures/dependentTsProject/index.ts
method checker (line 168) | checker (
function listener (line 187) | function listener (event: Interact.InteractEvent) {
method ondrop (line 231) | ondrop (event) {
FILE: vite.config.ts
function getDefinedEnv (line 30) | function getDefinedEnv () {
function dirListing (line 38) | function dirListing (): Plugin {
Condensed preview — 287 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (662K chars).
[
{
"path": ".browserslistrc",
"chars": 49,
"preview": "defaults and fully supports es6-module\nnode >= 16"
},
{
"path": ".codeclimate.yml",
"chars": 362,
"preview": "plugins:\n eslint:\n enabled: false\n channel: eslint-6\n extensions:\n - .ts\n - .js\n duplication:\n e"
},
{
"path": ".eslintignore",
"chars": 42,
"preview": "dist\ncoverage\n**/node_modules/**\n_angular\n"
},
{
"path": ".eslintrc.cjs",
"chars": 3288,
"preview": "module.exports = {\n extends: [\n 'plugin:import/errors',\n 'plugin:import/warnings',\n 'plugin:import/typescript'"
},
{
"path": ".github/stale.yml",
"chars": 716,
"preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 14\n# Number of days of inactivity before a "
},
{
"path": ".github/workflows/publish.yml",
"chars": 640,
"preview": "on:\n push:\n branches:\n - main\n - next\n\njobs:\n test:\n uses: ./.github/workflows/test.yml\n\n publish-npm"
},
{
"path": ".github/workflows/test.yml",
"chars": 492,
"preview": "on:\n pull_request:\n workflow_dispatch:\n workflow_call:\n\njobs:\n test:\n name: '🧪 Test'\n runs-on: ubuntu-latest\n "
},
{
"path": ".gitignore",
"chars": 582,
"preview": "*.d.ts\n*.d.ts.map\n!interactjs/index.d.ts\n!shims.d.ts\npackages/@interactjs/**/index.ts\npackages/@interactjs/*/use/**/*.ts"
},
{
"path": ".husky/.gitignore",
"chars": 2,
"preview": "_\n"
},
{
"path": ".husky/pre-commit",
"chars": 59,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nyarn lint-staged\n"
},
{
"path": ".npmignore",
"chars": 57,
"preview": "*.ts\n!*.d.ts\n*.map.*\n*.spec.ts\n*.spec.js\ndist/docs\nguide\n"
},
{
"path": ".npmrc",
"chars": 94,
"preview": "link-workspace-packages = true\nshared-workspace-lockfile = true\nprefer-frozen-lockfile = true\n"
},
{
"path": ".nvmrc",
"chars": 9,
"preview": "v20.10.0\n"
},
{
"path": ".prettierignore",
"chars": 27,
"preview": "dist\ncoverage\nnode_modules\n"
},
{
"path": ".prettierrc.json",
"chars": 90,
"preview": "{\n \"printWidth\": 110,\n \"semi\": false,\n \"singleQuote\": true,\n \"trailingComma\": \"all\"\n}\n"
},
{
"path": ".stylelintrc.cjs",
"chars": 175,
"preview": "module.exports = {\n extends: ['stylelint-config-standard', 'stylelint-config-recess-order', 'stylelint-config-css-modul"
},
{
"path": ".yarnrc",
"chars": 38,
"preview": "registry \"https://registry.npmjs.org\"\n"
},
{
"path": "CHANGELOG.md",
"chars": 24007,
"preview": "## v1.10.27\n\n- fix(types): fix issues with `skipLibCheck: false`\n\n## v1.10.26\n\n- fix: improve build; check output for ES"
},
{
"path": "ISSUE_TEMPLATE.md",
"chars": 775,
"preview": "If you have questions about the [API](http://interactjs.io/api) that aren't answered in the [docs](http://interactjs.io/"
},
{
"path": "LICENSE",
"chars": 1094,
"preview": "Copyright (c) 2012-present Taye Adeyemi <dev@taye.me>\n\nPermission is hereby granted, free of charge, to any person \nobta"
},
{
"path": "PULL_REQUEST_TEMPLATE.md",
"chars": 49,
"preview": "Make sure to include tests in your pull request.\n"
},
{
"path": "README.md",
"chars": 4123,
"preview": "<a href=\"http://interactjs.io\"><img alt=\"interact.js\" src=\"https://c4d6f7d727e094887e93-4ea74b676357550bd514a6a5b344c625"
},
{
"path": "babel.config.cjs",
"chars": 119,
"preview": "module.exports = {\n presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],\n}\n"
},
{
"path": "bin/_add_plugin_indexes",
"chars": 65,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/add_plugin_indexes')\n"
},
{
"path": "bin/_bundle",
"chars": 53,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/bundle')\n"
},
{
"path": "bin/_check_deps",
"chars": 58,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/_check_deps')\n"
},
{
"path": "bin/_clean",
"chars": 52,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/clean')\n"
},
{
"path": "bin/_link",
"chars": 770,
"preview": "#!/bin/bash\nROOT=$(dirname $(dirname $(readlink -f $0)))\nif [ -z \"$ROOT\" ]\nthen\n ROOT=$(dirname $(dirname $0))\nfi\n\nmo"
},
{
"path": "bin/_lint",
"chars": 51,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/lint')\n"
},
{
"path": "bin/_release",
"chars": 54,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/release')\n"
},
{
"path": "bin/_types",
"chars": 52,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/types')\n"
},
{
"path": "bin/_version",
"chars": 54,
"preview": "#!/usr/bin/env node\nrequire('../scripts/bin/version')\n"
},
{
"path": "bundle.rollup.config.cjs",
"chars": 2802,
"preview": "/* eslint-disable import/no-extraneous-dependencies */\nconst { resolve } = require('path')\n\nconst babel = require('@roll"
},
{
"path": "docs/action-options.md",
"chars": 5863,
"preview": "---\ntitle: Action Options\n---\n\nThe `Interactable` methods `draggable()`, `resizable()` and `gesturable()` are\nused to en"
},
{
"path": "docs/auto-start.md",
"chars": 869,
"preview": "---\ntitle: 'AutoStart (manualStart: false)'\n---\n\nThe [pre-bundled](/docs/installation) package includes the `auto-start`"
},
{
"path": "docs/draggable.md",
"chars": 2147,
"preview": "---\ntitle: Draggable\n---\n\nDragging is the simplest action interact.js provides. To make an element\ndraggable, create an "
},
{
"path": "docs/dropzone.md",
"chars": 3394,
"preview": "---\ntitle: Dropzone\n---\n\nDropzones define elements that draggable targets can be \"dropped\" into and which\nelements will "
},
{
"path": "docs/events.md",
"chars": 7157,
"preview": "---\ntitle: Events\n---\n\n## InteractEvents\n\n<LiveDemo :demoHtml=\"import('@/demos/events/actions.html?raw')\" :removeNext=\"3"
},
{
"path": "docs/faq.md",
"chars": 4369,
"preview": "---\ntitle: FAQ\n---\n\nThis page contains questions and issues that are frequently raised on [Gitter\nchat][gitter] and [Git"
},
{
"path": "docs/gesturable.md",
"chars": 2008,
"preview": "---\ntitle: Gesturable\n---\n\n```html\n<div id=\"rotate-area\">\n <div id=\"angle-info\">0°</div>\n <svg id=\"arrow\" viewbox="
},
{
"path": "docs/inertia.md",
"chars": 1700,
"preview": "---\ntitle: Inertia\n---\n\n```javascript\ninteract(target)\n .draggable({\n inertia: true\n })\n .resizable({\n inertia:"
},
{
"path": "docs/installation.md",
"chars": 5415,
"preview": "---\ntitle: Installation\n---\n\ninteract.js offers two sets of free packages that you can add to your project:\n\n1. To get "
},
{
"path": "docs/introduction.md",
"chars": 3605,
"preview": "---\ntitle: Introduction\n---\n\n## What is interact.js?\n\ninteract.js is a JavaScript library for drag and drop, resizing an"
},
{
"path": "docs/migrating.md",
"chars": 5261,
"preview": "---\ntitle: Migrating from v1.2\n---\n\nThe latest versions fix several bugs, allows setting more options on a\nper-action ba"
},
{
"path": "docs/modifiers.md",
"chars": 1542,
"preview": "---\ntitle: Modifiers\n---\n\n```js\n// create a restrict modifier to prevent dragging an element out of its parent\nconst res"
},
{
"path": "docs/reflow.md",
"chars": 977,
"preview": "---\ntitle: Reflow\n---\n\nThe reflow method lets you trigger an action start -> move -> end sequence which\nruns modifiers a"
},
{
"path": "docs/resizable.md",
"chars": 4768,
"preview": "---\ntitle: Resizable\n---\n\n```javascript\ninteract(target)\n .resizable({\n edges: {\n top : true, // Use po"
},
{
"path": "docs/restriction.md",
"chars": 3281,
"preview": "---\ntitle: Restrict\n---\n\ninteract.js has 3 restriction modifiers available through the\n`interact.modifiers` object:\n\n- p"
},
{
"path": "docs/snapping.md",
"chars": 8208,
"preview": "---\ntitle: Snapping\n---\n\ninteract.js has 3 snap modifiers available through the `interact.modifiers`\nobject:\n\n- pointer "
},
{
"path": "docs/tooling.md",
"chars": 2528,
"preview": "---\ntitle: Tooling & Optimization\n---\n\n## Feature selection\n\n```sh\n# install only the features you need\n$ npm install --"
},
{
"path": "esnext.rollup.config.cjs",
"chars": 5783,
"preview": "/* eslint-disable import/no-extraneous-dependencies */\nconst { resolve, basename, dirname, relative, extname } = require"
},
{
"path": "examples/.eslintignore",
"chars": 3,
"preview": "js\n"
},
{
"path": "examples/.eslintrc.cjs",
"chars": 213,
"preview": "module.exports = {\n extends: '../.eslintrc.cjs',\n globals: { interact: false, _: false, $: false },\n rules: { 'no-con"
},
{
"path": "examples/dropzones/index.css",
"chars": 816,
"preview": "body { font-family: Helvetica, Arial, sans-serif; }\n\n.dropzone-wrapper {\n position: absolute;\n bottom: 0;\n left"
},
{
"path": "examples/dropzones/index.html",
"chars": 703,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Highlight dropzones with interact.js</titl"
},
{
"path": "examples/dropzones/index.js",
"chars": 3887,
"preview": "/* eslint-disable import/no-absolute-path */\nimport interact from '@interactjs/interactjs'\n\nlet transformProp\nconst drag"
},
{
"path": "examples/events/index.css",
"chars": 1002,
"preview": "#swipe {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n\n margin: 0;\n padding: 10%;"
},
{
"path": "examples/events/index.html",
"chars": 761,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>interact.js events demo</tit"
},
{
"path": "examples/events/index.js",
"chars": 1923,
"preview": "/* eslint-disable import/no-absolute-path */\nimport interact from '@interactjs/interactjs'\n\nconst dirs = ['up', 'down', "
},
{
"path": "examples/iframes/bottom.html",
"chars": 309,
"preview": "<meta charset=\"utf-8\">\n<link href=\"./index.css\" rel=\"stylesheet\" type=\"text/css\"/>\n\n<script type=\"module\">\nimport setInt"
},
{
"path": "examples/iframes/index.css",
"chars": 349,
"preview": "body {\n margin: 0;\n padding: 5% 10%;\n font-family: sans-serif;\n}\n\n#drag-me {\n width: 25%;\n\n background-co"
},
{
"path": "examples/iframes/index.html",
"chars": 442,
"preview": "<meta charset=\"utf-8\">\n<link href=\"./index.css\" rel=\"stylesheet\" type=\"text/css\"/>\n\n<iframe src=\"middle.html\" style=\"bor"
},
{
"path": "examples/iframes/index.js",
"chars": 865,
"preview": "export default function setInteractables() {\n interact('.draggable', { context: document }).draggable({\n onmove: onM"
},
{
"path": "examples/iframes/middle.html",
"chars": 456,
"preview": "<meta charset=\"utf-8\">\n<link href=\"index.css\" rel=\"stylesheet\" type=\"text/css\"/>\n\n<script type=\"module\">\nimport interact"
},
{
"path": "examples/snap/index.css",
"chars": 994,
"preview": "body {\n margin: 0;\n padding: 0;\n border: 0;\n font-family: \"Arial\", sans-serif;\n}\n\ncanvas {\n position: absolute;\n t"
},
{
"path": "examples/snap/index.html",
"chars": 2443,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>interact.js drag snapping</title>\n<meta name=\"de"
},
{
"path": "examples/snap/index.js",
"chars": 9187,
"preview": "/* eslint-disable import/no-absolute-path */\nimport interact from '@interactjs/interactjs'\n\nwindow.interact = interact\n\n"
},
{
"path": "examples/sortable/index.html",
"chars": 1010,
"preview": "<title>interact.js Sortable and Swappable demo</title>\n\n<link rel=\"stylesheet\" href=\"./style.css\">\n\n<body>\n\n <div id=\"r"
},
{
"path": "examples/sortable/react.js",
"chars": 1143,
"preview": "import '@interactjs/react'\nimport { createElement as h, useState } from 'react'\nimport { createRoot } from 'react-dom/cl"
},
{
"path": "examples/sortable/shared.js",
"chars": 1201,
"preview": "import interact from '@interactjs/interactjs'\n\nfunction sortListener(event) {\n console.log(event.type, event.position)\n"
},
{
"path": "examples/sortable/style.css",
"chars": 996,
"preview": "@import \"bulma/css/bulma.css\";\n\nbody {\n margin: 1em;\n _font-size: 2em;\n}\n.container {\n max-width: 500px;\n}\n\n.item.i-s"
},
{
"path": "examples/sortable/vue.js",
"chars": 374,
"preview": "import '@interactjs/vue'\nimport { createApp } from 'vue/dist/vue.esm-bundler'\n\nimport interact from '@interactjs/interac"
},
{
"path": "examples/star/index.css",
"chars": 277,
"preview": ".point-handle {\n cursor: -webkit-grab;\n cursor: -moz-grab;\n cursor: -ms-grab;\n cursor: grab;\n\n touch-acti"
},
{
"path": "examples/star/index.js",
"chars": 2135,
"preview": "document.addEventListener('DOMContentLoaded', () => {\n const sns = 'http://www.w3.org/2000/svg'\n const xns = 'http://w"
},
{
"path": "examples/svg-editor/index.html",
"chars": 594,
"preview": "<svg>\n</svg>\n\n<label>\n Resize invert:\n <select id=\"invert\">\n <option value=\"reposition\">reposition</option>\n <op"
},
{
"path": "examples/svg-editor/index.js",
"chars": 3258,
"preview": "/* eslint-disable import/no-absolute-path */\nimport '@interactjs/actions'\nimport '@interactjs/modifiers'\nimport '@intera"
},
{
"path": "examples/transform/index.html",
"chars": 982,
"preview": "<head>\n<title>interact.js transforms modifier demo</title>\n<script type=\"module\" src=\"./index.js\"></script>\n<link rel=\"s"
},
{
"path": "examples/transform/index.js",
"chars": 1346,
"preview": "import interact from '@interactjs/interactjs'\n// import Vue from '../../node_modules/vue/dist/vue.esm.browser.js'\n\ninter"
},
{
"path": "jest.config.ts",
"chars": 568,
"preview": "import type { Config } from '@jest/types'\n\nimport { sourcesGlob } from './scripts/utils'\n\nconst config: Config.InitialOp"
},
{
"path": "lerna.json",
"chars": 86,
"preview": "{\n \"version\": \"0.0.0\",\n \"packages\": [\n \"@interactjs/*\",\n \"./interactjs\"\n ]\n}\n"
},
{
"path": "package.json",
"chars": 3932,
"preview": "{\n \"name\": \"@interactjs/_dev\",\n \"version\": \"1.10.27\",\n \"private\": true,\n \"directories\": {\n \"bin\": \"./bin\"\n },\n "
},
{
"path": "packages/.eslintrc.cjs",
"chars": 437,
"preview": "module.exports = {\n extends: '../.eslintrc.cjs',\n env: { browser: true, node: false },\n rules: {\n 'no-console': 2,"
},
{
"path": "packages/@interactjs/actions/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/actions/actions.spec.ts",
"chars": 1715,
"preview": "import type { Scope } from '@interactjs/core/scope'\nimport * as helpers from '@interactjs/core/tests/_helpers'\nimport ty"
},
{
"path": "packages/@interactjs/actions/drag/drag.spec.ts",
"chars": 4217,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { InteractEvent } from '@interactjs/core/I"
},
{
"path": "packages/@interactjs/actions/drag/plugin.ts",
"chars": 5547,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { InteractEvent } from '@interactjs/core/I"
},
{
"path": "packages/@interactjs/actions/drop/DropEvent.spec.ts",
"chars": 4112,
"preview": "import type { InteractEvent } from '@interactjs/core/InteractEvent'\nimport extend from '@interactjs/utils/extend'\n\nimpor"
},
{
"path": "packages/@interactjs/actions/drop/DropEvent.ts",
"chars": 2613,
"preview": "import { BaseEvent } from '@interactjs/core/BaseEvent'\nimport type { Interactable } from '@interactjs/core/Interactable'"
},
{
"path": "packages/@interactjs/actions/drop/drop.spec.ts",
"chars": 4996,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport * as helpers from '@interactjs/core/tests/_helpers'\n\n"
},
{
"path": "packages/@interactjs/actions/drop/plugin.ts",
"chars": 21207,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { EventPhase, InteractEvent } from '@inter"
},
{
"path": "packages/@interactjs/actions/gesture/gesture.spec.ts",
"chars": 4880,
"preview": "import type { Scope } from '@interactjs/core/scope'\nimport * as helpers from '@interactjs/core/tests/_helpers'\nimport ex"
},
{
"path": "packages/@interactjs/actions/gesture/plugin.ts",
"chars": 6171,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { InteractEvent, EventPhase } from '@inter"
},
{
"path": "packages/@interactjs/actions/package.json",
"chars": 569,
"preview": "{\n \"name\": \"@interactjs/actions\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\",\n "
},
{
"path": "packages/@interactjs/actions/plugin.ts",
"chars": 592,
"preview": "import type { Scope } from '@interactjs/core/scope'\n\n/* eslint-disable import/no-duplicates -- for typescript module aug"
},
{
"path": "packages/@interactjs/actions/resize/plugin.ts",
"chars": 15076,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { EventPhase, InteractEvent } from '@inter"
},
{
"path": "packages/@interactjs/actions/resize/resize.spec.ts",
"chars": 4133,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport type { ResizeEvent } from './plugin'\nimport resize fr"
},
{
"path": "packages/@interactjs/auto-scroll/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/auto-scroll/package.json",
"chars": 542,
"preview": "{\n \"name\": \"@interactjs/auto-scroll\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module"
},
{
"path": "packages/@interactjs/auto-scroll/plugin.ts",
"chars": 7332,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type Interaction from '@interactjs/core/Interac"
},
{
"path": "packages/@interactjs/auto-start/InteractableMethods.ts",
"chars": 6481,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { Interaction } from '@interactjs/core/Int"
},
{
"path": "packages/@interactjs/auto-start/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/auto-start/autoStart.spec.ts",
"chars": 1936,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport * as helpers from '@interactjs/core/tests/_helpers'\n\nimport au"
},
{
"path": "packages/@interactjs/auto-start/base.ts",
"chars": 10937,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { Interaction } from '@interactjs/core/Int"
},
{
"path": "packages/@interactjs/auto-start/dragAxis.ts",
"chars": 2879,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type Interaction from '@interactjs/core/Interac"
},
{
"path": "packages/@interactjs/auto-start/hold.spec.ts",
"chars": 915,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport hold from './hold'\n\ntest('autoStart/hold', () => {\n "
},
{
"path": "packages/@interactjs/auto-start/hold.ts",
"chars": 1976,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport type { Scope, Plugin } from '@interactjs/core/scope'\n"
},
{
"path": "packages/@interactjs/auto-start/package.json",
"chars": 575,
"preview": "{\n \"name\": \"@interactjs/auto-start\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\""
},
{
"path": "packages/@interactjs/auto-start/plugin.ts",
"chars": 477,
"preview": "import type { Scope } from '@interactjs/core/scope'\n\n/* eslint-disable import/no-duplicates -- for typescript module aug"
},
{
"path": "packages/@interactjs/core/BaseEvent.ts",
"chars": 1445,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { Interaction, InteractionProxy } from '@i"
},
{
"path": "packages/@interactjs/core/Eventable.spec.ts",
"chars": 787,
"preview": "import { Eventable } from './Eventable'\n\ntest('core/Eventable', () => {\n const eventable = new Eventable()\n const type"
},
{
"path": "packages/@interactjs/core/Eventable.ts",
"chars": 1977,
"preview": "import * as arr from '@interactjs/utils/arr'\nimport extend from '@interactjs/utils/extend'\nimport type { NormalizedListe"
},
{
"path": "packages/@interactjs/core/InteractEvent.ts",
"chars": 6238,
"preview": "import extend from '@interactjs/utils/extend'\nimport getOriginXY from '@interactjs/utils/getOriginXY'\nimport hypot from "
},
{
"path": "packages/@interactjs/core/InteractStatic.ts",
"chars": 7197,
"preview": "import browser from '@interactjs/utils/browser'\nimport * as domUtils from '@interactjs/utils/domUtils'\nimport is from '@"
},
{
"path": "packages/@interactjs/core/Interactable.spec.ts",
"chars": 6135,
"preview": "import drag from '@interactjs/actions/drag/plugin'\n\nimport * as helpers from './tests/_helpers'\n\ndescribe('core/Interact"
},
{
"path": "packages/@interactjs/core/Interactable.ts",
"chars": 14743,
"preview": "/* eslint-disable no-dupe-class-members */\nimport * as arr from '@interactjs/utils/arr'\nimport browser from '@interactjs"
},
{
"path": "packages/@interactjs/core/InteractableSet.ts",
"chars": 3361,
"preview": "import * as arr from '@interactjs/utils/arr'\nimport * as domUtils from '@interactjs/utils/domUtils'\nimport extend from '"
},
{
"path": "packages/@interactjs/core/Interaction.spec.ts",
"chars": 15406,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport drop from '@interactjs/actions/drop/plugin'\nimport autoStart f"
},
{
"path": "packages/@interactjs/core/Interaction.ts",
"chars": 17698,
"preview": "import * as arr from '@interactjs/utils/arr'\nimport extend from '@interactjs/utils/extend'\nimport hypot from '@interactj"
},
{
"path": "packages/@interactjs/core/NativeTypes.ts",
"chars": 167,
"preview": "export const NativePointerEvent = null as unknown as InstanceType<typeof PointerEvent>\nexport type NativeEventTarget = E"
},
{
"path": "packages/@interactjs/core/PointerInfo.ts",
"chars": 451,
"preview": "import type { PointerEventType, PointerType } from '@interactjs/core/types'\n\nexport class PointerInfo {\n id: number\n p"
},
{
"path": "packages/@interactjs/core/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/core/events.ts",
"chars": 9036,
"preview": "import * as arr from '@interactjs/utils/arr'\nimport * as domUtils from '@interactjs/utils/domUtils'\nimport is from '@int"
},
{
"path": "packages/@interactjs/core/interactablePreventDefault.spec.ts",
"chars": 920,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport autoStart from '@interactjs/auto-start/base'\n\nimport interacta"
},
{
"path": "packages/@interactjs/core/interactablePreventDefault.ts",
"chars": 3945,
"preview": "import { matchesSelector, nodeContains } from '@interactjs/utils/domUtils'\nimport is from '@interactjs/utils/is'\nimport "
},
{
"path": "packages/@interactjs/core/interactionFinder.spec.ts",
"chars": 1992,
"preview": "import finder from './interactionFinder'\nimport * as helpers from './tests/_helpers'\n\ntest('modifiers/snap', () => {\n c"
},
{
"path": "packages/@interactjs/core/interactionFinder.ts",
"chars": 4033,
"preview": "import * as dom from '@interactjs/utils/domUtils'\n\nimport type Interaction from '@interactjs/core/Interaction'\nimport ty"
},
{
"path": "packages/@interactjs/core/interactions.spec.ts",
"chars": 3067,
"preview": "import Interaction from './Interaction'\nimport interactions from './interactions'\nimport * as helpers from './tests/_hel"
},
{
"path": "packages/@interactjs/core/interactions.ts",
"chars": 8854,
"preview": "import browser from '@interactjs/utils/browser'\nimport domObjects from '@interactjs/utils/domObjects'\nimport { nodeConta"
},
{
"path": "packages/@interactjs/core/options.ts",
"chars": 1099,
"preview": "import type { Point, Listeners, OrBoolean, Element, Rect } from '@interactjs/core/types'\n\nexport interface Defaults {\n "
},
{
"path": "packages/@interactjs/core/package.json",
"chars": 457,
"preview": "{\n \"name\": \"@interactjs/core\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\",\n \"r"
},
{
"path": "packages/@interactjs/core/scope.spec.ts",
"chars": 1751,
"preview": "import type { ActionName } from '@interactjs/core/types'\n\nimport * as helpers from './tests/_helpers'\n\ndescribe('core/sc"
},
{
"path": "packages/@interactjs/core/scope.ts",
"chars": 7246,
"preview": "import browser from '@interactjs/utils/browser'\nimport clone from '@interactjs/utils/clone'\nimport domObjects from '@int"
},
{
"path": "packages/@interactjs/core/tests/_helpers.ts",
"chars": 3561,
"preview": "import extend from '@interactjs/utils/extend'\nimport is from '@interactjs/utils/is'\nimport * as pointerUtils from '@inte"
},
{
"path": "packages/@interactjs/core/types.ts",
"chars": 3699,
"preview": "import type Interaction from '@interactjs/core/Interaction'\n\nimport type { Interactable } from './Interactable'\nimport t"
},
{
"path": "packages/@interactjs/dev-tools/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/dev-tools/babel-plugin-prod.js",
"chars": 1640,
"preview": "/* global process, __dirname */\nconst path = require('path')\n\nconst PROD_EXT = '.prod'\n\nfunction fixImportSource ({ node"
},
{
"path": "packages/@interactjs/dev-tools/babel-plugin-prod.spec.ts",
"chars": 2584,
"preview": "/** @jest-environment node */\nimport * as babel from '@babel/core'\nimport proposalExportDefaultFrom from '@babel/plugin-"
},
{
"path": "packages/@interactjs/dev-tools/devTools.spec.ts",
"chars": 2708,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport resize from '@interactjs/actions/resize/plugin'\nimport * as he"
},
{
"path": "packages/@interactjs/dev-tools/package.json",
"chars": 640,
"preview": "{\n \"name\": \"@interactjs/dev-tools\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\","
},
{
"path": "packages/@interactjs/dev-tools/plugin.ts",
"chars": 5460,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport type { Scope, Plugin } from '@interactjs/core/scope'\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/plugin.stub.ts",
"chars": 18,
"preview": "export default {}\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/plugin.ts",
"chars": 18,
"preview": "export default {}\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/visualizer.spec.stub.ts",
"chars": 34,
"preview": "test.skip('visualizer', () => {})\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/visualizer.spec.ts",
"chars": 34,
"preview": "test.skip('visualizer', () => {})\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/vueModules.stub.ts",
"chars": 10,
"preview": "export {}\n"
},
{
"path": "packages/@interactjs/dev-tools/visualizer/vueModules.ts",
"chars": 10,
"preview": "export {}\n"
},
{
"path": "packages/@interactjs/inertia/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/inertia/inertia.spec.ts",
"chars": 6417,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport type { EventPhase, InteractEvent } from '@interactjs/core/Inte"
},
{
"path": "packages/@interactjs/inertia/package.json",
"chars": 670,
"preview": "{\n \"name\": \"@interactjs/inertia\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\",\n "
},
{
"path": "packages/@interactjs/inertia/plugin.ts",
"chars": 12243,
"preview": "import type { Interaction, DoPhaseArg } from '@interactjs/core/Interaction'\nimport type { Scope, SignalArgs, Plugin } fr"
},
{
"path": "packages/@interactjs/interact/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/interact/index.ts",
"chars": 270,
"preview": "import { Scope } from '@interactjs/core/scope'\n\nconst scope = new Scope()\n\nconst interact = scope.interactStatic\n\nexport"
},
{
"path": "packages/@interactjs/interact/interact.spec.ts",
"chars": 2746,
"preview": "import { Scope } from '@interactjs/core/scope'\n\nconst makeIframeDoc = () => {\n const iframe = document.body.appendChild"
},
{
"path": "packages/@interactjs/interact/package.json",
"chars": 454,
"preview": "{\n \"name\": \"@interactjs/interact\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\",\n"
},
{
"path": "packages/@interactjs/interactjs/index.stub.ts",
"chars": 1681,
"preview": "/* eslint-disable import/no-duplicates -- for typescript module augmentations */\nimport '@interactjs/actions/plugin'\nimp"
},
{
"path": "packages/@interactjs/interactjs/index.ts",
"chars": 1681,
"preview": "/* eslint-disable import/no-duplicates -- for typescript module augmentations */\nimport '@interactjs/actions/plugin'\nimp"
},
{
"path": "packages/@interactjs/interactjs/package.json",
"chars": 1109,
"preview": "{\n \"name\": \"@interactjs/interactjs\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\""
},
{
"path": "packages/@interactjs/modifiers/Modification.ts",
"chars": 10919,
"preview": "import type { EventPhase } from '@interactjs/core/InteractEvent'\nimport type { Interaction, DoAnyPhaseArg } from '@inter"
},
{
"path": "packages/@interactjs/modifiers/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/modifiers/all.ts",
"chars": 727,
"preview": "/* eslint-disable n/no-extraneous-import, import/no-unresolved */\nimport aspectRatio from './aspectRatio'\nimport avoid f"
},
{
"path": "packages/@interactjs/modifiers/aspectRatio.spec.ts",
"chars": 2988,
"preview": "import resize from '@interactjs/actions/resize/plugin'\nimport * as helpers from '@interactjs/core/tests/_helpers'\nimport"
},
{
"path": "packages/@interactjs/modifiers/aspectRatio.ts",
"chars": 4608,
"preview": "/**\n * @module modifiers/aspectRatio\n *\n * @description\n * This modifier forces elements to be resized with a specified "
},
{
"path": "packages/@interactjs/modifiers/avoid/avoid.stub.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/avoid/avoid.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/base.spec.ts",
"chars": 4368,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\nimport type { ActionName, Element } from '@interactjs/core/ty"
},
{
"path": "packages/@interactjs/modifiers/base.ts",
"chars": 3626,
"preview": "import type { InteractEvent } from '@interactjs/core/InteractEvent'\nimport type Interaction from '@interactjs/core/Inter"
},
{
"path": "packages/@interactjs/modifiers/noop.ts",
"chars": 164,
"preview": "import type { ModifierFunction } from './types'\n\nconst noop = (() => {}) as unknown as ModifierFunction<any, any, 'noop'"
},
{
"path": "packages/@interactjs/modifiers/package.json",
"chars": 674,
"preview": "{\n \"name\": \"@interactjs/modifiers\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\","
},
{
"path": "packages/@interactjs/modifiers/plugin.ts",
"chars": 909,
"preview": "import type { Plugin } from '@interactjs/core/scope'\nimport snappers from '@interactjs/snappers/plugin'\n\n/* eslint-disab"
},
{
"path": "packages/@interactjs/modifiers/restrict/edges.spec.ts",
"chars": 2014,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport { restrictEdges } from '../restrict/edges'\n\ntest('res"
},
{
"path": "packages/@interactjs/modifiers/restrict/edges.ts",
"chars": 3201,
"preview": "// This modifier adds the options.resize.restrictEdges setting which sets min and\n// max for the top, left, bottom and r"
},
{
"path": "packages/@interactjs/modifiers/restrict/pointer.spec.ts",
"chars": 1644,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport { restrict } from '../restrict/pointer'\n\ntest('restri"
},
{
"path": "packages/@interactjs/modifiers/restrict/pointer.ts",
"chars": 3082,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport type { RectResolvable, Rect, Point } from '@interactj"
},
{
"path": "packages/@interactjs/modifiers/restrict/rect.ts",
"chars": 461,
"preview": "import extend from '@interactjs/utils/extend'\n\nimport { makeModifier } from '../base'\n\nimport { restrict } from './point"
},
{
"path": "packages/@interactjs/modifiers/restrict/size.spec.ts",
"chars": 1915,
"preview": "import type { ResizeEvent } from '@interactjs/actions/resize/plugin'\nimport resize from '@interactjs/actions/resize/plug"
},
{
"path": "packages/@interactjs/modifiers/restrict/size.ts",
"chars": 2428,
"preview": "import type { Point, Rect, Size } from '@interactjs/core/types'\nimport extend from '@interactjs/utils/extend'\nimport * a"
},
{
"path": "packages/@interactjs/modifiers/rubberband/rubberband.stub.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/rubberband/rubberband.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/snap/edges.spec.ts",
"chars": 1344,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\nimport type { EdgeOptions } from '@interactjs/core/types'\n\nim"
},
{
"path": "packages/@interactjs/modifiers/snap/edges.ts",
"chars": 1512,
"preview": "/**\n * @module modifiers/snapEdges\n *\n * @description\n * This modifier allows snapping of the edges of targets during re"
},
{
"path": "packages/@interactjs/modifiers/snap/pointer.spec.ts",
"chars": 3306,
"preview": "import drag from '@interactjs/actions/drag/plugin'\nimport * as helpers from '@interactjs/core/tests/_helpers'\nimport typ"
},
{
"path": "packages/@interactjs/modifiers/snap/pointer.ts",
"chars": 6024,
"preview": "import type { Interaction, InteractionProxy } from '@interactjs/core/Interaction'\nimport type { ActionName, Point, RectR"
},
{
"path": "packages/@interactjs/modifiers/snap/size.spec.ts",
"chars": 943,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport { snapSize } from '../snap/size'\n\ntest('modifiers/sna"
},
{
"path": "packages/@interactjs/modifiers/snap/size.ts",
"chars": 2140,
"preview": "// This modifier allows snapping of the size of targets during resize\n// interactions.\n\nimport extend from '@interactjs/"
},
{
"path": "packages/@interactjs/modifiers/spring/spring.stub.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/spring/spring.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/transform/transform.stub.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/transform/transform.ts",
"chars": 34,
"preview": "export { default } from '../noop'\n"
},
{
"path": "packages/@interactjs/modifiers/types.ts",
"chars": 1913,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { EventPhase } from '@interactjs/core/Inte"
},
{
"path": "packages/@interactjs/offset/offset.spec.ts",
"chars": 861,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\n\nimport offset from './plugin'\n\ntest('plugins/spring', () => "
},
{
"path": "packages/@interactjs/offset/package.json",
"chars": 567,
"preview": "{\n \"name\": \"@interactjs/offset\",\n \"version\": \"1.10.27\",\n \"main\": \"index\",\n \"module\": \"index\",\n \"type\": \"module\",\n "
},
{
"path": "packages/@interactjs/offset/plugin.ts",
"chars": 2752,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport { _ProxyMethods } from '@interactjs/core/Interaction'"
},
{
"path": "packages/@interactjs/pointer-events/PointerEvent.spec.ts",
"chars": 3688,
"preview": "import * as helpers from '@interactjs/core/tests/_helpers'\nimport * as pointerUtils from '@interactjs/utils/pointerUtils"
},
{
"path": "packages/@interactjs/pointer-events/PointerEvent.ts",
"chars": 2324,
"preview": "import { BaseEvent } from '@interactjs/core/BaseEvent'\nimport type Interaction from '@interactjs/core/Interaction'\nimpor"
},
{
"path": "packages/@interactjs/pointer-events/README.md",
"chars": 201,
"preview": "<h2>\nThis package is an internal part of <a\nhref=\"https://www.npmjs.com/package/interactjs\">interactjs</a> and is not me"
},
{
"path": "packages/@interactjs/pointer-events/base.spec.ts",
"chars": 5597,
"preview": "import { Eventable } from '@interactjs/core/Eventable'\nimport type { Scope } from '@interactjs/core/scope'\nimport * as h"
},
{
"path": "packages/@interactjs/pointer-events/base.ts",
"chars": 8812,
"preview": "import type { Eventable } from '@interactjs/core/Eventable'\nimport type { Interaction } from '@interactjs/core/Interacti"
},
{
"path": "packages/@interactjs/pointer-events/holdRepeat.spec.ts",
"chars": 1837,
"preview": "import { Eventable } from '@interactjs/core/Eventable'\nimport * as helpers from '@interactjs/core/tests/_helpers'\n\nimpor"
},
{
"path": "packages/@interactjs/pointer-events/holdRepeat.ts",
"chars": 2552,
"preview": "import type Interaction from '@interactjs/core/Interaction'\nimport type { ListenerMap, Scope, SignalArgs, Plugin } from "
},
{
"path": "packages/@interactjs/pointer-events/interactableTargets.ts",
"chars": 2195,
"preview": "import type { Interactable } from '@interactjs/core/Interactable'\nimport type { Scope, Plugin } from '@interactjs/core/s"
}
]
// ... and 87 more files (download for full content)
About this extraction
This page contains the full source code of the taye/interact.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 287 files (604.4 KB), approximately 164.3k tokens, and a symbol index with 664 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.