@maas/vue-equipment 0.26.5 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composables/index.d.mts +19 -18
- package/dist/composables/index.d.ts +19 -18
- package/dist/composables/index.js +20 -18
- package/dist/composables/index.js.map +1 -1
- package/dist/composables/index.mjs +38 -19
- package/dist/composables/index.mjs.map +1 -1
- package/dist/nuxt/module.json +1 -1
- package/dist/nuxt/module.mjs +9 -2
- package/dist/plugins/MagicCommand/nuxt.d.ts +2 -0
- package/dist/plugins/MagicCommand/src/components/MagicCommandBody.vue +4 -4
- package/dist/plugins/MagicCommand/src/components/MagicCommandBody.vue.d.ts +1 -0
- package/dist/plugins/MagicCookie/nuxt.d.ts +2 -0
- package/dist/plugins/MagicDraggable/index.d.ts +5 -0
- package/dist/plugins/MagicDraggable/index.mjs +8 -0
- package/dist/plugins/MagicDraggable/nuxt.d.ts +2 -0
- package/dist/plugins/MagicDraggable/nuxt.mjs +23 -0
- package/dist/plugins/MagicDraggable/src/components/MagicDraggable.vue +108 -0
- package/dist/plugins/MagicDraggable/src/components/MagicDraggable.vue.d.ts +41 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableDrag.d.ts +18 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableDrag.mjs +307 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableSnap.d.ts +34 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableSnap.mjs +143 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableState.d.ts +108 -0
- package/dist/plugins/MagicDraggable/src/composables/private/useDraggableState.mjs +46 -0
- package/dist/plugins/MagicDraggable/src/composables/useDraggableApi.d.ts +1 -0
- package/dist/plugins/MagicDraggable/src/composables/useDraggableApi.mjs +2 -0
- package/dist/plugins/MagicDraggable/src/types/index.d.ts +48 -0
- package/dist/plugins/MagicDraggable/src/types/index.mjs +0 -0
- package/dist/plugins/MagicDraggable/src/utils/defaultOptions.d.ts +5 -0
- package/dist/plugins/MagicDraggable/src/utils/defaultOptions.mjs +21 -0
- package/dist/plugins/MagicDrawer/nuxt.d.ts +2 -0
- package/dist/plugins/MagicDrawer/src/components/MagicDrawer.vue +30 -19
- package/dist/plugins/MagicDrawer/src/components/MagicDrawer.vue.d.ts +1 -1
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerDrag.d.ts +4 -2
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerDrag.mjs +15 -14
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.d.ts +4 -2
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.mjs +13 -11
- package/dist/plugins/MagicDrawer/src/types/index.d.ts +21 -15
- package/dist/plugins/MagicDrawer/src/utils/defaultOptions.d.ts +4 -1
- package/dist/plugins/MagicDrawer/src/utils/defaultOptions.mjs +17 -14
- package/dist/plugins/MagicMarquee/nuxt.d.ts +2 -0
- package/dist/plugins/MagicModal/nuxt.d.ts +2 -0
- package/dist/plugins/MagicModal/src/components/MagicModal.vue +8 -5
- package/dist/plugins/MagicModal/src/types/index.d.ts +8 -5
- package/dist/plugins/MagicModal/src/utils/defaultOptions.mjs +6 -5
- package/dist/plugins/MagicNoise/nuxt.d.ts +2 -0
- package/dist/plugins/MagicPlayer/nuxt.d.ts +2 -0
- package/dist/plugins/MagicScroll/nuxt.d.ts +2 -0
- package/dist/plugins/MagicToast/nuxt.d.ts +2 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.mjs +1 -0
- package/dist/utils/index.d.mts +16 -1
- package/dist/utils/index.d.ts +16 -1
- package/dist/utils/index.js +72 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +58 -0
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +16 -4
- package/dist/plugins/MagicCommand/demo/DefaultView.vue +0 -84
- package/dist/plugins/MagicCommand/demo/DefaultView.vue.d.ts +0 -16
- package/dist/plugins/MagicCommand/demo/DemoItem.vue +0 -18
- package/dist/plugins/MagicCommand/demo/DemoItem.vue.d.ts +0 -21
- package/dist/plugins/MagicCommand/demo/ProjectView.vue +0 -63
- package/dist/plugins/MagicCommand/demo/ProjectView.vue.d.ts +0 -14
- package/dist/plugins/MagicToast/demo/DemoToast.vue +0 -22
- package/dist/plugins/MagicToast/demo/DemoToast.vue.d.ts +0 -18
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import MagicDraggable from "./src/components/MagicDraggable.vue";
|
|
2
|
+
import { useDraggableApi } from "./src/composables/useDraggableApi.mjs";
|
|
3
|
+
const MagicDraggablePlugin = {
|
|
4
|
+
install: (app) => {
|
|
5
|
+
app.component("MagicDraggable", MagicDraggable);
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export { MagicDraggablePlugin, MagicDraggable, useDraggableApi };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineNuxtModule,
|
|
3
|
+
createResolver,
|
|
4
|
+
addComponent,
|
|
5
|
+
addImports
|
|
6
|
+
} from "@nuxt/kit";
|
|
7
|
+
export default defineNuxtModule({
|
|
8
|
+
meta: {
|
|
9
|
+
name: "@maas/vue-equipment/nuxt/MagicDraggable"
|
|
10
|
+
},
|
|
11
|
+
setup() {
|
|
12
|
+
const resolver = createResolver(import.meta.url);
|
|
13
|
+
addComponent({
|
|
14
|
+
filePath: resolver.resolve("src/components/MagicDraggable.vue"),
|
|
15
|
+
name: "MagicDraggable",
|
|
16
|
+
global: true
|
|
17
|
+
});
|
|
18
|
+
addImports({
|
|
19
|
+
from: "@maas/vue-equipment/plugins/MagicDraggable",
|
|
20
|
+
name: "useDraggableApi"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="drawerRef"
|
|
4
|
+
class="magic-draggable"
|
|
5
|
+
:id="toValue(id)"
|
|
6
|
+
:class="[
|
|
7
|
+
toValue(props.class),
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
'-dragging': dragging,
|
|
11
|
+
'-disabled': disabled,
|
|
12
|
+
},
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<div class="magic-draggable__wrapper" ref="wrapperRef">
|
|
16
|
+
<component
|
|
17
|
+
:is="mappedOptions.tag"
|
|
18
|
+
ref="elRef"
|
|
19
|
+
class="magic-draggable__drag"
|
|
20
|
+
:style="style"
|
|
21
|
+
@pointerdown="guardedPointerdown"
|
|
22
|
+
@click="guardedClick"
|
|
23
|
+
>
|
|
24
|
+
<component v-if="component" v-bind="props" :is="component" />
|
|
25
|
+
<slot v-else />
|
|
26
|
+
</component>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script lang="ts" setup>
|
|
32
|
+
import {
|
|
33
|
+
ref,
|
|
34
|
+
computed,
|
|
35
|
+
toValue,
|
|
36
|
+
onMounted,
|
|
37
|
+
type Component,
|
|
38
|
+
type MaybeRef,
|
|
39
|
+
} from 'vue'
|
|
40
|
+
import { defu } from 'defu'
|
|
41
|
+
import { useDraggableDrag } from '../composables/private/useDraggableDrag'
|
|
42
|
+
import { useDraggableState } from '../composables/private/useDraggableState'
|
|
43
|
+
import { defaultOptions } from '../utils/defaultOptions'
|
|
44
|
+
|
|
45
|
+
import type { DraggableOptions } from '../types'
|
|
46
|
+
|
|
47
|
+
interface MagicDrawerProps {
|
|
48
|
+
id: MaybeRef<string>
|
|
49
|
+
class?: MaybeRef<string>
|
|
50
|
+
component?: Component
|
|
51
|
+
props?: Record<string, unknown>
|
|
52
|
+
options?: DraggableOptions
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const props = withDefaults(defineProps<MagicDrawerProps>(), {
|
|
56
|
+
options: () => defaultOptions,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const mappedOptions = defu(props.options, defaultOptions)
|
|
60
|
+
|
|
61
|
+
const elRef = ref<HTMLElement | undefined>(undefined)
|
|
62
|
+
const wrapperRef = ref<HTMLDivElement | undefined>(undefined)
|
|
63
|
+
|
|
64
|
+
const { findState } = useDraggableState(props.id)
|
|
65
|
+
const { dragging } = findState()
|
|
66
|
+
|
|
67
|
+
// Make sure this is reactive
|
|
68
|
+
const disabled = computed(() => {
|
|
69
|
+
if (props.options.disabled === undefined) {
|
|
70
|
+
return defaultOptions.disabled
|
|
71
|
+
} else {
|
|
72
|
+
return props.options.disabled
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const { snapPoints, animation, initial, threshold } = mappedOptions
|
|
77
|
+
|
|
78
|
+
const { initialize, onPointerdown, onClick, style } = useDraggableDrag({
|
|
79
|
+
id: props.id,
|
|
80
|
+
elRef,
|
|
81
|
+
wrapperRef,
|
|
82
|
+
threshold,
|
|
83
|
+
snapPoints,
|
|
84
|
+
animation,
|
|
85
|
+
initial,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Public functions
|
|
89
|
+
function guardedPointerdown(event: PointerEvent) {
|
|
90
|
+
if (!disabled.value) {
|
|
91
|
+
onPointerdown(event)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function guardedClick(event: PointerEvent) {
|
|
96
|
+
if (!disabled.value) {
|
|
97
|
+
onClick(event)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
onMounted(() => {
|
|
102
|
+
initialize()
|
|
103
|
+
})
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
:root{--magic-draggable-z-index:999;--magic-draggable-position:fixed;--magic-draggable-height:100%;--magic-draggable-width:100%;--magic-draggable-inset:0}.magic-draggable{background:transparent;border:none;color:inherit;height:var(--magic-draggable-height);inset:var(--magic-draggable-inset);padding:0;position:var(--magic-draggable-position);width:var(--magic-draggable-width);z-index:var(--magic-draggable-z-index)}.magic-draggable,.magic-draggable.-disabled{pointer-events:none}.magic-draggable__wrapper{display:block;height:100%;width:100%}.magic-draggable__drag{cursor:grab;display:inline-flex;height:auto;pointer-events:auto;position:relative;transform-origin:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:auto}.magic-draggable.-dragging .magic-draggable__drag{cursor:grabbing;-webkit-user-select:none;-moz-user-select:none;user-select:none}.magic-draggable.-disabled .magic-draggable__drag{cursor:default}
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Component, type MaybeRef } from 'vue';
|
|
2
|
+
import type { DraggableOptions } from '../types';
|
|
3
|
+
interface MagicDrawerProps {
|
|
4
|
+
id: MaybeRef<string>;
|
|
5
|
+
class?: MaybeRef<string>;
|
|
6
|
+
component?: Component;
|
|
7
|
+
props?: Record<string, unknown>;
|
|
8
|
+
options?: DraggableOptions;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<MagicDrawerProps>, {
|
|
11
|
+
options: () => DraggableOptions;
|
|
12
|
+
}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<MagicDrawerProps>, {
|
|
13
|
+
options: () => DraggableOptions;
|
|
14
|
+
}>>>, {
|
|
15
|
+
options: DraggableOptions;
|
|
16
|
+
}, {}>, {
|
|
17
|
+
default?(_: {}): any;
|
|
18
|
+
}>;
|
|
19
|
+
export default _default;
|
|
20
|
+
type __VLS_WithDefaults<P, D> = {
|
|
21
|
+
[K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
|
|
22
|
+
default: D[K];
|
|
23
|
+
}> : P[K];
|
|
24
|
+
};
|
|
25
|
+
type __VLS_Prettify<T> = {
|
|
26
|
+
[K in keyof T]: T[K];
|
|
27
|
+
} & {};
|
|
28
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
29
|
+
new (): {
|
|
30
|
+
$slots: S;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
34
|
+
type __VLS_TypePropsToOption<T> = {
|
|
35
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
36
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
37
|
+
} : {
|
|
38
|
+
type: import('vue').PropType<T[K]>;
|
|
39
|
+
required: true;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Ref, type MaybeRef } from 'vue';
|
|
2
|
+
import { type DefaultOptions } from '../../utils/defaultOptions.js';
|
|
3
|
+
type UseDraggableDragArgs = {
|
|
4
|
+
id: MaybeRef<string>;
|
|
5
|
+
elRef: Ref<HTMLElement | undefined>;
|
|
6
|
+
wrapperRef: Ref<HTMLDivElement | undefined>;
|
|
7
|
+
threshold: MaybeRef<DefaultOptions['threshold']>;
|
|
8
|
+
snapPoints: MaybeRef<DefaultOptions['snapPoints']>;
|
|
9
|
+
animation: MaybeRef<DefaultOptions['animation']>;
|
|
10
|
+
initial: MaybeRef<DefaultOptions['initial']>;
|
|
11
|
+
};
|
|
12
|
+
export declare function useDraggableDrag(args: UseDraggableDragArgs): {
|
|
13
|
+
initialize: () => Promise<void>;
|
|
14
|
+
onPointerdown: (e: PointerEvent) => void;
|
|
15
|
+
onClick: (e: MouseEvent) => void;
|
|
16
|
+
style: import("vue").ComputedRef<string>;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ref,
|
|
3
|
+
computed,
|
|
4
|
+
toValue,
|
|
5
|
+
nextTick,
|
|
6
|
+
watch
|
|
7
|
+
} from "vue";
|
|
8
|
+
import {
|
|
9
|
+
useEventListener,
|
|
10
|
+
unrefElement,
|
|
11
|
+
useResizeObserver,
|
|
12
|
+
useThrottleFn,
|
|
13
|
+
useIdle
|
|
14
|
+
} from "@vueuse/core";
|
|
15
|
+
import { useDraggableSnap } from "./useDraggableSnap.mjs";
|
|
16
|
+
import { useDraggableState } from "./useDraggableState.mjs";
|
|
17
|
+
import { isIOS } from "@maas/vue-equipment/utils";
|
|
18
|
+
export function useDraggableDrag(args) {
|
|
19
|
+
const { id, elRef, wrapperRef, threshold, snapPoints, initial, animation } = args;
|
|
20
|
+
const { findState } = useDraggableState(toValue(id));
|
|
21
|
+
const {
|
|
22
|
+
dragStart,
|
|
23
|
+
dragging,
|
|
24
|
+
interpolateTo,
|
|
25
|
+
originX,
|
|
26
|
+
originY,
|
|
27
|
+
lastDraggedX,
|
|
28
|
+
lastDraggedY,
|
|
29
|
+
intermediateDraggedX,
|
|
30
|
+
intermediateDraggedY,
|
|
31
|
+
draggedX,
|
|
32
|
+
draggedY,
|
|
33
|
+
elRect,
|
|
34
|
+
wrapperRect
|
|
35
|
+
} = findState();
|
|
36
|
+
let cancelPointerup = void 0;
|
|
37
|
+
let cancelPointermove = void 0;
|
|
38
|
+
let cancelTouchend = void 0;
|
|
39
|
+
const momentumThresholdReached = ref(false);
|
|
40
|
+
const distanceThresholdReached = ref(false);
|
|
41
|
+
const style = computed(
|
|
42
|
+
() => `transform: translate3d(${draggedX.value}px, ${draggedY.value}px, 0)`
|
|
43
|
+
);
|
|
44
|
+
const {
|
|
45
|
+
snapTo,
|
|
46
|
+
activeSnapPoint,
|
|
47
|
+
mapSnapPoint,
|
|
48
|
+
mappedSnapPoints,
|
|
49
|
+
snapPointsMap,
|
|
50
|
+
interpolateDragged
|
|
51
|
+
} = useDraggableSnap({
|
|
52
|
+
elRect,
|
|
53
|
+
wrapperRect,
|
|
54
|
+
animation,
|
|
55
|
+
snapPoints,
|
|
56
|
+
draggedY,
|
|
57
|
+
draggedX
|
|
58
|
+
});
|
|
59
|
+
async function getSizes() {
|
|
60
|
+
elRect.value = unrefElement(elRef)?.getBoundingClientRect();
|
|
61
|
+
wrapperRect.value = unrefElement(wrapperRef)?.getBoundingClientRect();
|
|
62
|
+
await nextTick();
|
|
63
|
+
}
|
|
64
|
+
function setDragged({ x, y }) {
|
|
65
|
+
draggedX.value = x - originX.value;
|
|
66
|
+
draggedY.value = y - originY.value;
|
|
67
|
+
}
|
|
68
|
+
function resetStateAndListeners() {
|
|
69
|
+
dragging.value = false;
|
|
70
|
+
interpolateTo.value = void 0;
|
|
71
|
+
momentumThresholdReached.value = false;
|
|
72
|
+
distanceThresholdReached.value = false;
|
|
73
|
+
cancelTouchend?.();
|
|
74
|
+
cancelPointerup?.();
|
|
75
|
+
cancelPointermove?.();
|
|
76
|
+
}
|
|
77
|
+
function detectCollision() {
|
|
78
|
+
const childRect = toValue(elRect);
|
|
79
|
+
const parentRect = toValue(wrapperRect);
|
|
80
|
+
if (!childRect || !parentRect) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (childRect.width > parentRect.width || childRect.height > parentRect.height) {
|
|
84
|
+
console.warn("MagicDraggable is too small for its content");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
interpolateTo.value = { x: draggedX.value, y: draggedY.value };
|
|
88
|
+
if (childRect.top < parentRect.top) {
|
|
89
|
+
interpolateTo.value = { x: interpolateTo.value?.x, y: 0 };
|
|
90
|
+
} else if (childRect.bottom > parentRect.bottom) {
|
|
91
|
+
interpolateTo.value = {
|
|
92
|
+
x: interpolateTo.value?.x,
|
|
93
|
+
y: parentRect.height - childRect.height
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (childRect.left < parentRect.left) {
|
|
97
|
+
interpolateTo.value = { x: 0, y: interpolateTo.value?.y };
|
|
98
|
+
} else if (childRect.right > parentRect.right) {
|
|
99
|
+
interpolateTo.value = {
|
|
100
|
+
x: parentRect.width - childRect.width,
|
|
101
|
+
y: interpolateTo.value?.y
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function vectorBetweenCoordinates(a, b) {
|
|
106
|
+
const dx = b.x - a.x;
|
|
107
|
+
const dy = b.y - a.y;
|
|
108
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
109
|
+
if (length === 0) {
|
|
110
|
+
return { x: 0, y: 0 };
|
|
111
|
+
} else {
|
|
112
|
+
return { x: dx / length, y: dy / length };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function dotProduct(vectorA, vectorB) {
|
|
116
|
+
return vectorA.x * vectorB.x + vectorA.y * vectorB.y;
|
|
117
|
+
}
|
|
118
|
+
function calculateDistance(a, b) {
|
|
119
|
+
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
|
|
120
|
+
}
|
|
121
|
+
function checkDistance() {
|
|
122
|
+
if (toValue(threshold).distance) {
|
|
123
|
+
const intermediateDraggedCoords = {
|
|
124
|
+
x: intermediateDraggedX.value,
|
|
125
|
+
y: intermediateDraggedY.value
|
|
126
|
+
};
|
|
127
|
+
const draggedCoords = { x: draggedX.value, y: draggedY.value };
|
|
128
|
+
const draggedDistance = calculateDistance(
|
|
129
|
+
intermediateDraggedCoords,
|
|
130
|
+
draggedCoords
|
|
131
|
+
);
|
|
132
|
+
if (draggedDistance < toValue(threshold).distance) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
distanceThresholdReached.value = true;
|
|
137
|
+
}
|
|
138
|
+
function checkMomentum() {
|
|
139
|
+
if (dragStart.value && toValue(threshold).momentum) {
|
|
140
|
+
const intermediateDraggedCoords = {
|
|
141
|
+
x: intermediateDraggedX.value,
|
|
142
|
+
y: intermediateDraggedY.value
|
|
143
|
+
};
|
|
144
|
+
const draggedCoords = { x: draggedX.value, y: draggedY.value };
|
|
145
|
+
const draggedDistance = calculateDistance(
|
|
146
|
+
intermediateDraggedCoords,
|
|
147
|
+
draggedCoords
|
|
148
|
+
);
|
|
149
|
+
const dragTime = (/* @__PURE__ */ new Date()).getTime() - dragStart.value.getTime();
|
|
150
|
+
if (dragTime === 0) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const dragSpeed = draggedDistance / dragTime;
|
|
154
|
+
if (dragSpeed < toValue(threshold).momentum) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
momentumThresholdReached.value = true;
|
|
159
|
+
}
|
|
160
|
+
function compareDistances(a, b) {
|
|
161
|
+
const draggedCoords = { x: draggedX.value, y: draggedY.value };
|
|
162
|
+
const distanceA = calculateDistance(a, draggedCoords);
|
|
163
|
+
const distanceB = calculateDistance(b, draggedCoords);
|
|
164
|
+
return distanceA < distanceB ? a : b;
|
|
165
|
+
}
|
|
166
|
+
function findSnapPointByVector() {
|
|
167
|
+
let bestDotProduct = -Infinity;
|
|
168
|
+
const intermediateDraggedCoords = {
|
|
169
|
+
x: intermediateDraggedX.value,
|
|
170
|
+
y: intermediateDraggedY.value
|
|
171
|
+
};
|
|
172
|
+
const draggedCoords = { x: draggedX.value, y: draggedY.value };
|
|
173
|
+
const lineVector = vectorBetweenCoordinates(
|
|
174
|
+
intermediateDraggedCoords,
|
|
175
|
+
draggedCoords
|
|
176
|
+
);
|
|
177
|
+
for (let i = 0; i < mappedSnapPoints.value.length; i++) {
|
|
178
|
+
const snapPoint = mappedSnapPoints.value[i];
|
|
179
|
+
const targetVector = vectorBetweenCoordinates(
|
|
180
|
+
intermediateDraggedCoords,
|
|
181
|
+
snapPoint
|
|
182
|
+
);
|
|
183
|
+
const currentDotProduct = dotProduct(lineVector, targetVector);
|
|
184
|
+
if (currentDotProduct > bestDotProduct) {
|
|
185
|
+
bestDotProduct = currentDotProduct;
|
|
186
|
+
interpolateTo.value = snapPoint;
|
|
187
|
+
} else if (currentDotProduct === bestDotProduct) {
|
|
188
|
+
if (!interpolateTo.value) {
|
|
189
|
+
interpolateTo.value = snapPoint;
|
|
190
|
+
} else {
|
|
191
|
+
const smallerDistance = compareDistances(
|
|
192
|
+
snapPoint,
|
|
193
|
+
interpolateTo.value
|
|
194
|
+
);
|
|
195
|
+
interpolateTo.value = smallerDistance;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function findClosestSnapPoint() {
|
|
201
|
+
const draggedCoords = { x: draggedX.value, y: draggedY.value };
|
|
202
|
+
const closestSnapPoint = mappedSnapPoints.value.reduce((a, b) => {
|
|
203
|
+
return calculateDistance(a, draggedCoords) < calculateDistance(b, draggedCoords) ? a : b;
|
|
204
|
+
});
|
|
205
|
+
return closestSnapPoint;
|
|
206
|
+
}
|
|
207
|
+
function onPointerup(_e) {
|
|
208
|
+
if (!momentumThresholdReached.value && distanceThresholdReached.value) {
|
|
209
|
+
interpolateTo.value = findClosestSnapPoint();
|
|
210
|
+
}
|
|
211
|
+
const { x, y } = interpolateTo.value || {};
|
|
212
|
+
if (x !== void 0 && y !== void 0) {
|
|
213
|
+
interpolateDragged({ x, y });
|
|
214
|
+
}
|
|
215
|
+
if (interpolateTo.value) {
|
|
216
|
+
const key = `x${interpolateTo.value.x}y${interpolateTo.value.y}`;
|
|
217
|
+
activeSnapPoint.value = snapPointsMap.value[key];
|
|
218
|
+
}
|
|
219
|
+
resetStateAndListeners();
|
|
220
|
+
}
|
|
221
|
+
function onPointermove(e) {
|
|
222
|
+
setDragged({ x: e.screenX, y: e.screenY });
|
|
223
|
+
getSizes();
|
|
224
|
+
detectCollision();
|
|
225
|
+
if (!distanceThresholdReached.value) {
|
|
226
|
+
checkDistance();
|
|
227
|
+
}
|
|
228
|
+
if (!momentumThresholdReached.value) {
|
|
229
|
+
checkMomentum();
|
|
230
|
+
}
|
|
231
|
+
if (!distanceThresholdReached.value && !momentumThresholdReached.value) {
|
|
232
|
+
interpolateTo.value = { x: lastDraggedX.value, y: lastDraggedY.value };
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (toValue(snapPoints).length) {
|
|
236
|
+
findSnapPointByVector();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function onIdle() {
|
|
240
|
+
interpolateTo.value = findClosestSnapPoint();
|
|
241
|
+
if (distanceThresholdReached.value && momentumThresholdReached.value) {
|
|
242
|
+
intermediateDraggedX.value = draggedX.value;
|
|
243
|
+
intermediateDraggedY.value = draggedY.value;
|
|
244
|
+
distanceThresholdReached.value = false;
|
|
245
|
+
momentumThresholdReached.value = false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function onPointerdown(e) {
|
|
249
|
+
if (dragging.value) {
|
|
250
|
+
return;
|
|
251
|
+
} else {
|
|
252
|
+
dragging.value = true;
|
|
253
|
+
}
|
|
254
|
+
intermediateDraggedX.value = draggedX.value;
|
|
255
|
+
intermediateDraggedY.value = draggedY.value;
|
|
256
|
+
lastDraggedX.value = draggedX.value;
|
|
257
|
+
lastDraggedY.value = draggedY.value;
|
|
258
|
+
cancelPointerup = useEventListener(document, "pointerup", onPointerup);
|
|
259
|
+
cancelPointermove = useEventListener(document, "pointermove", onPointermove);
|
|
260
|
+
cancelTouchend = isIOS() ? useEventListener(document, "touchend", onPointerup) : void 0;
|
|
261
|
+
originX.value = e.screenX - draggedX.value;
|
|
262
|
+
originY.value = e.screenY - draggedY.value;
|
|
263
|
+
dragStart.value = /* @__PURE__ */ new Date();
|
|
264
|
+
onPointermove(e);
|
|
265
|
+
}
|
|
266
|
+
function onClick(e) {
|
|
267
|
+
e.preventDefault();
|
|
268
|
+
}
|
|
269
|
+
async function initialize() {
|
|
270
|
+
await getSizes();
|
|
271
|
+
if (elRect.value && wrapperRect.value) {
|
|
272
|
+
if (elRect.value.width > wrapperRect.value.width || elRect.value.height > wrapperRect.value.height) {
|
|
273
|
+
console.warn("MagicDraggable is too small for its content");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
await nextTick();
|
|
278
|
+
if (toValue(initial).snapPoint) {
|
|
279
|
+
const mappedSnapPoint = mapSnapPoint(toValue(initial).snapPoint);
|
|
280
|
+
if (mappedSnapPoint) {
|
|
281
|
+
draggedX.value = mappedSnapPoint.x;
|
|
282
|
+
draggedY.value = mappedSnapPoint.y;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
useResizeObserver(wrapperRef, async () => {
|
|
287
|
+
useThrottleFn(async () => {
|
|
288
|
+
await getSizes();
|
|
289
|
+
if (activeSnapPoint.value) {
|
|
290
|
+
await snapTo({ snapPoint: activeSnapPoint.value, interpolate: false });
|
|
291
|
+
snapPointsMap.trigger();
|
|
292
|
+
}
|
|
293
|
+
}, 100)();
|
|
294
|
+
});
|
|
295
|
+
const { idle } = useIdle(toValue(threshold).idle);
|
|
296
|
+
watch(idle, (value) => {
|
|
297
|
+
if (value && dragging.value) {
|
|
298
|
+
onIdle();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
return {
|
|
302
|
+
initialize,
|
|
303
|
+
onPointerdown,
|
|
304
|
+
onClick,
|
|
305
|
+
style
|
|
306
|
+
};
|
|
307
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type MaybeRef, type Ref } from 'vue';
|
|
2
|
+
import { type DefaultOptions } from '../../utils/defaultOptions.js';
|
|
3
|
+
import type { SnapPoint, Coordinates } from '../../types.js';
|
|
4
|
+
type UseDraggableSnapArgs = {
|
|
5
|
+
elRect: Ref<DOMRect | undefined>;
|
|
6
|
+
wrapperRect: Ref<DOMRect | undefined>;
|
|
7
|
+
draggedY: Ref<number>;
|
|
8
|
+
draggedX: Ref<number>;
|
|
9
|
+
animation: MaybeRef<DefaultOptions['animation']>;
|
|
10
|
+
snapPoints: MaybeRef<DefaultOptions['snapPoints']>;
|
|
11
|
+
};
|
|
12
|
+
type InterpolateDraggedArgs = {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
duration?: number;
|
|
16
|
+
easing?: (t: number) => number;
|
|
17
|
+
};
|
|
18
|
+
type SnapToArgs = {
|
|
19
|
+
snapPoint: SnapPoint;
|
|
20
|
+
interpolate?: boolean;
|
|
21
|
+
duration?: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function useDraggableSnap(args: UseDraggableSnapArgs): {
|
|
24
|
+
mappedSnapPoints: import("@vueuse/core").ComputedRefWithControl<Coordinates[]>;
|
|
25
|
+
activeSnapPoint: Ref<("center" | "top-center" | "bottom-center" | "top-left" | "top-right" | "center-left" | "center-right" | "bottom-left" | "bottom-right") | ["center" | "top-center" | "bottom-center" | "top-left" | "top-right" | "center-left" | "center-right" | "bottom-left" | "bottom-right", offset?: {
|
|
26
|
+
x?: number | undefined;
|
|
27
|
+
y?: number | undefined;
|
|
28
|
+
} | undefined] | undefined>;
|
|
29
|
+
snapPointsMap: import("@vueuse/core").ComputedRefWithControl<Record<string, SnapPoint>>;
|
|
30
|
+
mapSnapPoint: (snapPoint: SnapPoint) => Coordinates | undefined;
|
|
31
|
+
interpolateDragged: (args: InterpolateDraggedArgs) => void;
|
|
32
|
+
snapTo: (args: SnapToArgs) => Promise<void>;
|
|
33
|
+
};
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ref, toValue, nextTick } from "vue";
|
|
2
|
+
import { computedWithControl } from "@vueuse/core";
|
|
3
|
+
import { interpolate } from "@maas/vue-equipment/utils";
|
|
4
|
+
import { defu } from "defu";
|
|
5
|
+
export function useDraggableSnap(args) {
|
|
6
|
+
const { draggedY, draggedX, elRect, wrapperRect, animation, snapPoints } = args;
|
|
7
|
+
const activeSnapPoint = ref(void 0);
|
|
8
|
+
const mappedSnapPoints = computedWithControl(
|
|
9
|
+
() => toValue(wrapperRect),
|
|
10
|
+
() => {
|
|
11
|
+
const mapped = toValue(snapPoints).map((snapPoint) => {
|
|
12
|
+
return mapSnapPoint(snapPoint);
|
|
13
|
+
}).filter((snapPoint) => snapPoint !== void 0);
|
|
14
|
+
return mapped;
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
const snapPointsMap = computedWithControl(
|
|
18
|
+
() => toValue(snapPoints),
|
|
19
|
+
() => {
|
|
20
|
+
const mapped = toValue(snapPoints).reduce((acc, current) => {
|
|
21
|
+
const key = mapSnapPoint(current);
|
|
22
|
+
if (key) {
|
|
23
|
+
const mappedKey = `x${key.x}y${key.y}`;
|
|
24
|
+
acc[mappedKey] = current;
|
|
25
|
+
}
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
return mapped;
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
function mapSnapPoint(snapPoint) {
|
|
32
|
+
if (!wrapperRect.value) {
|
|
33
|
+
console.warn("Wrapper rect is not defined");
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
if (!elRect.value) {
|
|
37
|
+
console.warn("Element rect is not defined");
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
const mappedSnapPoint = typeof snapPoint === "string" ? [snapPoint] : snapPoint;
|
|
41
|
+
const [position, offset] = mappedSnapPoint;
|
|
42
|
+
const mappedOffset = defu(offset, { x: 0, y: 0 });
|
|
43
|
+
switch (position) {
|
|
44
|
+
case "top-left":
|
|
45
|
+
return {
|
|
46
|
+
x: mappedOffset.x,
|
|
47
|
+
y: mappedOffset.y
|
|
48
|
+
};
|
|
49
|
+
case "top-center":
|
|
50
|
+
return {
|
|
51
|
+
x: wrapperRect.value.width / 2 + mappedOffset.x - elRect.value.width / 2,
|
|
52
|
+
y: mappedOffset.y
|
|
53
|
+
};
|
|
54
|
+
case "top-right":
|
|
55
|
+
return {
|
|
56
|
+
x: wrapperRect.value.width - mappedOffset.x - elRect.value.width,
|
|
57
|
+
y: mappedOffset.y
|
|
58
|
+
};
|
|
59
|
+
case "center-left":
|
|
60
|
+
return {
|
|
61
|
+
x: mappedOffset.x,
|
|
62
|
+
y: wrapperRect.value.height / 2 + mappedOffset.y - elRect.value.height / 2
|
|
63
|
+
};
|
|
64
|
+
case "center":
|
|
65
|
+
return {
|
|
66
|
+
x: wrapperRect.value.width / 2 - elRect.value.width / 2 + mappedOffset.x,
|
|
67
|
+
y: wrapperRect.value.height / 2 - elRect.value.height / 2 + mappedOffset.y
|
|
68
|
+
};
|
|
69
|
+
case "center-right":
|
|
70
|
+
return {
|
|
71
|
+
x: wrapperRect.value.width - mappedOffset.x - elRect.value.width,
|
|
72
|
+
y: wrapperRect.value.height / 2 + mappedOffset.y - elRect.value.height / 2
|
|
73
|
+
};
|
|
74
|
+
case "bottom-left":
|
|
75
|
+
return {
|
|
76
|
+
x: mappedOffset.x,
|
|
77
|
+
y: wrapperRect.value.height + mappedOffset.y - elRect.value.height
|
|
78
|
+
};
|
|
79
|
+
case "bottom-center":
|
|
80
|
+
return {
|
|
81
|
+
x: wrapperRect.value.width / 2 + mappedOffset.x - elRect.value.width / 2,
|
|
82
|
+
y: wrapperRect.value.height - mappedOffset.y - elRect.value.height
|
|
83
|
+
};
|
|
84
|
+
case "bottom-right":
|
|
85
|
+
return {
|
|
86
|
+
x: wrapperRect.value.width - mappedOffset.x - elRect.value.width,
|
|
87
|
+
y: wrapperRect.value.height - mappedOffset.y - elRect.value.height
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function interpolateDragged(args2) {
|
|
92
|
+
const {
|
|
93
|
+
x,
|
|
94
|
+
y,
|
|
95
|
+
duration = toValue(animation).snap?.duration,
|
|
96
|
+
easing = toValue(animation).snap?.easing
|
|
97
|
+
} = args2;
|
|
98
|
+
interpolate({
|
|
99
|
+
from: draggedY.value,
|
|
100
|
+
to: y,
|
|
101
|
+
duration,
|
|
102
|
+
easing,
|
|
103
|
+
callback: (value) => {
|
|
104
|
+
draggedY.value = value;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
interpolate({
|
|
108
|
+
from: draggedX.value,
|
|
109
|
+
to: x,
|
|
110
|
+
duration,
|
|
111
|
+
easing,
|
|
112
|
+
callback: (value) => {
|
|
113
|
+
draggedX.value = value;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async function snapTo(args2) {
|
|
118
|
+
const { snapPoint, interpolate: interpolate2, duration } = args2;
|
|
119
|
+
await nextTick();
|
|
120
|
+
const mappedSnapPoint = mapSnapPoint(snapPoint);
|
|
121
|
+
if (mappedSnapPoint) {
|
|
122
|
+
if (interpolate2) {
|
|
123
|
+
interpolateDragged({
|
|
124
|
+
x: mappedSnapPoint.x,
|
|
125
|
+
y: mappedSnapPoint.y,
|
|
126
|
+
duration
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
draggedX.value = mappedSnapPoint.x;
|
|
130
|
+
draggedY.value = mappedSnapPoint.y;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
activeSnapPoint.value = snapPoint;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
mappedSnapPoints,
|
|
137
|
+
activeSnapPoint,
|
|
138
|
+
snapPointsMap,
|
|
139
|
+
mapSnapPoint,
|
|
140
|
+
interpolateDragged,
|
|
141
|
+
snapTo
|
|
142
|
+
};
|
|
143
|
+
}
|