@maas/vue-equipment 1.1.0 → 1.2.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/nuxt/module.json +1 -1
- package/dist/nuxt/module.mjs +1 -1
- package/dist/plugins/MagicCarousel/src/utils/defaultOptions.mjs +1 -1
- package/dist/plugins/MagicDraggable/src/utils/defaultOptions.mjs +1 -1
- package/dist/plugins/MagicDrawer/src/components/MagicDrawerContent.vue +4 -0
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerDrag.mjs +1 -2
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerProgress.mjs +57 -77
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.mjs +2 -5
- package/dist/plugins/MagicDrawer/src/utils/defaultOptions.mjs +1 -1
- package/dist/plugins/MagicTray/index.d.ts +2 -1
- package/dist/plugins/MagicTray/index.mjs +3 -0
- package/dist/plugins/MagicTray/src/components/MagicTrayContent.d.vue.ts +2 -2
- package/dist/plugins/MagicTray/src/components/MagicTrayContent.vue +17 -16
- package/dist/plugins/MagicTray/src/components/MagicTrayContent.vue.d.ts +2 -2
- package/dist/plugins/MagicTray/src/components/MagicTrayTrigger.d.vue.ts +25 -0
- package/dist/plugins/MagicTray/src/components/MagicTrayTrigger.vue +90 -0
- package/dist/plugins/MagicTray/src/components/MagicTrayTrigger.vue.d.ts +25 -0
- package/dist/plugins/MagicTray/src/composables/private/useTrayDrag.d.ts +0 -4
- package/dist/plugins/MagicTray/src/composables/private/useTrayDrag.mjs +9 -415
- package/dist/plugins/MagicTray/src/composables/private/useTrayGesture.d.ts +16 -0
- package/dist/plugins/MagicTray/src/composables/private/useTrayGesture.mjs +426 -0
- package/dist/plugins/MagicTray/src/composables/private/useTrayMagnetism.mjs +9 -37
- package/dist/plugins/MagicTray/src/composables/private/useTrayProgress.mjs +1 -1
- package/dist/plugins/MagicTray/src/composables/private/useTraySnap.mjs +2 -4
- package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.d.ts +8 -1
- package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.mjs +7 -1
- package/dist/plugins/MagicTray/src/utils/defaultOptions.mjs +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { computed, onScopeDispose, readonly, ref, toValue, watch } from "vue";
|
|
2
|
+
import { useEventListener } from "@vueuse/core";
|
|
3
|
+
import {
|
|
4
|
+
cancelEdgeNavigation,
|
|
5
|
+
guardedReleasePointerCapture,
|
|
6
|
+
guardedSetPointerCapture,
|
|
7
|
+
isAndroid,
|
|
8
|
+
isIOS,
|
|
9
|
+
isWithinRange,
|
|
10
|
+
lockSelection,
|
|
11
|
+
snapCommit,
|
|
12
|
+
snapRelease
|
|
13
|
+
} from "@maas/vue-equipment/utils";
|
|
14
|
+
import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
15
|
+
import { useTraySnap } from "./useTraySnap.mjs";
|
|
16
|
+
import { SIDES, useTrayUtils } from "./useTrayUtils.mjs";
|
|
17
|
+
export function useTrayGesture(args) {
|
|
18
|
+
const { id, state, selectionLock = "press", preventEdgeNavigation } = args;
|
|
19
|
+
const { clampWithOvershoot, isVertical, isDraggableSide } = useTrayUtils();
|
|
20
|
+
const emitter = useMagicEmitter();
|
|
21
|
+
const {
|
|
22
|
+
maxInset,
|
|
23
|
+
mappedSnapPoints,
|
|
24
|
+
mappedRanges,
|
|
25
|
+
rangeAt,
|
|
26
|
+
snapPointAt,
|
|
27
|
+
restingInset,
|
|
28
|
+
findSnapTarget,
|
|
29
|
+
interpolateDragged
|
|
30
|
+
} = useTraySnap({ id, state });
|
|
31
|
+
let lastPendingTarget = void 0;
|
|
32
|
+
let heldRangeSnap = false;
|
|
33
|
+
let flicked = false;
|
|
34
|
+
let cancelPointerup = void 0;
|
|
35
|
+
let cancelPointermove = void 0;
|
|
36
|
+
let cancelPointercancel = void 0;
|
|
37
|
+
let cancelTouchmove = void 0;
|
|
38
|
+
let cancelTouchend = void 0;
|
|
39
|
+
let cancelTouchcancel = void 0;
|
|
40
|
+
let pointerdownTarget = null;
|
|
41
|
+
let releaseSelection = void 0;
|
|
42
|
+
const threshold = computed(() => state.options.threshold);
|
|
43
|
+
const disabled = computed(() => state.options.disabled);
|
|
44
|
+
const snapMode = computed(() => state.options.snap.mode);
|
|
45
|
+
const dragMode = computed(() => state.options.drag.mode);
|
|
46
|
+
const active = ref(false);
|
|
47
|
+
const hasDragged = computed(() => {
|
|
48
|
+
const sides = state.draggingSide ? [state.draggingSide] : SIDES;
|
|
49
|
+
return sides.some(
|
|
50
|
+
(side) => !isWithinRange({
|
|
51
|
+
input: state.dragged[side],
|
|
52
|
+
base: state.lastDragged[side],
|
|
53
|
+
threshold: toValue(threshold).lock
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
function lockSelectionOnce() {
|
|
58
|
+
releaseSelection ??= lockSelection();
|
|
59
|
+
}
|
|
60
|
+
function canBegin(side) {
|
|
61
|
+
return !state.dragging && !toValue(disabled) && state.elRect !== void 0 && isDraggableSide({ snapPoints: state.options.snapPoints, side });
|
|
62
|
+
}
|
|
63
|
+
function dragBounds(side) {
|
|
64
|
+
const points = mappedSnapPoints(side);
|
|
65
|
+
const geometricMax = maxInset(side);
|
|
66
|
+
if (!points.length) {
|
|
67
|
+
return { min: 0, max: geometricMax };
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
min: Math.max(0, points[0]),
|
|
71
|
+
max: Math.min(points[points.length - 1], geometricMax)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function snapDrag(side) {
|
|
75
|
+
return {
|
|
76
|
+
points: mappedSnapPoints(side),
|
|
77
|
+
ranges: mappedRanges(side),
|
|
78
|
+
mode: snapMode.value,
|
|
79
|
+
rest: state.snapped[side],
|
|
80
|
+
start: state.lastDragged[side],
|
|
81
|
+
position: state.dragged[side]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function settleTarget(side) {
|
|
85
|
+
const target = snapRelease({
|
|
86
|
+
...snapDrag(side),
|
|
87
|
+
committed: state.interpolateTo,
|
|
88
|
+
flicked,
|
|
89
|
+
tapped: !hasDragged.value
|
|
90
|
+
});
|
|
91
|
+
return restingInset(side, target);
|
|
92
|
+
}
|
|
93
|
+
function isSnapDrag(side) {
|
|
94
|
+
return typeof dragMode.value === "string" ? dragMode.value === "snap" : (dragMode.value?.[side] ?? "free") === "snap";
|
|
95
|
+
}
|
|
96
|
+
function computeInset(side, coord) {
|
|
97
|
+
let newInset = 0;
|
|
98
|
+
switch (side) {
|
|
99
|
+
case "top":
|
|
100
|
+
newInset = coord - state.origin;
|
|
101
|
+
break;
|
|
102
|
+
case "bottom":
|
|
103
|
+
newInset = state.origin - coord;
|
|
104
|
+
break;
|
|
105
|
+
case "left":
|
|
106
|
+
newInset = coord - state.origin;
|
|
107
|
+
break;
|
|
108
|
+
case "right":
|
|
109
|
+
newInset = state.origin - coord;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
const { min, max } = dragBounds(side);
|
|
113
|
+
return clampWithOvershoot(
|
|
114
|
+
newInset,
|
|
115
|
+
min,
|
|
116
|
+
max,
|
|
117
|
+
state.overshoot.outer[side],
|
|
118
|
+
state.overshoot.inner
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
function setDragged(side, coord) {
|
|
122
|
+
const newInset = computeInset(side, coord);
|
|
123
|
+
if (newInset === state.dragged[side]) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const prev = state.dragged[side];
|
|
127
|
+
state.relDirection[side] = newInset < prev ? "below" : "above";
|
|
128
|
+
state.dragged[side] = newInset;
|
|
129
|
+
}
|
|
130
|
+
function snapDragged(side, coord) {
|
|
131
|
+
const inset = computeInset(side, coord);
|
|
132
|
+
const target = findSnapTarget(side, inset);
|
|
133
|
+
if (target === void 0 || target === state.snapped[side]) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
state.dragged[side] = target;
|
|
137
|
+
state.snapped[side] = target;
|
|
138
|
+
state.activeSnapPoint[side] = snapPointAt(side, target);
|
|
139
|
+
heldRangeSnap = !mappedSnapPoints(side).includes(target);
|
|
140
|
+
if (!heldRangeSnap) {
|
|
141
|
+
emitSnap(side);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function releaseSnapDrag(side) {
|
|
145
|
+
if (heldRangeSnap) {
|
|
146
|
+
emitSnap(side);
|
|
147
|
+
}
|
|
148
|
+
heldRangeSnap = false;
|
|
149
|
+
}
|
|
150
|
+
function emitSnap(side) {
|
|
151
|
+
const point = state.activeSnapPoint[side];
|
|
152
|
+
if (point === void 0) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
emitter.emit("beforeSnap", {
|
|
156
|
+
id: toValue(id),
|
|
157
|
+
snapPoint: { side, point }
|
|
158
|
+
});
|
|
159
|
+
emitter.emit("afterSnap", {
|
|
160
|
+
id: toValue(id),
|
|
161
|
+
snapPoint: { side, point }
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function checkPosition(side) {
|
|
165
|
+
const direction = state.relDirection[side];
|
|
166
|
+
state.interpolateTo = snapCommit({
|
|
167
|
+
...snapDrag(side),
|
|
168
|
+
distance: toValue(threshold).distance,
|
|
169
|
+
flicked,
|
|
170
|
+
flickDirection: direction === "absolute" ? void 0 : direction
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function emitWillSnapTo(side) {
|
|
174
|
+
const target = settleTarget(side);
|
|
175
|
+
const isPoint = mappedSnapPoints(side).includes(target);
|
|
176
|
+
const pending = !isPoint && rangeAt(side, target)?.range || target;
|
|
177
|
+
if (pending === lastPendingTarget) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
lastPendingTarget = pending;
|
|
181
|
+
const snapPoint = snapPointAt(side, target);
|
|
182
|
+
if (snapPoint === void 0) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
emitter.emit("willSnapTo", {
|
|
186
|
+
id: toValue(id),
|
|
187
|
+
side,
|
|
188
|
+
snapPoint
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function checkMomentum(side) {
|
|
192
|
+
const elapsed = Date.now() - state.dragStart.getTime();
|
|
193
|
+
const distance = Math.abs(state.dragged[side] - state.lastDragged[side]);
|
|
194
|
+
const velocity = elapsed && distance ? distance / elapsed : 0;
|
|
195
|
+
flicked = velocity > toValue(threshold).momentum;
|
|
196
|
+
}
|
|
197
|
+
function resetListeners() {
|
|
198
|
+
cancelTouchmove?.();
|
|
199
|
+
cancelTouchend?.();
|
|
200
|
+
cancelTouchcancel?.();
|
|
201
|
+
cancelPointerup?.();
|
|
202
|
+
cancelPointermove?.();
|
|
203
|
+
cancelPointercancel?.();
|
|
204
|
+
}
|
|
205
|
+
function resetDragState() {
|
|
206
|
+
const side = state.draggingSide;
|
|
207
|
+
if (side) {
|
|
208
|
+
state.lastDragged[side] = state.snapped[side];
|
|
209
|
+
}
|
|
210
|
+
releaseSelection?.();
|
|
211
|
+
releaseSelection = void 0;
|
|
212
|
+
active.value = false;
|
|
213
|
+
state.dragging = false;
|
|
214
|
+
state.draggingSide = void 0;
|
|
215
|
+
state.interpolateTo = void 0;
|
|
216
|
+
}
|
|
217
|
+
function settle(side) {
|
|
218
|
+
const target = settleTarget(side);
|
|
219
|
+
if (target !== state.snapped[side] || state.interpolateTo !== void 0) {
|
|
220
|
+
state.snapped[side] = target;
|
|
221
|
+
state.activeSnapPoint[side] = snapPointAt(side, target);
|
|
222
|
+
}
|
|
223
|
+
interpolateDragged({ side, to: target });
|
|
224
|
+
}
|
|
225
|
+
function onPointermove(e) {
|
|
226
|
+
if (e.isTrusted && !e.isPrimary) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const side = state.draggingSide;
|
|
230
|
+
if (!side) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
e.stopImmediatePropagation();
|
|
234
|
+
e.stopPropagation();
|
|
235
|
+
const coord = isVertical(side) ? e.clientY : e.clientX;
|
|
236
|
+
if (isSnapDrag(side)) {
|
|
237
|
+
snapDragged(side, coord);
|
|
238
|
+
} else {
|
|
239
|
+
setDragged(side, coord);
|
|
240
|
+
checkMomentum(side);
|
|
241
|
+
checkPosition(side);
|
|
242
|
+
emitWillSnapTo(side);
|
|
243
|
+
}
|
|
244
|
+
if (hasDragged.value) {
|
|
245
|
+
lockSelectionOnce();
|
|
246
|
+
}
|
|
247
|
+
emitter.emit("drag", {
|
|
248
|
+
id: toValue(id),
|
|
249
|
+
side,
|
|
250
|
+
value: state.dragged[side]
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
function onPointerup(e) {
|
|
254
|
+
const side = state.draggingSide;
|
|
255
|
+
if (side) {
|
|
256
|
+
if (isSnapDrag(side)) {
|
|
257
|
+
releaseSnapDrag(side);
|
|
258
|
+
} else {
|
|
259
|
+
settle(side);
|
|
260
|
+
}
|
|
261
|
+
emitter.emit("afterDrag", {
|
|
262
|
+
id: toValue(id),
|
|
263
|
+
side,
|
|
264
|
+
value: state.dragged[side]
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
resetDragState();
|
|
268
|
+
resetListeners();
|
|
269
|
+
guardedReleasePointerCapture({ event: e, element: pointerdownTarget });
|
|
270
|
+
}
|
|
271
|
+
function onTouchmove(e) {
|
|
272
|
+
const side = state.draggingSide;
|
|
273
|
+
if (!side) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const firstTouch = e.touches[0];
|
|
277
|
+
if (!firstTouch) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
e.stopImmediatePropagation();
|
|
281
|
+
e.stopPropagation();
|
|
282
|
+
if (hasDragged.value) {
|
|
283
|
+
e.preventDefault();
|
|
284
|
+
}
|
|
285
|
+
const coord = isVertical(side) ? firstTouch.clientY : firstTouch.clientX;
|
|
286
|
+
if (isSnapDrag(side)) {
|
|
287
|
+
snapDragged(side, coord);
|
|
288
|
+
} else {
|
|
289
|
+
setDragged(side, coord);
|
|
290
|
+
checkMomentum(side);
|
|
291
|
+
checkPosition(side);
|
|
292
|
+
emitWillSnapTo(side);
|
|
293
|
+
}
|
|
294
|
+
if (hasDragged.value) {
|
|
295
|
+
lockSelectionOnce();
|
|
296
|
+
}
|
|
297
|
+
emitter.emit("drag", {
|
|
298
|
+
id: toValue(id),
|
|
299
|
+
side,
|
|
300
|
+
value: state.dragged[side]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
function onTouchend() {
|
|
304
|
+
const side = state.draggingSide;
|
|
305
|
+
if (side) {
|
|
306
|
+
if (isSnapDrag(side)) {
|
|
307
|
+
releaseSnapDrag(side);
|
|
308
|
+
} else {
|
|
309
|
+
settle(side);
|
|
310
|
+
}
|
|
311
|
+
emitter.emit("afterDrag", {
|
|
312
|
+
id: toValue(id),
|
|
313
|
+
side,
|
|
314
|
+
value: state.dragged[side]
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
resetDragState();
|
|
318
|
+
resetListeners();
|
|
319
|
+
}
|
|
320
|
+
function beginDrag(side, coord, target) {
|
|
321
|
+
active.value = true;
|
|
322
|
+
state.dragging = true;
|
|
323
|
+
state.draggingSide = side;
|
|
324
|
+
state.interpolateTo = void 0;
|
|
325
|
+
state.dragged[side] += state.magnetic[side];
|
|
326
|
+
state.magnetic[side] = 0;
|
|
327
|
+
state.lastDragged[side] = state.dragged[side];
|
|
328
|
+
lastPendingTarget = void 0;
|
|
329
|
+
heldRangeSnap = false;
|
|
330
|
+
flicked = false;
|
|
331
|
+
pointerdownTarget = target;
|
|
332
|
+
if (selectionLock === "press") {
|
|
333
|
+
lockSelectionOnce();
|
|
334
|
+
}
|
|
335
|
+
switch (side) {
|
|
336
|
+
case "top":
|
|
337
|
+
case "left":
|
|
338
|
+
state.origin = coord - state.dragged[side];
|
|
339
|
+
break;
|
|
340
|
+
case "bottom":
|
|
341
|
+
case "right":
|
|
342
|
+
state.origin = coord + state.dragged[side];
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
state.dragStart = /* @__PURE__ */ new Date();
|
|
346
|
+
emitter.emit("beforeDrag", {
|
|
347
|
+
id: toValue(id),
|
|
348
|
+
side,
|
|
349
|
+
value: state.dragged[side]
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function onCancel() {
|
|
353
|
+
const side = state.draggingSide;
|
|
354
|
+
if (active.value && side) {
|
|
355
|
+
interpolateDragged({ side, to: state.snapped[side] });
|
|
356
|
+
resetDragState();
|
|
357
|
+
}
|
|
358
|
+
resetListeners();
|
|
359
|
+
}
|
|
360
|
+
function onPointerdown(side, e) {
|
|
361
|
+
if (!canBegin(side)) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const coord = isVertical(side) ? e.clientY : e.clientX;
|
|
365
|
+
const target = e.target instanceof Element ? e.target : null;
|
|
366
|
+
beginDrag(side, coord, target);
|
|
367
|
+
guardedSetPointerCapture({ event: e, element: target });
|
|
368
|
+
resetListeners();
|
|
369
|
+
cancelPointerup = useEventListener(document, "pointerup", onPointerup);
|
|
370
|
+
cancelPointercancel = useEventListener(
|
|
371
|
+
document,
|
|
372
|
+
"pointercancel",
|
|
373
|
+
onPointerup
|
|
374
|
+
);
|
|
375
|
+
cancelPointermove = useEventListener(
|
|
376
|
+
document,
|
|
377
|
+
"pointermove",
|
|
378
|
+
onPointermove,
|
|
379
|
+
{
|
|
380
|
+
passive: false
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
cancelTouchend = isIOS() || isAndroid() ? useEventListener(document, "touchend", onTouchend) : void 0;
|
|
384
|
+
cancelTouchcancel = isIOS() || isAndroid() ? useEventListener(document, "touchcancel", onTouchend) : void 0;
|
|
385
|
+
onPointermove(e);
|
|
386
|
+
}
|
|
387
|
+
function onTouchstart(side, e) {
|
|
388
|
+
if (toValue(preventEdgeNavigation)) {
|
|
389
|
+
cancelEdgeNavigation({ event: e });
|
|
390
|
+
}
|
|
391
|
+
if (!isAndroid() || !canBegin(side)) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const firstTouch = e.touches[0];
|
|
395
|
+
if (!firstTouch) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
e.stopImmediatePropagation();
|
|
399
|
+
e.stopPropagation();
|
|
400
|
+
const coord = isVertical(side) ? firstTouch.clientY : firstTouch.clientX;
|
|
401
|
+
beginDrag(side, coord, e.target instanceof Element ? e.target : null);
|
|
402
|
+
cancelTouchmove?.();
|
|
403
|
+
cancelTouchmove = useEventListener(document, "touchmove", onTouchmove, {
|
|
404
|
+
passive: false
|
|
405
|
+
});
|
|
406
|
+
cancelTouchend?.();
|
|
407
|
+
cancelTouchend = useEventListener(document, "touchend", onTouchend, {
|
|
408
|
+
passive: false
|
|
409
|
+
});
|
|
410
|
+
cancelTouchcancel?.();
|
|
411
|
+
cancelTouchcancel = useEventListener(document, "touchcancel", onTouchend);
|
|
412
|
+
onTouchmove(e);
|
|
413
|
+
}
|
|
414
|
+
watch(disabled, (value) => {
|
|
415
|
+
if (value) {
|
|
416
|
+
onCancel();
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
onScopeDispose(onCancel, true);
|
|
420
|
+
return {
|
|
421
|
+
active: readonly(active),
|
|
422
|
+
hasDragged,
|
|
423
|
+
onPointerdown,
|
|
424
|
+
onTouchstart
|
|
425
|
+
};
|
|
426
|
+
}
|
|
@@ -5,19 +5,14 @@ import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
|
5
5
|
import { useMagicError } from "@maas/vue-equipment/plugins/MagicError";
|
|
6
6
|
import { useEasings } from "@maas/vue-equipment/composables/useEasings";
|
|
7
7
|
import { useTraySnap } from "./useTraySnap.mjs";
|
|
8
|
-
import { useTrayUtils } from "./useTrayUtils.mjs";
|
|
9
|
-
const SIDES = ["top", "right", "bottom", "left"];
|
|
10
|
-
const EPSILON = 0.5;
|
|
8
|
+
import { SIDES, useTrayUtils } from "./useTrayUtils.mjs";
|
|
11
9
|
export function useTrayMagnetism(args) {
|
|
12
10
|
const { id, elRef, handleRefs, state } = args;
|
|
13
11
|
const { throwError } = useMagicError({
|
|
14
12
|
prefix: "MagicTray",
|
|
15
13
|
source: "useTrayMagnetism"
|
|
16
14
|
});
|
|
17
|
-
const {
|
|
18
|
-
id,
|
|
19
|
-
state
|
|
20
|
-
});
|
|
15
|
+
const { maxInset } = useTraySnap({ id, state });
|
|
21
16
|
const { flattenSnapPoints } = useTrayUtils();
|
|
22
17
|
const emitter = useMagicEmitter();
|
|
23
18
|
const easings = useEasings();
|
|
@@ -42,29 +37,6 @@ export function useTrayMagnetism(args) {
|
|
|
42
37
|
const enabled = computed(
|
|
43
38
|
() => magneticSides.value.length > 0 && !disabled.value
|
|
44
39
|
);
|
|
45
|
-
const magneticPoints = computed(
|
|
46
|
-
() => {
|
|
47
|
-
const result = {
|
|
48
|
-
top: [],
|
|
49
|
-
right: [],
|
|
50
|
-
bottom: [],
|
|
51
|
-
left: []
|
|
52
|
-
};
|
|
53
|
-
for (const side of magneticSides.value) {
|
|
54
|
-
const config = sideConfig(side);
|
|
55
|
-
if (!config || !mappedSnapPoints(side).length) {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
result[side] = Object.entries(config).map(([key, direction]) => ({
|
|
59
|
-
inset: mapSnapPoint(side, coercePoint(key)),
|
|
60
|
-
direction
|
|
61
|
-
})).filter(
|
|
62
|
-
(point) => point.inset === 0 || !!point.inset && !Number.isNaN(point.inset)
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
40
|
const progress = {
|
|
69
41
|
top: 0,
|
|
70
42
|
right: 0,
|
|
@@ -136,11 +108,11 @@ export function useTrayMagnetism(args) {
|
|
|
136
108
|
}
|
|
137
109
|
}
|
|
138
110
|
function restDirection(side) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return
|
|
111
|
+
const point = state.activeSnapPoint[side];
|
|
112
|
+
if (point === void 0) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return sideConfig(side)?.[point] ?? null;
|
|
144
116
|
}
|
|
145
117
|
function handleRect(side) {
|
|
146
118
|
const handle = unrefElement(handleRefs[side].value?.[0]);
|
|
@@ -169,7 +141,7 @@ export function useTrayMagnetism(args) {
|
|
|
169
141
|
if (settling[side]) {
|
|
170
142
|
return;
|
|
171
143
|
}
|
|
172
|
-
if (Math.
|
|
144
|
+
if (Math.round(magneticOffset[side]) === 0) {
|
|
173
145
|
resetSide(side);
|
|
174
146
|
return;
|
|
175
147
|
}
|
|
@@ -346,7 +318,7 @@ export function useTrayMagnetism(args) {
|
|
|
346
318
|
-state.dragged[side],
|
|
347
319
|
maxInset(side) - state.dragged[side]
|
|
348
320
|
);
|
|
349
|
-
if (Math.
|
|
321
|
+
if (Math.round(target) !== 0) {
|
|
350
322
|
cancelSettle(side);
|
|
351
323
|
magneticOffset[side] = target;
|
|
352
324
|
if (!isVirtual.value) {
|
|
@@ -2,7 +2,7 @@ import { toValue, watch } from "vue";
|
|
|
2
2
|
import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
3
3
|
import { clampValue } from "@maas/vue-equipment/utils";
|
|
4
4
|
import { useTraySnap } from "./useTraySnap.mjs";
|
|
5
|
-
|
|
5
|
+
import { SIDES } from "./useTrayUtils.mjs";
|
|
6
6
|
export function useTrayProgress(args) {
|
|
7
7
|
const { id, state } = args;
|
|
8
8
|
const emitter = useMagicEmitter();
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
} from "@maas/vue-equipment/utils";
|
|
8
8
|
import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
9
9
|
import { useTrayUtils } from "./useTrayUtils.mjs";
|
|
10
|
-
const SNAP_TOLERANCE = 0.01;
|
|
11
10
|
function isMapped(value) {
|
|
12
11
|
return value !== void 0 && !Number.isNaN(value);
|
|
13
12
|
}
|
|
@@ -118,9 +117,7 @@ export function useTraySnap(args) {
|
|
|
118
117
|
if (mapped === void 0) {
|
|
119
118
|
return false;
|
|
120
119
|
}
|
|
121
|
-
return !!rangeAt(side, mapped) || mappedSnapPoints(side).
|
|
122
|
-
(point) => Math.abs(point - mapped) < SNAP_TOLERANCE
|
|
123
|
-
);
|
|
120
|
+
return !!rangeAt(side, mapped) || mappedSnapPoints(side).includes(mapped);
|
|
124
121
|
}
|
|
125
122
|
function findSnapTarget(side, inset) {
|
|
126
123
|
const target = snapTargetAt({
|
|
@@ -186,6 +183,7 @@ export function useTraySnap(args) {
|
|
|
186
183
|
}
|
|
187
184
|
const closest = findSnapTarget(side, mapped) ?? mapped;
|
|
188
185
|
state.snapped[side] = closest;
|
|
186
|
+
state.lastDragged[side] = closest;
|
|
189
187
|
state.activeSnapPoint[side] = snapPointAt(side, closest) ?? snapPoint;
|
|
190
188
|
if (shouldInterpolate) {
|
|
191
189
|
interpolateDragged({ side, to: closest, duration });
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import type { MagicTraySide, MagicTraySnapEntry, MagicTraySnapRange } from '../../types/index.js';
|
|
1
|
+
import type { MagicTraySide, MagicTraySnapEntry, MagicTraySnapRange, TraySnapPoints } from '../../types/index.js';
|
|
2
|
+
export declare const SIDES: Array<MagicTraySide>;
|
|
3
|
+
type IsDraggableSideArgs = {
|
|
4
|
+
snapPoints: TraySnapPoints;
|
|
5
|
+
side: MagicTraySide;
|
|
6
|
+
};
|
|
2
7
|
export declare function useTrayUtils(): {
|
|
3
8
|
clampWithOvershoot: (value: number, min: number, max: number, outer: number, inner: number) => any;
|
|
4
9
|
isVertical: (side: MagicTraySide) => side is "top" | "bottom";
|
|
5
10
|
oppositeSide: (side: MagicTraySide) => MagicTraySide;
|
|
6
11
|
isSnapRange: (entry: MagicTraySnapEntry) => entry is MagicTraySnapRange;
|
|
7
12
|
flattenSnapPoints: (entries: Array<MagicTraySnapEntry>) => import("../../types/index.js").MagicTraySnapPoint[];
|
|
13
|
+
isDraggableSide: (args: IsDraggableSideArgs) => boolean;
|
|
8
14
|
};
|
|
15
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { rubberband } from "@maas/vue-equipment/utils";
|
|
2
|
+
export const SIDES = ["top", "right", "bottom", "left"];
|
|
2
3
|
export function useTrayUtils() {
|
|
3
4
|
function clampWithOvershoot(value, min, max, outer, inner) {
|
|
4
5
|
if (value < min) {
|
|
@@ -32,11 +33,16 @@ export function useTrayUtils() {
|
|
|
32
33
|
(entry) => isSnapRange(entry) ? [entry.min, entry.max] : [entry]
|
|
33
34
|
);
|
|
34
35
|
}
|
|
36
|
+
function isDraggableSide(args) {
|
|
37
|
+
const { snapPoints, side } = args;
|
|
38
|
+
return (snapPoints[side]?.length ?? 0) > 0;
|
|
39
|
+
}
|
|
35
40
|
return {
|
|
36
41
|
clampWithOvershoot,
|
|
37
42
|
isVertical,
|
|
38
43
|
oppositeSide,
|
|
39
44
|
isSnapRange,
|
|
40
|
-
flattenSnapPoints
|
|
45
|
+
flattenSnapPoints,
|
|
46
|
+
isDraggableSide
|
|
41
47
|
};
|
|
42
48
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maas/vue-equipment",
|
|
3
3
|
"description": "Our Frontend Toolkit, Free and Open Source",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"contributors": [
|
|
6
6
|
{
|
|
7
7
|
"name": "Robin Scholz",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"@floating-ui/vue": "^1 || ^2",
|
|
79
79
|
"@maas/magic-timer": "^1",
|
|
80
80
|
"@maas/vue-autosize": "^1",
|
|
81
|
-
"@maas/vue-primitive": "^1.
|
|
81
|
+
"@maas/vue-primitive": "^1.5",
|
|
82
82
|
"@nuxt/kit": ">=3",
|
|
83
83
|
"@vueuse/core": ">=12",
|
|
84
84
|
"@vueuse/integrations": ">=12",
|