├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .vuepress ├── components │ ├── BaseButton.vue │ ├── BaseSwitch.vue │ ├── DemoInteractDraggable.vue │ ├── DemoInteractDraggableWithEventBus.vue │ └── styles │ │ ├── animations.scss │ │ ├── colors.scss │ │ ├── index.scss │ │ ├── mixins.scss │ │ └── typography.scss ├── config.js └── enhanceApp.js ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs └── vue2InteractDraggable │ └── README.md ├── package.json ├── rollup.config.js ├── src ├── components │ └── Vue2InteractDraggable.vue ├── index.js └── interact-event-bus.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/*.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['eslint:recommended', 'plugin:vue/recommended'], 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | }, 6 | env: { 7 | node: true, 8 | browser: true 9 | }, 10 | 'rules': { 11 | 'generator-star-spacing': 0, 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 13 | }, 14 | globals: { 15 | requestAnimationFrame: true, 16 | performance: true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | dist 5 | yarn-error.log 6 | PLAN.md 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.vuepress/components/BaseButton.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 40 | 41 | 78 | -------------------------------------------------------------------------------- /.vuepress/components/BaseSwitch.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 68 | 69 | 131 | -------------------------------------------------------------------------------- /.vuepress/components/DemoInteractDraggable.vue: -------------------------------------------------------------------------------- 1 | 104 | 105 | 154 | 155 | -------------------------------------------------------------------------------- /.vuepress/components/DemoInteractDraggableWithEventBus.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 113 | 114 | -------------------------------------------------------------------------------- /.vuepress/components/styles/animations.scss: -------------------------------------------------------------------------------- 1 | $ease-out-back: cubic-bezier(0.175, 0.885, 0.32, 1.275); 2 | 3 | @keyframes scaleUpAndDown { 4 | 0% { 5 | opacity: 1; 6 | transform: scale(1); 7 | } 8 | 9 | 60% { 10 | opacity: 0; 11 | transform: scale(1.4); 12 | } 13 | 14 | 61% { 15 | opacity: 0; 16 | transform: scale(1); 17 | } 18 | 19 | 100% { 20 | opacity: 1; 21 | transform: scale(1); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.vuepress/components/styles/colors.scss: -------------------------------------------------------------------------------- 1 | $c-white: #fff; 2 | $c-black: #000; 3 | $c-red-50: #73345e; 4 | $c-red-25: #432958; 5 | $c-navy: #0f0e3d; 6 | $c-text: #8285a7; 7 | $primary-gradient-start: #35495e; 8 | $primary-gradient-end: #42b883; 9 | -------------------------------------------------------------------------------- /.vuepress/components/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import "../styles/mixins.scss"; 2 | @import "../styles/colors.scss"; 3 | @import "../styles/typography.scss"; 4 | @import "../styles/animations.scss"; 5 | -------------------------------------------------------------------------------- /.vuepress/components/styles/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin _position($position, $args) { 2 | @each $dir in top, left, bottom, right { 3 | $i: index($args, $dir); 4 | 5 | @if $i { 6 | #{$dir}: nth($args, $i + 1); 7 | } 8 | } 9 | 10 | position: $position; 11 | } 12 | 13 | @mixin absolute($args) { 14 | @include _position(absolute, $args); 15 | } 16 | 17 | @mixin card() { 18 | @include absolute(0); 19 | @include sizing(200px); 20 | @include flex-center(); 21 | 22 | display: flex; 23 | height: 100vw; 24 | max-height: 200px; 25 | margin: auto; 26 | border-radius: 15px; 27 | box-shadow: 0 30px 30px 0 rgba(0, 0, 0, 0.05); 28 | font-size: $fs-h2; 29 | font-weight: $fw-bold; 30 | color: $c-white; 31 | background-image: linear-gradient( 32 | -180deg, 33 | $primary-gradient-start 2%, 34 | $primary-gradient-end 100% 35 | ); 36 | opacity: 1; 37 | transform-origin: 50%, 100%; 38 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 39 | user-select: none; 40 | pointer-events: none; 41 | will-change: transform, opacity; 42 | pointer-events: auto; 43 | 44 | &__title { 45 | margin: 0 0 15px; 46 | font-size: $fs-card-title; 47 | } 48 | } 49 | 50 | @mixin sizing($args, $prefix: "") { 51 | $width: if(length($args) == 2, nth($args, 1), $args); 52 | $height: if(length($args) == 2, nth($args, 2), $args); 53 | 54 | #{$prefix}width: $width; 55 | #{$prefix}height: $height; 56 | } 57 | 58 | @mixin flex-center() { 59 | display: flex; 60 | align-items: center; 61 | justify-content: center; 62 | } 63 | 64 | @mixin circle($args) { 65 | @include sizing($args); 66 | 67 | border-radius: 50%; 68 | } 69 | 70 | @mixin after() { 71 | &::after { 72 | content: ""; 73 | 74 | @content; 75 | } 76 | } 77 | 78 | @mixin before() { 79 | &::before { 80 | content: ''; 81 | 82 | @content; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.vuepress/components/styles/typography.scss: -------------------------------------------------------------------------------- 1 | $fs-h2: rem(24px); 2 | $fw-bold: 700; 3 | -------------------------------------------------------------------------------- /.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'vue2-interact', 3 | themeConfig:{ 4 | sidebar: [ 5 | { 6 | collapsable: false, 7 | children: [ 8 | '/' 9 | ] 10 | }, 11 | { 12 | collapsable: false, 13 | children: [ 14 | '/docs/vue2InteractDraggable/' 15 | ] 16 | } 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import Vue2InteractDraggable from "../src/components/Vue2InteractDraggable"; 2 | 3 | export default ({ 4 | Vue, 5 | }) => { 6 | Vue.component('Vue2InteractDraggable', Vue2InteractDraggable) 7 | } 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/mateuszRybczonek/vue2-interact). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **Keep the same style** - eslint will automatically be ran before committing 11 | 12 | - **Tip** to pass lint tests easier use the `npm run lint:fix` command 13 | 14 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 15 | 16 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 17 | 18 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 19 | 20 | - **Create feature branches** - Don't ask us to pull from your master branch. 21 | 22 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 23 | 24 | - **Send coherent history** - Make sure your commits message means something 25 | 26 | 27 | **Happy coding**! 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Mateusz Rybczonek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue2-interact 2 | 3 | > [interact.js](http://interactjs.io/) wrapper component for Vue.js apps 4 | 5 | ## Installation 6 | 7 | ```bash 8 | yarn add vue2-interact 9 | ``` 10 | 11 | ## Documentation 12 | > [Go to docs and demo](https://vue2-interact.netlify.com/) 13 | 14 | ## Usage 15 | 16 | ```js 17 | import Vue from 'vue' 18 | import { Vue2InteractDraggable } from 'vue2-interact' 19 | 20 | export default { 21 | components: { 22 | Vue2InteractDraggable 23 | } 24 | } 25 | ``` 26 | 27 | ## Development 28 | 29 | ### Launch visual tests 30 | 31 | ```bash 32 | yarn watch 33 | ``` 34 | 35 | ### Build 36 | 37 | Bundle the js and css of to the `dist` folder: 38 | 39 | ```bash 40 | yarn build 41 | ``` 42 | 43 | ## Publishing 44 | 45 | The `prepare` hook will ensure dist files are created before publishing. This 46 | way you don't need to commit them in your repository. 47 | 48 | ```bash 49 | # Bump the version first 50 | # It'll also commit it and create a tag 51 | npm version 52 | # Push the bumped package and tags 53 | git push --follow-tags 54 | # Ship it 🚀 55 | npm publish 56 | ``` 57 | 58 | ## License 59 | 60 | [MIT](http://opensource.org/licenses/MIT) 61 | -------------------------------------------------------------------------------- /docs/vue2InteractDraggable/README.md: -------------------------------------------------------------------------------- 1 | # vue2-interact-draggable 2 | 3 | > interact.js draggable wrapper component for Vue.js 4 | 5 | ## Basic usage 6 | 7 | ### 1. Import component 8 | ```js 9 | import Vue from 'vue' 10 | import { Vue2InteractDraggable } from 'vue2-interact' 11 | 12 | export default { 13 | components: { 14 | Vue2InteractDraggable 15 | } 16 | } 17 | ``` 18 | 19 | ### 2. Use component 20 | ```html 21 | 27 |
28 |

Drag me!

29 |
30 |
31 | ``` 32 | 33 | ### 3. Demo 34 | 35 | 36 | 37 | [Sandbox demo](https://codesandbox.io/s/n34kv9n2wp) 38 | 39 | ## Event bus usage 40 | Using event bus allows us to fire the `Vue2InteractDraggable` component methods from the outside of the component. 41 | 42 | The component accepts `interact-event-bus-events` property tells `Vue2InteractDraggable` component to listen to those events and fire appropriate method when needed. 43 | 44 | Available events: 45 | - `draggedDown` 46 | - `draggedLeft` 47 | - `draggedRight` 48 | - `draggedUp` 49 | 50 | By emitting appropriate event in the event bus we can trigger the method from anywhere in the application. 51 | 52 | ### 1. Import component and event bus 53 | ```js 54 | import Vue from 'vue' 55 | import { Vue2InteractDraggable, InteractEventBus } from 'vue2-interact' 56 | 57 | export default { 58 | components: { 59 | Vue2InteractDraggable 60 | } 61 | } 62 | ``` 63 | 64 | ### 2. Use component 65 | ```html 66 | 72 |
73 |

Drag me!

74 |
75 |
76 | 77 | 78 | ``` 79 | 80 | ```js 81 | 101 | ``` 102 | 103 | ### 3. Demo 104 | 105 | 106 | 107 | [Sandbox demo](https://codesandbox.io/s/5wo373kqwk) 108 | 109 | ## Listeners 110 | 111 | ### draggedRight 112 | 113 | Function fired when element is dragged right from its original position by distance specified in `interact-x-threshold` property. 114 | 115 | ### draggedLeft 116 | 117 | Function fired when element is dragged left from its original position by distance specified in `interact-x-threshold` property. 118 | 119 | ### draggedUp 120 | 121 | Function fired when element is dragged up from its original position by distance specified in `interact-y-threshold` property. 122 | 123 | ### draggedDown 124 | 125 | Function fired when element is dragged down from its original position by distance specified in `interact-y-threshold` property. 126 | 127 | ## Properties 128 | 129 | ### interact-block 130 | 131 | - type: Boolean 132 | - default: false 133 | 134 | - available types: 135 | - `interact-block-drag-down` 136 | - `interact-block-drag-up` 137 | - `interact-block-drag-left` 138 | - `interact-block-drag-right` 139 | 140 | Prevent an event from being fired when the element is dragged in certain direction. 141 | 142 | ### interact-max-rotation 143 | 144 | - type: Number 145 | - default: 0 146 | 147 | Specify maximum rotation in degrees to which the element is rotated during horizontal drag. 148 | 149 | ### interact-lock 150 | 151 | - type: Boolean 152 | - default: false 153 | 154 | - available types: 155 | - `interact-lock-x-axis` 156 | - `interact-lock-y-axis` 157 | - `interact-lock-swipe-down` 158 | - `interact-lock-swipe-up` 159 | - `interact-lock-swipe-left` 160 | - `interact-lock-swipe-right` 161 | 162 | Prevent swiping in specified axis or direction. 163 | 164 | ### interact-x-threshold 165 | 166 | - type: Number 167 | - default: 200 168 | 169 | Horizontal (X) distance to which the element must be dragged to fire the appropriate event. 170 | 171 | ### interact-y-threshold 172 | 173 | - type: Number 174 | - default: 300 175 | 176 | Vertical (Y) distance to which the element must be dragged to fire the appropriate event. 177 | 178 | ### interact-out-of-sight-x-coordinate 179 | 180 | - type: Number 181 | - default: 500 182 | 183 | Horizontal (X) distance to which the element will be moved when horizontal (X) threshold is met at the end of drag. 184 | 185 | ### interact-out-of-sight-y-coordinate 186 | 187 | - type: Number 188 | - default: 1000 189 | 190 | Vertical (Y) distance to which the element will be moved when vertical (Y) threshold is met at the end of drag. 191 | 192 | ### interactEventBusEvents 193 | 194 | - type: Object 195 | - default: {} 196 | 197 | Allows to fire the `Vue2InteractDraggable` component methods from the outside of the component. 198 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue2-interact", 3 | "version": "0.0.3", 4 | "description": "Interact wrapper component for Vue.js apps", 5 | "author": "Mateusz Rybczonek ", 6 | "main": "dist/vue2-interact.common.js", 7 | "module": "dist/vue2-interact.esm.js", 8 | "browser": "dist/vue2-interact.js", 9 | "unpkg": "dist/vue2-interact.js", 10 | "style": "dist/vue2-interact.css", 11 | "files": [ 12 | "dist", 13 | "src" 14 | ], 15 | "scripts": { 16 | "build": "NODE_ENV=production rollup -c", 17 | "watch": "NODE_ENV=dev rollup -c -w", 18 | "lint": "yarn lint:js && yarn lint:css", 19 | "lint:js": "eslint --ext .js,.vue src", 20 | "lint:js:fix": "yarn lint:js --fix", 21 | "lint:css": "stylelint src/**/*.{vue,css}", 22 | "pretest": "yarn lint", 23 | "prepare": "yarn build", 24 | "docs:dev": "vuepress dev", 25 | "docs:build": "vuepress build" 26 | }, 27 | "dependencies": { 28 | "interact.js": "^1.2.8" 29 | }, 30 | "devDependencies": { 31 | "babel-core": "^6.26.3", 32 | "babel-eslint": "^8.2.3", 33 | "babel-plugin-external-helpers": "^6.22.0", 34 | "babel-plugin-transform-async-to-generator": "^6.24.1", 35 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 36 | "babel-plugin-transform-runtime": "^6.23.0", 37 | "babel-preset-env": "^1.7.0", 38 | "clean-css": "^4.1.11", 39 | "eslint": "^3.19.0", 40 | "eslint-plugin-vue": "^4.5.0", 41 | "node-sass": "^4.10.0", 42 | "rollup": "^0.58.2", 43 | "rollup-plugin-babel": "^3.0.6", 44 | "rollup-plugin-commonjs": "^9.1.3", 45 | "rollup-plugin-node-resolve": "^3.3.0", 46 | "rollup-plugin-uglify": "^3.0.0", 47 | "rollup-plugin-vue": "^2.3.0", 48 | "sass-loader": "^7.1.0", 49 | "stylelint": "^7.10.0", 50 | "stylelint-config-standard": "^16.0.0", 51 | "stylelint-processor-arbitrary-tags": "^0.1.0", 52 | "vue": "^2.5.17", 53 | "vuepress": "^0.14.4" 54 | }, 55 | "peerDependencies": { 56 | "vue": "^2.5.17" 57 | }, 58 | "postcss": { 59 | "plugins": { 60 | "autoprefixer": {} 61 | } 62 | }, 63 | "repository": { 64 | "type": "git", 65 | "url": "git+https://github.com/mateuszRybczonek/vue2-interact.git" 66 | }, 67 | "bugs": { 68 | "url": "https://github.com/mateuszRybczonek/vue2-interact/issues" 69 | }, 70 | "homepage": "https://github.com/mateuszRybczonek/vue2-interact#readme", 71 | "license": "MIT", 72 | "browserslist": [ 73 | "last 2 versions" 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | import babel from 'rollup-plugin-babel' 4 | import uglify from 'rollup-plugin-uglify' 5 | import vue from 'rollup-plugin-vue' 6 | import CleanCSS from 'clean-css'; 7 | import fs from 'fs'; 8 | 9 | const pkg = require('./package.json') 10 | 11 | const input = 'src/index.js'; 12 | 13 | export default [ 14 | { 15 | input, 16 | output: { 17 | file: pkg.browser, 18 | format: 'umd', 19 | name: 'Vue2Interact', 20 | sourcemap: process.env.NODE_ENV === 'dev' 21 | }, 22 | plugins: [ 23 | resolve(), 24 | vue({ 25 | compileTemplate: true, 26 | css: false 27 | }), 28 | commonjs(), 29 | babel({ 30 | exclude: ['node_modules/**'], 31 | runtimeHelpers: true, 32 | }), 33 | uglify() 34 | ] 35 | }, 36 | { 37 | input, 38 | external: Object.keys(pkg.dependencies || {}), 39 | output: [ 40 | { 41 | file: pkg.main, 42 | format: 'cjs', 43 | sourcemap: process.env.NODE_ENV === 'dev' 44 | }, 45 | { 46 | file: pkg.module, 47 | format: 'es', 48 | sourcemap: process.env.NODE_ENV === 'dev' 49 | } 50 | ], 51 | plugins: [ 52 | vue({ 53 | compileTemplate: true, 54 | css(styles) { 55 | fs.writeFileSync(pkg.style, new CleanCSS().minify(styles).styles) 56 | } 57 | }), 58 | babel({ 59 | runtimeHelpers: true, 60 | exclude: ['node_modules/**'] 61 | }), 62 | ] 63 | } 64 | ] 65 | -------------------------------------------------------------------------------- /src/components/Vue2InteractDraggable.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 280 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Vue2InteractDraggable from './components/Vue2InteractDraggable.vue' 2 | import InteractEventBus from './interact-event-bus.js'; 3 | 4 | const plugin = { 5 | install (Vue) { 6 | Vue.component('Vue2InteractDraggable', Vue2InteractDraggable) 7 | } 8 | } 9 | 10 | export { Vue2InteractDraggable }; 11 | export { InteractEventBus }; 12 | 13 | // Auto-install 14 | let GlobalVue = null 15 | if (typeof window !== 'undefined') { 16 | GlobalVue = window.Vue 17 | } else if (typeof global !== 'undefined') { 18 | GlobalVue = global.Vue 19 | } 20 | if (GlobalVue) { 21 | GlobalVue.use(plugin) 22 | } 23 | -------------------------------------------------------------------------------- /src/interact-event-bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | export default new Vue(); 4 | --------------------------------------------------------------------------------