├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── index.d.ts
├── index.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 | test/
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | test
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Jerry Bendy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-touch-events [](https://www.npmjs.com/package/vue2-touch-events)
2 |
3 | Enable tap / swipe / touch hold events for vue.js 2.x
4 |
5 | Features:
6 |
7 | * Common touch events, such as `tap`, `swipe`, `touchhold` ([more](#Bindings))
8 | * All events support mouse and touch screen at same time
9 | * Optimized touch effects with `touchClass` option and `v-touch-class` directive
10 | * Binding multiple touch events on one DOM element
11 | * Customizable events with native-likely events handler
12 | * Allow splitting configurations for different DOM elements by `v-touch-options` directive
13 | * Directive names can be customized to avoid namespace conflict
14 |
15 | **This is for **vue.js 2.x** only. For vue.js 3.x see [this library](https://github.com/robinrodricks/vue3-touch-events).**
16 |
17 | ## Install
18 |
19 | To install with npm or yarn, use
20 |
21 | ```shell
22 | npm i -S vue2-touch-events
23 |
24 | // or
25 |
26 | yarn add vue2-touch-events
27 | ```
28 |
29 | ## Usage
30 |
31 | ```js
32 | import Vue from 'vue'
33 | import Vue2TouchEvents from 'vue2-touch-events'
34 |
35 | Vue.use(Vue2TouchEvents)
36 | ```
37 |
38 | In your `.vue` file:
39 |
40 | ```html
41 |
42 | Tap Me
43 |
44 |
45 | Tap Me
46 |
47 |
48 | Swipe Here
49 |
50 |
51 | Swipe Here
52 |
53 |
54 | Long Tap Event
55 |
56 |
57 | Down,start/Up,end Event
58 |
59 |
60 | Triggered once when starting to move and tapTolerance is exceeded
61 | Continuously triggering Event
62 |
63 |
64 | Touch and hold on the screen for a while
65 |
66 |
67 | Mix Multiple Events
73 |
74 |
75 | Different options
77 |
78 |
79 | Customize touch class
80 |
81 | Customize touch class
82 |
83 |
84 | Change namespace to 'kiss'
85 | ```
86 |
87 | If you use vue and this plugin in UMD way (in a script tag) , this plugin is auto used. So it's not necessary to write `Vue.use(Vue2TouchEvents)`.
88 |
89 | ```html
90 |
91 |
92 | ```
93 |
94 | ## APIs
95 |
96 | ### Global configuration (optional)
97 |
98 | ```js
99 | Vue.use(Vue2TouchEvents, {
100 | disableClick: false,
101 | touchClass: '',
102 | tapTolerance: 10,
103 | touchHoldTolerance: 400,
104 | swipeTolerance: 30,
105 | longTapTimeInterval: 400,
106 | namespace: 'touch'
107 | })
108 | ```
109 |
110 | * `disableClick` default `false`. Use touch event only, will not trigger click event.
111 |
112 | You should keep this value default if you use your website on both mobile and PC.
113 |
114 | If your website uses on mobile only, it's a good choice to set this value to `true` to get a better user experience, and it can resolve some touch pass-through issue.
115 |
116 | * `touchClass` default: `''`. Add an extra CSS class when touch start, and remove it when touch end.
117 |
118 | This is a global config, and you can use `v-touch-class` directive to overwrite this setting in a single component.
119 |
120 | * `tapTolerance` default `10`. The tolerance to ensure whether the tap event effective or not.
121 |
122 | * `touchHoldTolerance` default `400` in millisecond. The timeout for a `touchhold` event.
123 |
124 | * `swipeTolerance` default `30`. The tolerance to ensure whether the swipe event effective or not.
125 |
126 | * `longTapTimeInterval` default `400` in millisecond. The minimum time interval to detect whether long tap event effective or not.
127 |
128 | * `namespace` default `touch`(v3.2.0). Customize the directive names to avoid namespace conflict. By default, the `touch` means `v-touch` and `v-touch-class` are available, and you can use `v-click` and `v-click-class` by change `namespace` to `click`.
129 |
130 | ### Directives
131 |
132 | #### v-touch
133 |
134 | Bind the `v-touch` directive to components which you want to enable touch events.
135 |
136 | `v-touch` accepts an argument to tell it which event you want to bind.
137 |
138 | ```html
139 | Tap
140 | ```
141 |
142 | The first argument of the `v-swipe` callback is the direction of swipe event. It could be `left`, `right`, `top` or `bottom`.
143 |
144 | `v-swipe` can accept extra modifiers. It means you can bind events only for specify direction.
145 |
146 | ```js
147 | export default {
148 | methods: {
149 | swipeHandler (direction) {
150 | console.log(direction) // May be left / right / top / bottom
151 | }
152 | }
153 | }
154 | ```
155 |
156 | ### v-touch-options `(v2.2.0)`
157 |
158 | `v-touch-options` directive allows you set a different configuration for a specified component. It will override global configurations.
159 |
160 | #### v-touch-class
161 |
162 | `v-touch-class` directive allows you set an extra class on your components. If you already have a global config `touchClass`, this value will **overwrite** it.
163 |
164 | For example:
165 |
166 | ```html
167 | Tap Me
168 | ```
169 |
170 | Now, when you start to touch, it will add an extra `active` class automatically. And remove it when touch end.
171 |
172 | If your setting of `disableClick` is `false` (it's default), it will bind `mouseenter` and `mouseleave` events, too.
173 |
174 | So that you can use this feature to instead of `:active` and `:hover` pseudo class, for a better user experience.
175 |
176 | ```css
177 | /* before */
178 | span:active, span:hover {
179 | background: green;
180 | }
181 |
182 | /* now, you can write like this */
183 | span.active {
184 | background: green;
185 | }
186 | ```
187 |
188 | ### Bindings
189 |
190 | #### v-touch:tap / v-touch
191 |
192 | `tap` is the default event type of `v-touch`. It will be trigger when tap on the screen or click the mouse.
193 |
194 | #### v-touch:swipe
195 |
196 | `swipe` means touch on the screen and move in a direction. The direction could be `top`,`bottom`,`left` or `right`.
197 |
198 | #### v-touch:longtap
199 |
200 | > `longtap` will be deprecated in next major version. Please use `touchhold` insead. If you still want to use this feature, please let me know.
201 |
202 | `longtap` means touch on the screen and hold for a while. It will be triggered when you release your finger. (It's not normal when we use touch devices, so it's a good choice to use `touchhold` instaed)
203 |
204 | #### v-touch:touchhold `(v2.1.0)`
205 |
206 | `touchhold` will be triggered when touch on the screen and hold for `touchHoldTolerance` milliseconds. This will be triggered before your finger released, as what native APP does.
207 |
208 | #### v-touch:start / v-touch:end / v-touch:moving
209 |
210 | * `start` is same as `touchstart` or `mousedown`.
211 | * `end` is same as `touchend` or `mouseup`.
212 | * `moving` is same as `touchmovoe` or `mousemove`.
213 |
214 | These three events are like native DOM events. You can use these events to custom behaviors which this library doesn't support yet.
215 |
216 | ### Modifiers
217 |
218 | #### left, right, top, bottom
219 |
220 | This four modifiers are for `v-touch:swipe` only, to specify which direction you want to bind events to.
221 |
222 | #### self
223 |
224 | Same as `v-on:click.self`, only trigger events when the event target is the `currentTarget`.
225 |
226 | #### stop
227 |
228 | Same as `v-on:click.stop`, stops event propagation.
229 |
230 | #### prevent
231 |
232 | Same as `v-on:click.prevent`, prevents default event handler from firing.
233 |
234 | #### disablePassive `(v2.3.0)`
235 |
236 | `{passive: true}` is set for touch event listeners if your browser supports `passive`. This is good for user experience. If this is not what you want, you can use `disablePassive` modifier to prevent this behavior.
237 |
238 | ## Others
239 |
240 | ### How to add extra parameters
241 |
242 | As mentioned by [#3](https://github.com/jerrybendy/vue-touch-events/issues/3), if you want to add extra
243 | parameters for `v-touch`, you can't do that like `v-on`. The hack is that you can let your method returns
244 | a `function` and handle the extra parameters in the returned function.
245 |
246 | ```html
247 |
Swipe
248 | ```
249 |
250 | ```js
251 | export default {
252 | methods: {
253 | myMethod (param) {
254 | return function(direction, event) {
255 | console.log(direction, param);
256 | // do something ~
257 | }
258 | }
259 | }
260 | }
261 | ```
262 |
263 | ### How to resolve conflict with vuetify
264 | Upgrade to the latest version (>= v3.2.0), and use the `namespace` parameter. For example:
265 |
266 | ```js
267 | import Vue2TouchEvents from 'vue2-touch-events'
268 |
269 | Vue.use(Vue2TouchEvents, {
270 | namespace: 'my-touch'
271 | })
272 | ```
273 |
274 | ## Change History
275 |
276 | [Look at here](https://github.com/jerrybendy/vue-touch-events/releases)
277 |
278 | ## LICENSE
279 |
280 | MIT License
281 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | import {PluginObject} from "vue";
2 |
3 | declare const Vue2TouchEvents: PluginObject;
4 |
5 | export interface Vue2TouchEventsOptions {
6 | disableClick?: boolean;
7 | touchClass?: string;
8 | tapTolerance?: number;
9 | swipeTolerance?: number;
10 | longTapTimeInterval?: number;
11 | touchHoldTolerance?: number;
12 | namespace?: string;
13 | }
14 |
15 | export default Vue2TouchEvents;
16 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Jerry Bendy
4 | * @since 4/12/2017
5 | */
6 |
7 | function touchX(event) {
8 | if(event.type.indexOf('mouse') !== -1){
9 | return event.clientX;
10 | }
11 | return event.touches[0].clientX;
12 | }
13 |
14 | function touchY(event) {
15 | if(event.type.indexOf('mouse') !== -1){
16 | return event.clientY;
17 | }
18 | return event.touches[0].clientY;
19 | }
20 |
21 | var isPassiveSupported = (function() {
22 | var supportsPassive = false;
23 | try {
24 | var opts = Object.defineProperty({}, 'passive', {
25 | get: function() {
26 | supportsPassive = true;
27 | }
28 | });
29 | window.addEventListener('test', null, opts);
30 | } catch (e) {}
31 | return supportsPassive;
32 | })();
33 |
34 | // Save last touch time globally (touch start time or touch end time), if a `click` event triggered,
35 | // and the time near by the last touch time, this `click` event will be ignored. This is used for
36 | // resolve touch through issue.
37 | var globalLastTouchTime = 0;
38 |
39 | var vueTouchEvents = {
40 | install: function (Vue, constructorOptions) {
41 |
42 | var globalOptions = Object.assign({}, {
43 | disableClick: false,
44 | tapTolerance: 10, // px
45 | swipeTolerance: 30, // px
46 | touchHoldTolerance: 400, // ms
47 | longTapTimeInterval: 400, // ms
48 | touchClass: '',
49 | namespace: 'touch'
50 | }, constructorOptions);
51 |
52 | function touchStartEvent(event) {
53 | var $this = this.$$touchObj,
54 | isTouchEvent = event.type.indexOf('touch') >= 0,
55 | isMouseEvent = event.type.indexOf('mouse') >= 0,
56 | $el = this;
57 |
58 | if (isTouchEvent) {
59 | globalLastTouchTime = event.timeStamp;
60 | }
61 |
62 | if (isMouseEvent && globalLastTouchTime && event.timeStamp - globalLastTouchTime < 350) {
63 | return;
64 | }
65 |
66 | if ($this.touchStarted) {
67 | return;
68 | }
69 |
70 | addTouchClass(this);
71 |
72 | $this.touchStarted = true;
73 |
74 | $this.touchMoved = false;
75 | $this.swipeOutBounded = false;
76 |
77 | $this.startX = touchX(event);
78 | $this.startY = touchY(event);
79 |
80 | $this.currentX = 0;
81 | $this.currentY = 0;
82 |
83 | $this.touchStartTime = event.timeStamp;
84 |
85 | // Trigger touchhold event after `touchHoldTolerance`ms
86 | $this.touchHoldTimer = setTimeout(function() {
87 | $this.touchHoldTimer = null;
88 | triggerEvent(event, $el, 'touchhold');
89 | }, $this.options.touchHoldTolerance);
90 |
91 | triggerEvent(event, this, 'start');
92 | }
93 |
94 | function touchMoveEvent(event) {
95 | var $this = this.$$touchObj;
96 |
97 | $this.currentX = touchX(event);
98 | $this.currentY = touchY(event);
99 |
100 | if (!$this.touchMoved) {
101 | var tapTolerance = $this.options.tapTolerance;
102 |
103 | $this.touchMoved = Math.abs($this.startX - $this.currentX) > tapTolerance ||
104 | Math.abs($this.startY - $this.currentY) > tapTolerance;
105 |
106 | if($this.touchMoved){
107 | cancelTouchHoldTimer($this);
108 | triggerEvent(event, this, 'moved');
109 | }
110 |
111 | } else if (!$this.swipeOutBounded) {
112 | var swipeOutBounded = $this.options.swipeTolerance;
113 |
114 | $this.swipeOutBounded = Math.abs($this.startX - $this.currentX) > swipeOutBounded &&
115 | Math.abs($this.startY - $this.currentY) > swipeOutBounded;
116 | }
117 |
118 | if($this.touchMoved){
119 | triggerEvent(event, this, 'moving');
120 | }
121 | }
122 |
123 | function touchCancelEvent() {
124 | var $this = this.$$touchObj;
125 |
126 | cancelTouchHoldTimer($this);
127 | removeTouchClass(this);
128 |
129 | $this.touchStarted = $this.touchMoved = false;
130 | $this.startX = $this.startY = 0;
131 | }
132 |
133 | function touchEndEvent(event) {
134 | var $this = this.$$touchObj,
135 | isTouchEvent = event.type.indexOf('touch') >= 0,
136 | isMouseEvent = event.type.indexOf('mouse') >= 0;
137 |
138 | if (isTouchEvent) {
139 | globalLastTouchTime = event.timeStamp;
140 | }
141 |
142 | var touchholdEnd = isTouchEvent && !$this.touchHoldTimer;
143 | cancelTouchHoldTimer($this);
144 |
145 | $this.touchStarted = false;
146 |
147 | removeTouchClass(this);
148 |
149 | if (isMouseEvent && globalLastTouchTime && event.timeStamp - globalLastTouchTime < 350) {
150 | return;
151 | }
152 |
153 | // Fix #33, Trigger `end` event when touch stopped
154 | triggerEvent(event, this, 'end');
155 |
156 | if (!$this.touchMoved) {
157 | // detect if this is a longTap event or not
158 | if ($this.callbacks.longtap && event.timeStamp - $this.touchStartTime > $this.options.longTapTimeInterval) {
159 | if (event.cancelable) {
160 | event.preventDefault();
161 | }
162 | triggerEvent(event, this, 'longtap');
163 |
164 | } else if ($this.callbacks.touchhold && touchholdEnd) {
165 | if (event.cancelable) {
166 | event.preventDefault();
167 | }
168 | return;
169 | } else {
170 | // emit tap event
171 | triggerEvent(event, this, 'tap');
172 | }
173 |
174 | } else if (!$this.swipeOutBounded) {
175 | var swipeOutBounded = $this.options.swipeTolerance,
176 | direction,
177 | distanceY = Math.abs($this.startY - $this.currentY),
178 | distanceX = Math.abs($this.startX - $this.currentX);
179 |
180 | if (distanceY > swipeOutBounded || distanceX > swipeOutBounded) {
181 | if (distanceY > distanceX) {
182 | direction = $this.startY > $this.currentY ? 'top' : 'bottom';
183 | } else {
184 | direction = $this.startX > $this.currentX ? 'left' : 'right';
185 | }
186 |
187 | // Only emit the specified event when it has modifiers
188 | if ($this.callbacks['swipe.' + direction]) {
189 | triggerEvent(event, this, 'swipe.' + direction, direction);
190 | } else {
191 | // Emit a common event when it has no any modifier
192 | triggerEvent(event, this, 'swipe', direction);
193 | }
194 | }
195 | }
196 | }
197 |
198 | function mouseEnterEvent() {
199 | addTouchClass(this);
200 | }
201 |
202 | function mouseLeaveEvent() {
203 | removeTouchClass(this);
204 | }
205 |
206 | function triggerEvent(e, $el, eventType, param) {
207 | var $this = $el.$$touchObj;
208 |
209 | // get the callback list
210 | var callbacks = $this && $this.callbacks[eventType] || [];
211 | if (callbacks.length === 0) {
212 | return null;
213 | }
214 |
215 | for (var i = 0; i < callbacks.length; i++) {
216 | var binding = callbacks[i];
217 |
218 | if (binding.modifiers.stop) {
219 | e.stopPropagation();
220 | }
221 |
222 | if (binding.modifiers.prevent && e.cancelable) {
223 | e.preventDefault();
224 | }
225 |
226 | // handle `self` modifier`
227 | if (binding.modifiers.self && e.target !== e.currentTarget) {
228 | continue;
229 | }
230 |
231 | if (typeof binding.value === 'function') {
232 | if (param) {
233 | binding.value(param, e);
234 | } else {
235 | binding.value(e);
236 | }
237 | }
238 | }
239 | }
240 |
241 | function addTouchClass($el) {
242 | var className = $el.$$touchObj.options.touchClass;
243 | className && $el.classList.add(className);
244 | }
245 |
246 | function removeTouchClass($el) {
247 | var className = $el.$$touchObj.options.touchClass;
248 | className && $el.classList.remove(className);
249 | }
250 |
251 | function cancelTouchHoldTimer($this) {
252 | if ($this.touchHoldTimer) {
253 | clearTimeout($this.touchHoldTimer);
254 | $this.touchHoldTimer = null;
255 | }
256 | }
257 |
258 | function buildTouchObj($el, extraOptions) {
259 | var touchObj = $el.$$touchObj || {
260 | // an object contains all callbacks registered,
261 | // key is event name, value is an array
262 | callbacks: {},
263 | // prevent bind twice, set to true when event bound
264 | hasBindTouchEvents: false,
265 | // default options, would be override by v-touch-options
266 | options: globalOptions
267 | };
268 | if (extraOptions) {
269 | touchObj.options = Object.assign({}, touchObj.options, extraOptions);
270 | }
271 | $el.$$touchObj = touchObj;
272 | return $el.$$touchObj;
273 | }
274 |
275 | Vue.directive(globalOptions.namespace, {
276 | bind: function ($el, binding) {
277 | // build a touch configuration object
278 | var $this = buildTouchObj($el);
279 | // declare passive option for the event listener. Defaults to { passive: true } if supported
280 | var passiveOpt = isPassiveSupported ? { passive: true } : false;
281 | // register callback
282 | var eventType = binding.arg || 'tap';
283 | switch (eventType) {
284 | case 'swipe':
285 | var _m = binding.modifiers;
286 | if (_m.left || _m.right || _m.top || _m.bottom) {
287 | for (var i in binding.modifiers) {
288 | if (['left', 'right', 'top', 'bottom'].indexOf(i) >= 0) {
289 | var _e = 'swipe.' + i;
290 | $this.callbacks[_e] = $this.callbacks[_e] || [];
291 | $this.callbacks[_e].push(binding);
292 | }
293 | }
294 | } else {
295 | $this.callbacks.swipe = $this.callbacks.swipe || [];
296 | $this.callbacks.swipe.push(binding);
297 | }
298 | break;
299 |
300 | case 'start':
301 | case 'moving':
302 | if (binding.modifiers.disablePassive) {
303 | // change the passive option for the moving event if disablePassive modifier exists
304 | passiveOpt = false;
305 | }
306 | // fallthrough
307 | default:
308 | $this.callbacks[eventType] = $this.callbacks[eventType] || [];
309 | $this.callbacks[eventType].push(binding);
310 | }
311 |
312 | // prevent bind twice
313 | if ($this.hasBindTouchEvents) {
314 | return;
315 | }
316 |
317 | $el.addEventListener('touchstart', touchStartEvent, passiveOpt);
318 | $el.addEventListener('touchmove', touchMoveEvent, passiveOpt);
319 | $el.addEventListener('touchcancel', touchCancelEvent);
320 | $el.addEventListener('touchend', touchEndEvent);
321 |
322 | if (!$this.options.disableClick) {
323 | $el.addEventListener('mousedown', touchStartEvent);
324 | $el.addEventListener('mousemove', touchMoveEvent);
325 | $el.addEventListener('mouseup', touchEndEvent);
326 | $el.addEventListener('mouseenter', mouseEnterEvent);
327 | $el.addEventListener('mouseleave', mouseLeaveEvent);
328 | }
329 |
330 | // set bind mark to true
331 | $this.hasBindTouchEvents = true;
332 | },
333 |
334 | unbind: function ($el) {
335 | $el.removeEventListener('touchstart', touchStartEvent);
336 | $el.removeEventListener('touchmove', touchMoveEvent);
337 | $el.removeEventListener('touchcancel', touchCancelEvent);
338 | $el.removeEventListener('touchend', touchEndEvent);
339 |
340 | if ($el.$$touchObj && !$el.$$touchObj.options.disableClick) {
341 | $el.removeEventListener('mousedown', touchStartEvent);
342 | $el.removeEventListener('mousemove', touchMoveEvent);
343 | $el.removeEventListener('mouseup', touchEndEvent);
344 | $el.removeEventListener('mouseenter', mouseEnterEvent);
345 | $el.removeEventListener('mouseleave', mouseLeaveEvent);
346 | }
347 |
348 | // remove vars
349 | delete $el.$$touchObj;
350 | }
351 | });
352 |
353 | Vue.directive(globalOptions.namespace + '-class', {
354 | bind: function ($el, binding) {
355 | buildTouchObj($el, {
356 | touchClass: binding.value
357 | });
358 | }
359 | });
360 |
361 | Vue.directive(globalOptions.namespace + '-options', {
362 | bind: function($el, binding) {
363 | buildTouchObj($el, binding.value);
364 | }
365 | });
366 | }
367 | };
368 |
369 |
370 | /*
371 | * Exports
372 | */
373 | if (typeof module === 'object') {
374 | module.exports = vueTouchEvents;
375 |
376 | } else if (typeof define === 'function' && define.amd) {
377 | define([], function () {
378 | return vueTouchEvents;
379 | });
380 | } else if (window.Vue) {
381 | window.vueTouchEvents = vueTouchEvents;
382 | Vue.use(vueTouchEvents);
383 | }
384 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue2-touch-events",
3 | "version": "3.2.3",
4 | "description": "Simple touch events support for vueJS2",
5 | "main": "index.js",
6 | "types": "index.d.ts",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/jerrybendy/vue-touch-events.git"
13 | },
14 | "keywords": [
15 | "vue",
16 | "touch",
17 | "tap",
18 | "swipe",
19 | "longtap"
20 | ],
21 | "author": "Jerry Bendy ",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/jerrybendy/vue-touch-events/issues"
25 | },
26 | "homepage": "https://github.com/jerrybendy/vue-touch-events#readme",
27 | "devDependencies": {
28 | "@types/vue": "^2.0.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------