8 |
9 |
10 |
21 |
--------------------------------------------------------------------------------
/playground/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + Vite
2 |
3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `
9 |
10 |
11 |
29 |
30 |
31 |
32 |
101 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import dragSetup from './events/dragSetup';
2 |
3 | import vueDragEvent from './utils/vueDragEvent';
4 |
5 | // Add draggable configuration to element for the first time
6 | const mountedHook = (el, binding) => {
7 | dragSetup(el, binding);
8 | };
9 |
10 | // Update the drag configuration
11 | const updatedHook = (el, binding) => {
12 | // Remove events from updated element
13 | el.onmousedown = null;
14 | el.ontouchstart = null;
15 |
16 | const handle = typeof binding.oldValue === 'object'
17 | ? binding.oldValue.handle
18 | : binding.oldValue;
19 |
20 | const oldHandleArray = document.querySelectorAll(handle);
21 |
22 | oldHandleArray.forEach((oldHandle) => {
23 | // Remove events from the old handle
24 | oldHandle.onmousedown = null;
25 | oldHandle.ontouchstart = null;
26 |
27 | // Remove CSS classes related to the old handle
28 | oldHandle.classList.remove(window.data.class.handle);
29 | el.classList.remove(window.data.class.usesHandle);
30 | });
31 |
32 | // Vue event if anything is updated
33 | if (binding.oldValue) {
34 | Object.keys(binding.oldValue).forEach((key) => {
35 | vueDragEvent(el, `update-${key}`);
36 | });
37 | }
38 |
39 | // Add draggable configuration to element
40 | dragSetup(el, binding);
41 | };
42 |
43 | // Create custom directive
44 | export default {
45 | install(Vue, options) {
46 | // Initialize 'data' object
47 | window.data = {};
48 |
49 | // Store default event classes
50 | window.data.class = {
51 | initial: 'drag-draggable',
52 | usesHandle: 'drag-uses-handle',
53 | handle: 'drag-handle',
54 | down: 'drag-down',
55 | move: 'drag-move',
56 | };
57 |
58 | let removeTransition = true;
59 |
60 | // Replace default event classes with custom ones
61 | if (options) {
62 | if (options.eventClass) {
63 | const classes = options.eventClass;
64 |
65 | Object.keys(classes).forEach((key) => {
66 | if (classes[key]) {
67 | window.data.class[key] = classes[key];
68 | }
69 | });
70 | }
71 |
72 | if (typeof options.removeTransition === 'boolean') {
73 | removeTransition = options.removeTransition;
74 | }
75 | }
76 |
77 | // Create stylesheet with basic styling (position, z-index and cursors)
78 | const styleElement = document.createElement('style');
79 | styleElement.innerHTML = `.${window.data.class.initial}{position:relative;}.${window.data.class.initial}:not(.${window.data.class.usesHandle}),.${window.data.class.handle}{cursor:move;cursor:grab;cursor:-webkit-grab;}.${window.data.class.handle}.${window.data.class.down},.${window.data.class.initial}:not(.${window.data.class.usesHandle}).${window.data.class.down}{z-index:999;cursor:grabbing;cursor:-webkit-grabbing;}`;
80 | styleElement.innerHTML += removeTransition === true ? `.${window.data.class.move}{transition:none;}` : '';
81 | document.body.appendChild(styleElement);
82 |
83 | // Register 'v-drag' directive
84 | Vue.directive('drag', {
85 | // Hooks for Vue3
86 | mounted(el, binding) {
87 | mountedHook(el, binding);
88 | },
89 |
90 | updated(el, binding) {
91 | updatedHook(el, binding);
92 | },
93 |
94 | // Hooks for Vue2
95 | inserted(el, binding) {
96 | mountedHook(el, binding);
97 | },
98 |
99 | update(el, binding) {
100 | updatedHook(el, binding);
101 | },
102 | });
103 | },
104 | };
105 |
--------------------------------------------------------------------------------
/src/tests/utils.test.js:
--------------------------------------------------------------------------------
1 | import isValidAxisValue from '../utils/isValidAxisValue';
2 | import returnPositionString from '../utils/returnPositionString';
3 | import getSnappingValues from '../utils/getSnappingValues';
4 |
5 | describe('Utils', () => {
6 | describe('getSnappingValues', () => {
7 | test('Declare value with number', () => {
8 | expect(getSnappingValues(10)).toStrictEqual({ x: 10, y: 10 });
9 | });
10 | test('Declare value with number 0', () => {
11 | expect(getSnappingValues(0)).toStrictEqual({ x: 1, y: 1 });
12 | });
13 | test('Declare value with string, without units', () => {
14 | expect(getSnappingValues('10')).toStrictEqual({ x: 10, y: 10 });
15 | });
16 | test('Declare value with string, with units', () => {
17 | expect(getSnappingValues('10px')).toStrictEqual({ x: 10, y: 10 });
18 | });
19 | test('Declare value with empty string', () => {
20 | expect(getSnappingValues('')).toStrictEqual({ x: 1, y: 1 });
21 | });
22 | test('Declare value with array of numbers of length 1', () => {
23 | expect(getSnappingValues([10])).toStrictEqual({ x: 10, y: 10 });
24 | });
25 | test('Declare value with array of numbers of length 2', () => {
26 | expect(getSnappingValues([10, 20])).toStrictEqual({ x: 10, y: 20 });
27 | });
28 | test('Declare value with array of numbers of length 3', () => {
29 | expect(getSnappingValues([10, 20, 30])).toStrictEqual({ x: 10, y: 20 });
30 | });
31 | test('Declare value with empty array', () => {
32 | expect(getSnappingValues([])).toStrictEqual({ x: 1, y: 1 });
33 | });
34 | test('Declare value with array of strings of length 1', () => {
35 | expect(getSnappingValues(['10'])).toStrictEqual({ x: 10, y: 10 });
36 | });
37 | test('Declare value with array of strings of length 2', () => {
38 | expect(getSnappingValues(['10', '20px'])).toStrictEqual({ x: 10, y: 20 });
39 | });
40 | test('Declare value with array of strings of length 3', () => {
41 | expect(getSnappingValues(['10px', '20', '30px'])).toStrictEqual({ x: 10, y: 20 });
42 | });
43 | test('Declare value with object', () => {
44 | expect(getSnappingValues({ x: 10, y: '20' })).toStrictEqual({ x: 10, y: 20 });
45 | });
46 | test('Declare value with object missing one value', () => {
47 | expect(getSnappingValues({ x: '10px' })).toStrictEqual({ x: 10, y: 1 });
48 | });
49 | test('Declare value with empty object', () => {
50 | expect(getSnappingValues({})).toStrictEqual({ x: 1, y: 1 });
51 | });
52 | test("Declare value with boolean 'true'", () => {
53 | expect(getSnappingValues(true)).toStrictEqual({ x: 1, y: 1 });
54 | });
55 | test("Declare value with boolean 'false'", () => {
56 | expect(getSnappingValues(false)).toStrictEqual({ x: 1, y: 1 });
57 | });
58 | test('Empty declaration', () => {
59 | expect(getSnappingValues()).toStrictEqual({ x: 1, y: 1 });
60 | });
61 | });
62 |
63 | describe('isValidAxisValue', () => {
64 | test("Validate axis when the value is 'x'", () => {
65 | expect(isValidAxisValue('x')).toBeTruthy();
66 | });
67 | test("Validate axis when the value is 'y'", () => {
68 | expect(isValidAxisValue('y')).toBeTruthy();
69 | });
70 | test("Validate axis when the value is 'all'", () => {
71 | expect(isValidAxisValue('all')).toBeTruthy();
72 | });
73 | test('Validate axis when the value is another one', () => {
74 | expect(isValidAxisValue('fall')).toBeFalsy();
75 | });
76 | test('Validate axis when the value is empty', () => {
77 | expect(isValidAxisValue('')).toBeFalsy();
78 | });
79 | });
80 |
81 | describe('returnPositionString', () => {
82 | test('Return string when matrix is defined', () => {
83 | const data = ['1, 2, 3, 4,'];
84 | expect(returnPositionString(data, 20, 30)).toBe('matrix(1, 2, 3, 4, 20, 30)');
85 | });
86 | test('Return string when matrix is not defined', () => {
87 | const data = false;
88 | expect(returnPositionString(data, 20, 30)).toBe('matrix(1, 0, 0, 1, 20, 30)');
89 | });
90 | });
91 | });
92 |
--------------------------------------------------------------------------------
/dist/module.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * v-drag v3.0.9
3 | * by Nil Vila and contributors
4 | */
5 | function a(a,t){const n="x"===t?window.data.snapX:window.data.snapY;return Math.round(a/n)*n}function t(a,t,n="add"){a.forEach(a=>{document[n+"EventListener"](a,t,!1)})}function n(a,t,n){return`matrix(${a||"1, 0, 0, 1,"} ${t}, ${n})`}function o(a,t){a.dispatchEvent(new Event("v-drag-"+t))}function e(t,e){window.data.relativeX=window.data.mouseX*t,window.data.relativeY=window.data.mouseY*e,window.data.move.style.transform=n(window.data.matrix,window.data.matrixX+a(window.data.relativeX,"x"),window.data.matrixY+a(window.data.relativeY,"y")),o(window.data.move,"moving"),(window.getSelection?window.getSelection():document.selection).empty()}const d={x(){e(!0,!1)},y(){e(!1,!0)},all(){e(!0,!0)}};function i(){d[window.data.axis](window.data),window.data.posAnimation=requestAnimationFrame(i)}function s(){window.data.move.classList.add(window.data.class.move),window.data.posAnimation=requestAnimationFrame(i),t(["mousemove","touchmove"],s,"remove")}function w(a,t){let n=Number(window.getComputedStyle(window.data.move)[t].replace("px",""));if("none"!==a){const o=a.match(/[0-9.-]+/g);n+=Number(o[8-t.length])}return n}function l(a,t,n){window.data.move.style.transform=a,window.data.move.style.left=t,window.data.move.style.top=n}function c(a){a.preventDefault(),window.data.mouseX=(a.pageX||a.touches[0].pageX)-window.data.initialX,window.data.mouseY=(a.pageY||a.touches[0].pageY)-window.data.initialY,window.setTimeout(()=>{(a.clientY||a.touches[0].clientY)>.8*window.innerHeight&&(document.documentElement.scrollTop+=10),(a.clientY||a.touches[0].clientY)<.2*window.innerHeight&&(document.documentElement.scrollTop-=10),(a.clientX||a.touches[0].clientX)>.8*window.innerWidth&&(document.documentElement.scrollLeft+=10),(a.clientX||a.touches[0].clientX)<.2*window.innerWidth&&(document.documentElement.scrollLeft-=10)},100)}function r(a,e,d,i,r){r.preventDefault(),window.data.grab=a,window.data.move=e,window.data.axis=d,window.data.initialX=r.pageX||r.touches[0].pageX,window.data.initialY=r.pageY||r.touches[0].pageY,window.data.relativeX=0,window.data.relativeY=0,window.data.snapX=i.x,window.data.snapY=i.y;const u=window.getComputedStyle(window.data.move).transform;window.data.matrix="none"!==u&&u.match(/\d([^,]*,){4}/g);const m=w(u,"left"),v=w(u,"top");l(n(window.data.matrix,m,v),0,0),window.data.matrixX=m,window.data.matrixY=v,window.data.grab.classList.add(window.data.class.down),o(e,"down"),o(e,"start"),t(["mousemove","touchmove"],c),t(["mousemove","touchmove"],s)}function u(){window.data.grab&&window.data.move&&(cancelAnimationFrame(window.data.posAnimation),t(["mousemove","touchmove"],s,"remove"),l(window.data.matrix?n(window.data.matrix,0,0):"none",window.data.matrixX+a(window.data.relativeX,"x")+"px",window.data.matrixY+a(window.data.relativeY,"y")+"px"),window.data.grab.classList.remove(window.data.class.down),window.data.move.classList.remove(window.data.class.move),o(window.data.move,"end"),t(["mousemove","touchmove"],c,"remove"))}function m(a,t){const n="string"==typeof a?parseInt(a.replace(/px/g,""),10):a;return 0===n||Number.isNaN(n)||t&&void 0===n?1:n}function v(a){return!!["x","y","all"].includes(a)}function p(a,n){const e=n.value||{},d=e instanceof Object?e.handle:e,i=function(a){if("string"==typeof a){const t=a.split(",");return{x:m(t[0]),y:void 0!==m(t[1])?m(t[1]):m(t[0])}}return"number"==typeof a?{x:m(a),y:m(a)}:a instanceof Object&&(a.x||a.y)?{x:m(a.x)||1,y:m(a.y)||1}:Array.isArray(a)?{x:m(a[0])||1,y:void 0!==m(a[1])?m(a[1],!0):m(a[0],!0)}:{x:1,y:1}}(e.snap),s=[];let w;w=e instanceof Object&&e.axis&&v(e.axis)?e.axis:v(n.arg)?n.arg:"all",d instanceof HTMLElement?s.push(d):document.querySelectorAll(d).forEach(a=>{s.push(a)}),0!==s.length?(a.classList.add(window.data.class.usesHandle),s.forEach(t=>{t.classList.add(window.data.class.handle),t.onmousedown=n=>r(t,a,w,i,n),t.ontouchstart=n=>r(t,a,w,i,n)})):(a.onmousedown=t=>r(a,a,w,i,t),a.ontouchstart=t=>r(a,a,w,i,t)),a.classList.add(window.data.class.initial),o(a,"setup"),t(["mouseup","touchend"],u)}const h=(a,t)=>{p(a,t)},f=(a,t)=>{a.onmousedown=null,a.ontouchstart=null;const n="object"==typeof t.oldValue?t.oldValue.handle:t.oldValue;document.querySelectorAll(n).forEach(t=>{t.onmousedown=null,t.ontouchstart=null,t.classList.remove(window.data.class.handle),a.classList.remove(window.data.class.usesHandle)}),t.oldValue&&Object.keys(t.oldValue).forEach(t=>{o(a,"update-"+t)}),p(a,t)};var g={install(a,t){window.data={},window.data.class={initial:"drag-draggable",usesHandle:"drag-uses-handle",handle:"drag-handle",down:"drag-down",move:"drag-move"};let n=!0;if(t){if(t.eventClass){const a=t.eventClass;Object.keys(a).forEach(t=>{a[t]&&(window.data.class[t]=a[t])})}"boolean"==typeof t.removeTransition&&(n=t.removeTransition)}const o=document.createElement("style");o.innerHTML=`.${window.data.class.initial}{position:relative;}.${window.data.class.initial}:not(.${window.data.class.usesHandle}),.${window.data.class.handle}{cursor:move;cursor:grab;cursor:-webkit-grab;}.${window.data.class.handle}.${window.data.class.down},.${window.data.class.initial}:not(.${window.data.class.usesHandle}).${window.data.class.down}{z-index:999;cursor:grabbing;cursor:-webkit-grabbing;}`,o.innerHTML+=!0===n?`.${window.data.class.move}{transition:none;}`:"",document.body.appendChild(o),a.directive("drag",{mounted(a,t){h(a,t)},updated(a,t){f(a,t)},inserted(a,t){h(a,t)},update(a,t){f(a,t)}})}};export{g as default};
6 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * v-drag v3.0.9
3 | * by Nil Vila and contributors
4 | */
5 | "use strict";function a(a,t){const n="x"===t?window.data.snapX:window.data.snapY;return Math.round(a/n)*n}function t(a,t,n="add"){a.forEach(a=>{document[n+"EventListener"](a,t,!1)})}function n(a,t,n){return`matrix(${a||"1, 0, 0, 1,"} ${t}, ${n})`}function o(a,t){a.dispatchEvent(new Event("v-drag-"+t))}function e(t,e){window.data.relativeX=window.data.mouseX*t,window.data.relativeY=window.data.mouseY*e,window.data.move.style.transform=n(window.data.matrix,window.data.matrixX+a(window.data.relativeX,"x"),window.data.matrixY+a(window.data.relativeY,"y")),o(window.data.move,"moving"),(window.getSelection?window.getSelection():document.selection).empty()}const d={x(){e(!0,!1)},y(){e(!1,!0)},all(){e(!0,!0)}};function i(){d[window.data.axis](window.data),window.data.posAnimation=requestAnimationFrame(i)}function s(){window.data.move.classList.add(window.data.class.move),window.data.posAnimation=requestAnimationFrame(i),t(["mousemove","touchmove"],s,"remove")}function w(a,t){let n=Number(window.getComputedStyle(window.data.move)[t].replace("px",""));if("none"!==a){const o=a.match(/[0-9.-]+/g);n+=Number(o[8-t.length])}return n}function l(a,t,n){window.data.move.style.transform=a,window.data.move.style.left=t,window.data.move.style.top=n}function c(a){a.preventDefault(),window.data.mouseX=(a.pageX||a.touches[0].pageX)-window.data.initialX,window.data.mouseY=(a.pageY||a.touches[0].pageY)-window.data.initialY,window.setTimeout(()=>{(a.clientY||a.touches[0].clientY)>.8*window.innerHeight&&(document.documentElement.scrollTop+=10),(a.clientY||a.touches[0].clientY)<.2*window.innerHeight&&(document.documentElement.scrollTop-=10),(a.clientX||a.touches[0].clientX)>.8*window.innerWidth&&(document.documentElement.scrollLeft+=10),(a.clientX||a.touches[0].clientX)<.2*window.innerWidth&&(document.documentElement.scrollLeft-=10)},100)}function r(a,e,d,i,r){r.preventDefault(),window.data.grab=a,window.data.move=e,window.data.axis=d,window.data.initialX=r.pageX||r.touches[0].pageX,window.data.initialY=r.pageY||r.touches[0].pageY,window.data.relativeX=0,window.data.relativeY=0,window.data.snapX=i.x,window.data.snapY=i.y;const u=window.getComputedStyle(window.data.move).transform;window.data.matrix="none"!==u&&u.match(/\d([^,]*,){4}/g);const m=w(u,"left"),v=w(u,"top");l(n(window.data.matrix,m,v),0,0),window.data.matrixX=m,window.data.matrixY=v,window.data.grab.classList.add(window.data.class.down),o(e,"down"),o(e,"start"),t(["mousemove","touchmove"],c),t(["mousemove","touchmove"],s)}function u(){window.data.grab&&window.data.move&&(cancelAnimationFrame(window.data.posAnimation),t(["mousemove","touchmove"],s,"remove"),l(window.data.matrix?n(window.data.matrix,0,0):"none",window.data.matrixX+a(window.data.relativeX,"x")+"px",window.data.matrixY+a(window.data.relativeY,"y")+"px"),window.data.grab.classList.remove(window.data.class.down),window.data.move.classList.remove(window.data.class.move),o(window.data.move,"end"),t(["mousemove","touchmove"],c,"remove"))}function m(a,t){const n="string"==typeof a?parseInt(a.replace(/px/g,""),10):a;return 0===n||Number.isNaN(n)||t&&void 0===n?1:n}function v(a){return!!["x","y","all"].includes(a)}function p(a,n){const e=n.value||{},d=e instanceof Object?e.handle:e,i=function(a){if("string"==typeof a){const t=a.split(",");return{x:m(t[0]),y:void 0!==m(t[1])?m(t[1]):m(t[0])}}return"number"==typeof a?{x:m(a),y:m(a)}:a instanceof Object&&(a.x||a.y)?{x:m(a.x)||1,y:m(a.y)||1}:Array.isArray(a)?{x:m(a[0])||1,y:void 0!==m(a[1])?m(a[1],!0):m(a[0],!0)}:{x:1,y:1}}(e.snap),s=[];let w;w=e instanceof Object&&e.axis&&v(e.axis)?e.axis:v(n.arg)?n.arg:"all",d instanceof HTMLElement?s.push(d):document.querySelectorAll(d).forEach(a=>{s.push(a)}),0!==s.length?(a.classList.add(window.data.class.usesHandle),s.forEach(t=>{t.classList.add(window.data.class.handle),t.onmousedown=n=>r(t,a,w,i,n),t.ontouchstart=n=>r(t,a,w,i,n)})):(a.onmousedown=t=>r(a,a,w,i,t),a.ontouchstart=t=>r(a,a,w,i,t)),a.classList.add(window.data.class.initial),o(a,"setup"),t(["mouseup","touchend"],u)}const h=(a,t)=>{p(a,t)},f=(a,t)=>{a.onmousedown=null,a.ontouchstart=null;const n="object"==typeof t.oldValue?t.oldValue.handle:t.oldValue;document.querySelectorAll(n).forEach(t=>{t.onmousedown=null,t.ontouchstart=null,t.classList.remove(window.data.class.handle),a.classList.remove(window.data.class.usesHandle)}),t.oldValue&&Object.keys(t.oldValue).forEach(t=>{o(a,"update-"+t)}),p(a,t)};var g={install(a,t){window.data={},window.data.class={initial:"drag-draggable",usesHandle:"drag-uses-handle",handle:"drag-handle",down:"drag-down",move:"drag-move"};let n=!0;if(t){if(t.eventClass){const a=t.eventClass;Object.keys(a).forEach(t=>{a[t]&&(window.data.class[t]=a[t])})}"boolean"==typeof t.removeTransition&&(n=t.removeTransition)}const o=document.createElement("style");o.innerHTML=`.${window.data.class.initial}{position:relative;}.${window.data.class.initial}:not(.${window.data.class.usesHandle}),.${window.data.class.handle}{cursor:move;cursor:grab;cursor:-webkit-grab;}.${window.data.class.handle}.${window.data.class.down},.${window.data.class.initial}:not(.${window.data.class.usesHandle}).${window.data.class.down}{z-index:999;cursor:grabbing;cursor:-webkit-grabbing;}`,o.innerHTML+=!0===n?`.${window.data.class.move}{transition:none;}`:"",document.body.appendChild(o),a.directive("drag",{mounted(a,t){h(a,t)},updated(a,t){f(a,t)},inserted(a,t){h(a,t)},update(a,t){f(a,t)}})}};module.exports=g;
6 |
--------------------------------------------------------------------------------
/dist/browser.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * v-drag v3.0.9
3 | * by Nil Vila and contributors
4 | */
5 | var vdrag=function(){"use strict";function a(a,t){const n="x"===t?window.data.snapX:window.data.snapY;return Math.round(a/n)*n}function t(a,t,n="add"){a.forEach(a=>{document[n+"EventListener"](a,t,!1)})}function n(a,t,n){return`matrix(${a||"1, 0, 0, 1,"} ${t}, ${n})`}function o(a,t){a.dispatchEvent(new Event("v-drag-"+t))}function e(t,e){window.data.relativeX=window.data.mouseX*t,window.data.relativeY=window.data.mouseY*e,window.data.move.style.transform=n(window.data.matrix,window.data.matrixX+a(window.data.relativeX,"x"),window.data.matrixY+a(window.data.relativeY,"y")),o(window.data.move,"moving"),(window.getSelection?window.getSelection():document.selection).empty()}const d={x(){e(!0,!1)},y(){e(!1,!0)},all(){e(!0,!0)}};function i(){d[window.data.axis](window.data),window.data.posAnimation=requestAnimationFrame(i)}function s(){window.data.move.classList.add(window.data.class.move),window.data.posAnimation=requestAnimationFrame(i),t(["mousemove","touchmove"],s,"remove")}function w(a,t){let n=Number(window.getComputedStyle(window.data.move)[t].replace("px",""));if("none"!==a){const o=a.match(/[0-9.-]+/g);n+=Number(o[8-t.length])}return n}function l(a,t,n){window.data.move.style.transform=a,window.data.move.style.left=t,window.data.move.style.top=n}function c(a){a.preventDefault(),window.data.mouseX=(a.pageX||a.touches[0].pageX)-window.data.initialX,window.data.mouseY=(a.pageY||a.touches[0].pageY)-window.data.initialY,window.setTimeout(()=>{(a.clientY||a.touches[0].clientY)>.8*window.innerHeight&&(document.documentElement.scrollTop+=10),(a.clientY||a.touches[0].clientY)<.2*window.innerHeight&&(document.documentElement.scrollTop-=10),(a.clientX||a.touches[0].clientX)>.8*window.innerWidth&&(document.documentElement.scrollLeft+=10),(a.clientX||a.touches[0].clientX)<.2*window.innerWidth&&(document.documentElement.scrollLeft-=10)},100)}function r(a,e,d,i,r){r.preventDefault(),window.data.grab=a,window.data.move=e,window.data.axis=d,window.data.initialX=r.pageX||r.touches[0].pageX,window.data.initialY=r.pageY||r.touches[0].pageY,window.data.relativeX=0,window.data.relativeY=0,window.data.snapX=i.x,window.data.snapY=i.y;const u=window.getComputedStyle(window.data.move).transform;window.data.matrix="none"!==u&&u.match(/\d([^,]*,){4}/g);const m=w(u,"left"),v=w(u,"top");l(n(window.data.matrix,m,v),0,0),window.data.matrixX=m,window.data.matrixY=v,window.data.grab.classList.add(window.data.class.down),o(e,"down"),o(e,"start"),t(["mousemove","touchmove"],c),t(["mousemove","touchmove"],s)}function u(){window.data.grab&&window.data.move&&(cancelAnimationFrame(window.data.posAnimation),t(["mousemove","touchmove"],s,"remove"),l(window.data.matrix?n(window.data.matrix,0,0):"none",window.data.matrixX+a(window.data.relativeX,"x")+"px",window.data.matrixY+a(window.data.relativeY,"y")+"px"),window.data.grab.classList.remove(window.data.class.down),window.data.move.classList.remove(window.data.class.move),o(window.data.move,"end"),t(["mousemove","touchmove"],c,"remove"))}function m(a,t){const n="string"==typeof a?parseInt(a.replace(/px/g,""),10):a;return 0===n||Number.isNaN(n)||t&&void 0===n?1:n}function v(a){return!!["x","y","all"].includes(a)}function p(a,n){const e=n.value||{},d=e instanceof Object?e.handle:e,i=function(a){if("string"==typeof a){const t=a.split(",");return{x:m(t[0]),y:void 0!==m(t[1])?m(t[1]):m(t[0])}}return"number"==typeof a?{x:m(a),y:m(a)}:a instanceof Object&&(a.x||a.y)?{x:m(a.x)||1,y:m(a.y)||1}:Array.isArray(a)?{x:m(a[0])||1,y:void 0!==m(a[1])?m(a[1],!0):m(a[0],!0)}:{x:1,y:1}}(e.snap),s=[];let w;w=e instanceof Object&&e.axis&&v(e.axis)?e.axis:v(n.arg)?n.arg:"all",d instanceof HTMLElement?s.push(d):document.querySelectorAll(d).forEach(a=>{s.push(a)}),0!==s.length?(a.classList.add(window.data.class.usesHandle),s.forEach(t=>{t.classList.add(window.data.class.handle),t.onmousedown=n=>r(t,a,w,i,n),t.ontouchstart=n=>r(t,a,w,i,n)})):(a.onmousedown=t=>r(a,a,w,i,t),a.ontouchstart=t=>r(a,a,w,i,t)),a.classList.add(window.data.class.initial),o(a,"setup"),t(["mouseup","touchend"],u)}const h=(a,t)=>{p(a,t)},f=(a,t)=>{a.onmousedown=null,a.ontouchstart=null;const n="object"==typeof t.oldValue?t.oldValue.handle:t.oldValue;document.querySelectorAll(n).forEach(t=>{t.onmousedown=null,t.ontouchstart=null,t.classList.remove(window.data.class.handle),a.classList.remove(window.data.class.usesHandle)}),t.oldValue&&Object.keys(t.oldValue).forEach(t=>{o(a,"update-"+t)}),p(a,t)};return{install(a,t){window.data={},window.data.class={initial:"drag-draggable",usesHandle:"drag-uses-handle",handle:"drag-handle",down:"drag-down",move:"drag-move"};let n=!0;if(t){if(t.eventClass){const a=t.eventClass;Object.keys(a).forEach(t=>{a[t]&&(window.data.class[t]=a[t])})}"boolean"==typeof t.removeTransition&&(n=t.removeTransition)}const o=document.createElement("style");o.innerHTML=`.${window.data.class.initial}{position:relative;}.${window.data.class.initial}:not(.${window.data.class.usesHandle}),.${window.data.class.handle}{cursor:move;cursor:grab;cursor:-webkit-grab;}.${window.data.class.handle}.${window.data.class.down},.${window.data.class.initial}:not(.${window.data.class.usesHandle}).${window.data.class.down}{z-index:999;cursor:grabbing;cursor:-webkit-grabbing;}`,o.innerHTML+=!0===n?`.${window.data.class.move}{transition:none;}`:"",document.body.appendChild(o),a.directive("drag",{mounted(a,t){h(a,t)},updated(a,t){f(a,t)},inserted(a,t){h(a,t)},update(a,t){f(a,t)}})}}}();
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # v-drag
2 |
3 | The simplest way to integrate drag on Vue.js.
4 |
5 | Draggable elements are a common UX pattern, specially on touch screens. But as a developer, you might know how challenging it is to apply it with JavaScript. So to simplify things, v-drag was written. Its aim is to quickly integrate and customize draggable elements on projects using Vue.js.
6 |
7 | [](https://github.com/nil/v-drag/actions/workflows/build.yml)
8 | [](https://github.com/nil/v-drag/actions/workflows/npm-publish.yml)
9 | [](https://www.npmjs.com/package/v-drag)
10 | [](https://github.com/nil/v-drag/blob/master/LICENSE)
11 |
12 | ## Table of contents
13 |
14 | 1. [Installation](#installation)
15 | 2. [Usage](#usage)
16 | 3. [Options](#options)
17 | 1. [Axis](#axis)
18 | 2. [Snap](#snap)
19 | 3. [Handle](#handle)
20 | 4. [Vue events](#vue-events)
21 | 5. [Global configuration](#global-configuration)
22 | 1. [Event classes](#event-classes)
23 | 2. [Remove transitions](#remove-transitions)
24 |
25 | ## Installation
26 |
27 | ```sh
28 | npm install v-drag --save
29 | ```
30 |
31 | v-drag’s source code is also available [uncompressed](https://raw.githubusercontent.com/nil/v-drag/master/src/index.js) and [minified](https://raw.githubusercontent.com/nil/v-drag/master/src/index.min.js).
32 |
33 | ## Usage
34 |
35 | Import v-drag into any file you are planning to use it:
36 |
37 | ```js
38 | import drag from "v-drag"
39 | ```
40 |
41 | ```js
42 | const drag = require("v-drag");
43 | ```
44 |
45 | Then call the v-drag plugin:
46 |
47 | ```js
48 | Vue.use(drag, {
49 | // global configuration
50 | });
51 | ```
52 |
53 | No extra setup is necessary at this point. Add the `v-drag` attribute to any element to make it draggable:
54 |
55 | ```html
56 |
Drag me!
57 | ```
58 |
59 | ## Options
60 |
61 | The default behavior for any element with the `v-drag` attribute is to be draggable in any direction and without a handle. However, this can be changed using an object or its equivalent shortcuts:
62 |
63 | ```html
64 |
65 |
Handle
66 |
67 | ```
68 |
69 | Both the object and the values can be declared inline, as in the example above, or using the `data` object, computed properties, methods, props,…
70 |
71 | ### Axis
72 |
73 | Constrains the element to move only in one direction: horizontal or vertical.
74 |
75 | **Values**
76 |
77 | - `all`: all directions `default`
78 | - `x`: horizontal movement
79 | - `y`: vertical movement
80 |
81 | **Shortcut**
82 |
83 | ```html
84 |
Horizontal
85 | ```
86 |
87 | ### Snap
88 |
89 | When dragging, the element will snap to the specified grid. You can use either a number or a string with units.
90 |
91 | ```html
92 |
Drag me in 100px increments
93 | ```
94 |
95 | Using an array, different values can be declared for each axis:
96 |
97 | ```html
98 |
99 | Horizontal: 10px
100 | Vertical: 50px
101 |
102 | ```
103 |
104 | ### Handle
105 |
106 | Informs that the element can only be dragged using another element, known as handle. It’s not necessary for the handle to be located inside the draggable element, and each element can have more than one handle.
107 |
108 | **Values**
109 |
110 | Handle’s name must be a selector (the same used to refer to the element in CSS) or a Ref.
111 |
112 | **Shortcut**
113 |
114 | ```html
115 |
Don’t drag me
116 |
Drag me
117 | ```
118 |
119 | **Ref**
120 |
121 | To define handles using Refs, you must first set its value in `data` and replace it after the component is mounted:
122 |
123 | ```html
124 |
125 |
126 | Drag me using handle
127 |
Handle
128 |
129 |
130 |
131 |
146 | ```
147 |
148 | ## Vue events
149 |
150 | These events are emitted when the user makes the corresponding action.
151 |
152 | ```html
153 |