@maas/vue-equipment 1.0.1 → 1.1.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 +2 -2
- package/dist/plugins/MagicDrawer/index.d.ts +2 -2
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerDrag.mjs +127 -168
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.d.ts +16 -11
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.mjs +178 -175
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerState.mjs +2 -1
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerUtils.d.ts +3 -0
- package/dist/plugins/MagicDrawer/src/composables/private/useDrawerUtils.mjs +11 -1
- package/dist/plugins/MagicDrawer/src/composables/useMagicDrawer.d.ts +1 -0
- package/dist/plugins/MagicDrawer/src/composables/useMagicDrawer.mjs +2 -1
- package/dist/plugins/MagicDrawer/src/types/index.d.ts +8 -1
- package/dist/plugins/MagicTray/index.d.ts +2 -2
- package/dist/plugins/MagicTray/src/composables/private/useTrayDrag.mjs +99 -51
- package/dist/plugins/MagicTray/src/composables/private/useTrayMagnetism.mjs +3 -1
- package/dist/plugins/MagicTray/src/composables/private/useTraySnap.d.ts +12 -7
- package/dist/plugins/MagicTray/src/composables/private/useTraySnap.mjs +89 -39
- package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.d.ts +3 -1
- package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.mjs +11 -1
- package/dist/plugins/MagicTray/src/types/index.d.ts +7 -1
- package/dist/utils/index.d.ts +46 -1
- package/dist/utils/index.js +75 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
isAndroid,
|
|
22
22
|
isIOS,
|
|
23
23
|
isWithinRange,
|
|
24
|
-
lockSelection
|
|
24
|
+
lockSelection,
|
|
25
|
+
snapCommit,
|
|
26
|
+
snapRelease
|
|
25
27
|
} from "@maas/vue-equipment/utils";
|
|
26
28
|
import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
27
29
|
import { useMagicError } from "@maas/vue-equipment/plugins/MagicError";
|
|
@@ -37,7 +39,7 @@ export function useTrayDrag(args) {
|
|
|
37
39
|
});
|
|
38
40
|
const { initializeState } = useTrayState(toValue(id));
|
|
39
41
|
const state = initializeState();
|
|
40
|
-
const { clampWithOvershoot, isVertical } = useTrayUtils();
|
|
42
|
+
const { clampWithOvershoot, isVertical, flattenSnapPoints } = useTrayUtils();
|
|
41
43
|
const emitter = useMagicEmitter();
|
|
42
44
|
const {
|
|
43
45
|
dimension,
|
|
@@ -45,8 +47,12 @@ export function useTrayDrag(args) {
|
|
|
45
47
|
maxInset,
|
|
46
48
|
mapSnapPoint,
|
|
47
49
|
mappedSnapPoints,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
mappedRanges,
|
|
51
|
+
rangeAt,
|
|
52
|
+
snapPointAt,
|
|
53
|
+
restingInset,
|
|
54
|
+
isSnapTarget,
|
|
55
|
+
findSnapTarget,
|
|
50
56
|
interpolateDragged,
|
|
51
57
|
snapTo
|
|
52
58
|
} = useTraySnap({ id, state });
|
|
@@ -63,9 +69,11 @@ export function useTrayDrag(args) {
|
|
|
63
69
|
}
|
|
64
70
|
function openSnapPoint(side) {
|
|
65
71
|
const points = mappedSnapPoints(side);
|
|
66
|
-
return points.length ?
|
|
72
|
+
return points.length ? snapPointAt(side, points[0]) : void 0;
|
|
67
73
|
}
|
|
68
74
|
let lastPendingTarget = void 0;
|
|
75
|
+
let heldRangeSnap = false;
|
|
76
|
+
let flicked = false;
|
|
69
77
|
let suppressClick = false;
|
|
70
78
|
let cancelPointerup = void 0;
|
|
71
79
|
let cancelPointermove = void 0;
|
|
@@ -86,8 +94,24 @@ export function useTrayDrag(args) {
|
|
|
86
94
|
const preventEdgeNavigation = computed(
|
|
87
95
|
() => state.options.preventEdgeNavigation
|
|
88
96
|
);
|
|
89
|
-
function
|
|
90
|
-
return
|
|
97
|
+
function snapDrag(side) {
|
|
98
|
+
return {
|
|
99
|
+
points: mappedSnapPoints(side),
|
|
100
|
+
ranges: mappedRanges(side),
|
|
101
|
+
mode: snapMode.value,
|
|
102
|
+
rest: state.snapped[side],
|
|
103
|
+
start: state.lastDragged[side],
|
|
104
|
+
position: state.dragged[side]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function settleTarget(side) {
|
|
108
|
+
const target = snapRelease({
|
|
109
|
+
...snapDrag(side),
|
|
110
|
+
committed: state.interpolateTo,
|
|
111
|
+
flicked,
|
|
112
|
+
tapped: !hasDragged.value
|
|
113
|
+
});
|
|
114
|
+
return restingInset(side, target);
|
|
91
115
|
}
|
|
92
116
|
function isSnapDrag(side) {
|
|
93
117
|
return typeof dragMode.value === "string" ? dragMode.value === "snap" : (dragMode.value?.[side] ?? "free") === "snap";
|
|
@@ -211,45 +235,57 @@ export function useTrayDrag(args) {
|
|
|
211
235
|
}
|
|
212
236
|
function snapDragged(side, coord) {
|
|
213
237
|
const inset = computeInset(side, coord);
|
|
214
|
-
const target =
|
|
238
|
+
const target = findSnapTarget(side, inset);
|
|
215
239
|
if (target === void 0 || target === state.snapped[side]) {
|
|
216
240
|
return;
|
|
217
241
|
}
|
|
218
|
-
const snapPoint = snapPointsMap(side)[target];
|
|
219
242
|
state.dragged[side] = target;
|
|
220
243
|
state.snapped[side] = target;
|
|
221
|
-
state.activeSnapPoint[side] =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
snapPoint: { side, point: snapPoint }
|
|
226
|
-
});
|
|
227
|
-
emitter.emit("afterSnap", {
|
|
228
|
-
id: toValue(id),
|
|
229
|
-
snapPoint: { side, point: snapPoint }
|
|
230
|
-
});
|
|
244
|
+
state.activeSnapPoint[side] = snapPointAt(side, target);
|
|
245
|
+
heldRangeSnap = !mappedSnapPoints(side).includes(target);
|
|
246
|
+
if (!heldRangeSnap) {
|
|
247
|
+
emitSnap(side);
|
|
231
248
|
}
|
|
232
249
|
}
|
|
233
|
-
function
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
state.interpolateTo = findClosestSnapPoint({
|
|
237
|
-
side,
|
|
238
|
-
value: snapReference(side),
|
|
239
|
-
direction: delta < 0 ? "below" : "above"
|
|
240
|
-
});
|
|
241
|
-
} else {
|
|
242
|
-
state.interpolateTo = void 0;
|
|
250
|
+
function releaseSnapDrag(side) {
|
|
251
|
+
if (heldRangeSnap) {
|
|
252
|
+
emitSnap(side);
|
|
243
253
|
}
|
|
254
|
+
heldRangeSnap = false;
|
|
255
|
+
}
|
|
256
|
+
function emitSnap(side) {
|
|
257
|
+
const point = state.activeSnapPoint[side];
|
|
258
|
+
if (point === void 0) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
emitter.emit("beforeSnap", {
|
|
262
|
+
id: toValue(id),
|
|
263
|
+
snapPoint: { side, point }
|
|
264
|
+
});
|
|
265
|
+
emitter.emit("afterSnap", {
|
|
266
|
+
id: toValue(id),
|
|
267
|
+
snapPoint: { side, point }
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function checkPosition(side) {
|
|
271
|
+
const direction = state.relDirection[side];
|
|
272
|
+
state.interpolateTo = snapCommit({
|
|
273
|
+
...snapDrag(side),
|
|
274
|
+
distance: toValue(threshold).distance,
|
|
275
|
+
flicked,
|
|
276
|
+
flickDirection: direction === "absolute" ? void 0 : direction
|
|
277
|
+
});
|
|
244
278
|
}
|
|
245
279
|
function emitWillSnapTo(side) {
|
|
246
|
-
const target =
|
|
247
|
-
|
|
280
|
+
const target = settleTarget(side);
|
|
281
|
+
const isPoint = mappedSnapPoints(side).includes(target);
|
|
282
|
+
const pending = !isPoint && rangeAt(side, target)?.range || target;
|
|
283
|
+
if (pending === lastPendingTarget) {
|
|
248
284
|
return;
|
|
249
285
|
}
|
|
250
|
-
lastPendingTarget =
|
|
251
|
-
const snapPoint =
|
|
252
|
-
if (
|
|
286
|
+
lastPendingTarget = pending;
|
|
287
|
+
const snapPoint = snapPointAt(side, target);
|
|
288
|
+
if (snapPoint === void 0) {
|
|
253
289
|
return;
|
|
254
290
|
}
|
|
255
291
|
emitter.emit("willSnapTo", {
|
|
@@ -262,13 +298,7 @@ export function useTrayDrag(args) {
|
|
|
262
298
|
const elapsed = Date.now() - state.dragStart.getTime();
|
|
263
299
|
const distance = Math.abs(state.dragged[side] - state.lastDragged[side]);
|
|
264
300
|
const velocity = elapsed && distance ? distance / elapsed : 0;
|
|
265
|
-
|
|
266
|
-
state.interpolateTo = findClosestSnapPoint({
|
|
267
|
-
side,
|
|
268
|
-
value: snapReference(side),
|
|
269
|
-
direction: state.relDirection[side]
|
|
270
|
-
});
|
|
271
|
-
}
|
|
301
|
+
flicked = velocity > toValue(threshold).momentum;
|
|
272
302
|
}
|
|
273
303
|
function resetListeners() {
|
|
274
304
|
cancelTouchmove?.();
|
|
@@ -286,13 +316,12 @@ export function useTrayDrag(args) {
|
|
|
286
316
|
state.interpolateTo = void 0;
|
|
287
317
|
}
|
|
288
318
|
function settle(side) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
state.snapped[side] =
|
|
292
|
-
state.activeSnapPoint[side] =
|
|
293
|
-
} else {
|
|
294
|
-
interpolateDragged({ side, to: state.snapped[side] });
|
|
319
|
+
const target = settleTarget(side);
|
|
320
|
+
if (target !== state.snapped[side] || state.interpolateTo !== void 0) {
|
|
321
|
+
state.snapped[side] = target;
|
|
322
|
+
state.activeSnapPoint[side] = snapPointAt(side, target);
|
|
295
323
|
}
|
|
324
|
+
interpolateDragged({ side, to: target });
|
|
296
325
|
}
|
|
297
326
|
function onPointermove(e) {
|
|
298
327
|
if (e.isTrusted && !e.isPrimary) {
|
|
@@ -323,7 +352,9 @@ export function useTrayDrag(args) {
|
|
|
323
352
|
const side = state.draggingSide;
|
|
324
353
|
if (side) {
|
|
325
354
|
suppressClick = hasDragged.value;
|
|
326
|
-
if (
|
|
355
|
+
if (isSnapDrag(side)) {
|
|
356
|
+
releaseSnapDrag(side);
|
|
357
|
+
} else {
|
|
327
358
|
settle(side);
|
|
328
359
|
}
|
|
329
360
|
emitter.emit("afterDrag", {
|
|
@@ -369,7 +400,9 @@ export function useTrayDrag(args) {
|
|
|
369
400
|
const side = state.draggingSide;
|
|
370
401
|
if (side) {
|
|
371
402
|
suppressClick = hasDragged.value;
|
|
372
|
-
if (
|
|
403
|
+
if (isSnapDrag(side)) {
|
|
404
|
+
releaseSnapDrag(side);
|
|
405
|
+
} else {
|
|
373
406
|
settle(side);
|
|
374
407
|
}
|
|
375
408
|
emitter.emit("afterDrag", {
|
|
@@ -389,6 +422,8 @@ export function useTrayDrag(args) {
|
|
|
389
422
|
state.magnetic[side] = 0;
|
|
390
423
|
state.lastDragged[side] = state.dragged[side];
|
|
391
424
|
lastPendingTarget = void 0;
|
|
425
|
+
heldRangeSnap = false;
|
|
426
|
+
flicked = false;
|
|
392
427
|
suppressClick = false;
|
|
393
428
|
pointerdownTarget = target;
|
|
394
429
|
releaseSelection = lockSelection();
|
|
@@ -484,6 +519,12 @@ export function useTrayDrag(args) {
|
|
|
484
519
|
return;
|
|
485
520
|
}
|
|
486
521
|
await getSizes();
|
|
522
|
+
if (contentExtent(side) && !isSnapTarget(side, point)) {
|
|
523
|
+
logWarning(
|
|
524
|
+
`Cannot snap side "${side}" to ${point}, which is neither a snap point nor inside a range`
|
|
525
|
+
);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
487
528
|
snapTo({
|
|
488
529
|
side,
|
|
489
530
|
snapPoint: point,
|
|
@@ -501,7 +542,14 @@ export function useTrayDrag(args) {
|
|
|
501
542
|
pendingInitialSides.add(side);
|
|
502
543
|
continue;
|
|
503
544
|
}
|
|
504
|
-
const
|
|
545
|
+
const configured = state.options.initial.snapPoints?.[side];
|
|
546
|
+
const isValid = configured === void 0 || isSnapTarget(side, configured);
|
|
547
|
+
if (!isValid) {
|
|
548
|
+
logWarning(
|
|
549
|
+
`initial.snapPoints.${side} (${configured}) is neither a snap point nor inside a range and is ignored`
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
const initial = (isValid ? configured : void 0) ?? openSnapPoint(side);
|
|
505
553
|
if (initial === void 0) {
|
|
506
554
|
continue;
|
|
507
555
|
}
|
|
@@ -518,7 +566,7 @@ export function useTrayDrag(args) {
|
|
|
518
566
|
}
|
|
519
567
|
function validateSnapPoints() {
|
|
520
568
|
for (const side of draggableSides.value) {
|
|
521
|
-
const points = state.options.snapPoints[side] ?? [];
|
|
569
|
+
const points = flattenSnapPoints(state.options.snapPoints[side] ?? []);
|
|
522
570
|
const canOpen = points.some((point) => parseFloat(String(point)) === 0);
|
|
523
571
|
const hasInitial = state.options.initial.snapPoints?.[side] !== void 0;
|
|
524
572
|
if (!canOpen && !hasInitial) {
|
|
@@ -5,6 +5,7 @@ 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";
|
|
8
9
|
const SIDES = ["top", "right", "bottom", "left"];
|
|
9
10
|
const EPSILON = 0.5;
|
|
10
11
|
export function useTrayMagnetism(args) {
|
|
@@ -17,6 +18,7 @@ export function useTrayMagnetism(args) {
|
|
|
17
18
|
id,
|
|
18
19
|
state
|
|
19
20
|
});
|
|
21
|
+
const { flattenSnapPoints } = useTrayUtils();
|
|
20
22
|
const emitter = useMagicEmitter();
|
|
21
23
|
const easings = useEasings();
|
|
22
24
|
const magnetism = computed(() => state.options.magnetism);
|
|
@@ -122,7 +124,7 @@ export function useTrayMagnetism(args) {
|
|
|
122
124
|
if (!config) {
|
|
123
125
|
continue;
|
|
124
126
|
}
|
|
125
|
-
const configured = state.options.snapPoints[side] ?? [];
|
|
127
|
+
const configured = flattenSnapPoints(state.options.snapPoints[side] ?? []);
|
|
126
128
|
for (const key of Object.keys(config)) {
|
|
127
129
|
if (!configured.includes(coercePoint(key))) {
|
|
128
130
|
throwError({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MaybeRef } from 'vue';
|
|
2
|
-
import type { MagicTraySide, MagicTraySnapPoint, TrayState } from '../../types/index.js';
|
|
2
|
+
import type { MagicTraySide, MagicTraySnapPoint, MagicTraySnapRange, TrayState } from '../../types/index.js';
|
|
3
3
|
type UseTraySnapArgs = {
|
|
4
4
|
id: MaybeRef<string>;
|
|
5
5
|
state: TrayState;
|
|
@@ -16,10 +16,11 @@ type InterpolateDraggedArgs = {
|
|
|
16
16
|
duration?: number;
|
|
17
17
|
easing?: (t: number) => number;
|
|
18
18
|
};
|
|
19
|
-
type
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
type MappedSnapRange = {
|
|
20
|
+
min: number;
|
|
21
|
+
max: number;
|
|
22
|
+
momentum?: boolean;
|
|
23
|
+
range: MagicTraySnapRange;
|
|
23
24
|
};
|
|
24
25
|
export declare function useTraySnap(args: UseTraySnapArgs): {
|
|
25
26
|
dimension: (side: MagicTraySide) => number;
|
|
@@ -28,8 +29,12 @@ export declare function useTraySnap(args: UseTraySnapArgs): {
|
|
|
28
29
|
maxInset: (side: MagicTraySide) => number;
|
|
29
30
|
mapSnapPoint: (side: MagicTraySide, snapPoint: MagicTraySnapPoint) => any;
|
|
30
31
|
mappedSnapPoints: (side: MagicTraySide) => any[];
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
mappedRanges: (side: MagicTraySide) => Array<MappedSnapRange>;
|
|
33
|
+
rangeAt: (side: MagicTraySide, inset: number) => any;
|
|
34
|
+
snapPointAt: (side: MagicTraySide, inset: number) => MagicTraySnapPoint | undefined;
|
|
35
|
+
restingInset: (side: MagicTraySide, inset: number) => any;
|
|
36
|
+
isSnapTarget: (side: MagicTraySide, snapPoint: MagicTraySnapPoint) => boolean;
|
|
37
|
+
findSnapTarget: (side: MagicTraySide, inset: number) => any;
|
|
33
38
|
interpolateDragged: (args: InterpolateDraggedArgs) => void;
|
|
34
39
|
snapTo: (args: SnapToArgs) => Promise<void>;
|
|
35
40
|
};
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { computed, nextTick, toValue } from "vue";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
clampValue,
|
|
4
|
+
interpolate,
|
|
5
|
+
snapRangeAt,
|
|
6
|
+
snapTargetAt
|
|
7
|
+
} from "@maas/vue-equipment/utils";
|
|
3
8
|
import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
|
|
4
9
|
import { useTrayUtils } from "./useTrayUtils.mjs";
|
|
10
|
+
const SNAP_TOLERANCE = 0.01;
|
|
11
|
+
function isMapped(value) {
|
|
12
|
+
return value !== void 0 && !Number.isNaN(value);
|
|
13
|
+
}
|
|
14
|
+
function roundDecimal(value) {
|
|
15
|
+
return Math.round(value * 1e4) / 1e4;
|
|
16
|
+
}
|
|
5
17
|
export function useTraySnap(args) {
|
|
6
18
|
const { id, state } = args;
|
|
7
|
-
const { isVertical, oppositeSide } = useTrayUtils();
|
|
19
|
+
const { isVertical, oppositeSide, isSnapRange, flattenSnapPoints } = useTrayUtils();
|
|
8
20
|
const emitter = useMagicEmitter();
|
|
9
21
|
const snapPoints = computed(() => state.options.snapPoints);
|
|
10
22
|
const animation = computed(() => state.options.animation);
|
|
@@ -43,53 +55,80 @@ export function useTraySnap(args) {
|
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
57
|
function mappedSnapPoints(side) {
|
|
46
|
-
const configured = snapPoints.value[side] ?? [];
|
|
47
|
-
const mapped = configured.map((snapPoint) => mapSnapPoint(side, snapPoint)).filter(
|
|
48
|
-
(value) => value === 0 || !!value && !Number.isNaN(value)
|
|
49
|
-
);
|
|
58
|
+
const configured = flattenSnapPoints(snapPoints.value[side] ?? []);
|
|
59
|
+
const mapped = configured.map((snapPoint) => mapSnapPoint(side, snapPoint)).filter(isMapped);
|
|
50
60
|
return [...new Set(mapped)].sort((a, b) => a - b);
|
|
51
61
|
}
|
|
52
62
|
function snapPointsMap(side) {
|
|
53
|
-
const configured = snapPoints.value[side] ?? [];
|
|
63
|
+
const configured = flattenSnapPoints(snapPoints.value[side] ?? []);
|
|
54
64
|
const map = {};
|
|
55
65
|
for (const snapPoint of configured) {
|
|
56
66
|
const mapped = mapSnapPoint(side, snapPoint);
|
|
57
|
-
if (mapped
|
|
67
|
+
if (isMapped(mapped)) {
|
|
58
68
|
map[mapped] = snapPoint;
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
return map;
|
|
62
72
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
73
|
+
function mappedRanges(side) {
|
|
74
|
+
const configured = snapPoints.value[side] ?? [];
|
|
75
|
+
return configured.filter(isSnapRange).flatMap((range) => {
|
|
76
|
+
const min = mapSnapPoint(side, range.min);
|
|
77
|
+
const max = mapSnapPoint(side, range.max);
|
|
78
|
+
if (!isMapped(min) || !isMapped(max)) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return [
|
|
82
|
+
{
|
|
83
|
+
min: Math.min(min, max),
|
|
84
|
+
max: Math.max(min, max),
|
|
85
|
+
momentum: range.momentum,
|
|
86
|
+
range
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function rangeAt(side, inset) {
|
|
92
|
+
return snapRangeAt({ ranges: mappedRanges(side), position: inset });
|
|
93
|
+
}
|
|
94
|
+
function snapPointAt(side, inset) {
|
|
95
|
+
const configured = snapPointsMap(side)[inset];
|
|
96
|
+
if (configured !== void 0) {
|
|
97
|
+
return configured;
|
|
98
|
+
}
|
|
99
|
+
const mapped = rangeAt(side, inset);
|
|
100
|
+
if (!mapped) {
|
|
65
101
|
return void 0;
|
|
66
102
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
103
|
+
const offset = inset - padding(side);
|
|
104
|
+
const { min, max } = mapped.range;
|
|
105
|
+
return typeof min === "number" && typeof max === "number" ? roundDecimal(offset / contentExtent(side)) : `${Math.round(offset)}px`;
|
|
106
|
+
}
|
|
107
|
+
function restingInset(side, inset) {
|
|
108
|
+
const range = rangeAt(side, inset);
|
|
109
|
+
const snapPoint = snapPointAt(side, inset);
|
|
110
|
+
if (!range || snapPoint === void 0) {
|
|
111
|
+
return inset;
|
|
75
112
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return void 0;
|
|
84
|
-
}
|
|
113
|
+
const mapped = mapSnapPoint(side, snapPoint);
|
|
114
|
+
return mapped === void 0 ? inset : clampValue(mapped, range.min, range.max);
|
|
115
|
+
}
|
|
116
|
+
function isSnapTarget(side, snapPoint) {
|
|
117
|
+
const mapped = mapSnapPoint(side, snapPoint);
|
|
118
|
+
if (mapped === void 0) {
|
|
119
|
+
return false;
|
|
85
120
|
}
|
|
86
|
-
return
|
|
87
|
-
(
|
|
121
|
+
return !!rangeAt(side, mapped) || mappedSnapPoints(side).some(
|
|
122
|
+
(point) => Math.abs(point - mapped) < SNAP_TOLERANCE
|
|
88
123
|
);
|
|
89
124
|
}
|
|
90
|
-
function
|
|
91
|
-
const
|
|
92
|
-
|
|
125
|
+
function findSnapTarget(side, inset) {
|
|
126
|
+
const target = snapTargetAt({
|
|
127
|
+
points: mappedSnapPoints(side),
|
|
128
|
+
ranges: mappedRanges(side),
|
|
129
|
+
value: inset
|
|
130
|
+
});
|
|
131
|
+
return target === void 0 ? void 0 : restingInset(side, target);
|
|
93
132
|
}
|
|
94
133
|
function interpolateDragged(args2) {
|
|
95
134
|
const {
|
|
@@ -98,8 +137,8 @@ export function useTraySnap(args) {
|
|
|
98
137
|
duration = toValue(animation).snap.duration,
|
|
99
138
|
easing = toValue(animation).snap.easing
|
|
100
139
|
} = args2;
|
|
101
|
-
const snapPoint =
|
|
102
|
-
if (
|
|
140
|
+
const snapPoint = snapPointAt(side, to);
|
|
141
|
+
if (snapPoint === void 0) {
|
|
103
142
|
interpolate({
|
|
104
143
|
from: state.dragged[side],
|
|
105
144
|
to,
|
|
@@ -115,6 +154,13 @@ export function useTraySnap(args) {
|
|
|
115
154
|
id: toValue(id),
|
|
116
155
|
snapPoint: { side, point: snapPoint }
|
|
117
156
|
});
|
|
157
|
+
if (state.dragged[side] === to) {
|
|
158
|
+
emitter.emit("afterSnap", {
|
|
159
|
+
id: toValue(id),
|
|
160
|
+
snapPoint: { side, point: snapPoint }
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
118
164
|
interpolate({
|
|
119
165
|
from: state.dragged[side],
|
|
120
166
|
to,
|
|
@@ -138,14 +184,14 @@ export function useTraySnap(args) {
|
|
|
138
184
|
if (mapped === void 0) {
|
|
139
185
|
return;
|
|
140
186
|
}
|
|
141
|
-
const closest =
|
|
187
|
+
const closest = findSnapTarget(side, mapped) ?? mapped;
|
|
188
|
+
state.snapped[side] = closest;
|
|
189
|
+
state.activeSnapPoint[side] = snapPointAt(side, closest) ?? snapPoint;
|
|
142
190
|
if (shouldInterpolate) {
|
|
143
191
|
interpolateDragged({ side, to: closest, duration });
|
|
144
192
|
} else {
|
|
145
193
|
state.dragged[side] = closest;
|
|
146
194
|
}
|
|
147
|
-
state.snapped[side] = closest;
|
|
148
|
-
state.activeSnapPoint[side] = snapPoint;
|
|
149
195
|
}
|
|
150
196
|
return {
|
|
151
197
|
dimension,
|
|
@@ -154,8 +200,12 @@ export function useTraySnap(args) {
|
|
|
154
200
|
maxInset,
|
|
155
201
|
mapSnapPoint,
|
|
156
202
|
mappedSnapPoints,
|
|
157
|
-
|
|
158
|
-
|
|
203
|
+
mappedRanges,
|
|
204
|
+
rangeAt,
|
|
205
|
+
snapPointAt,
|
|
206
|
+
restingInset,
|
|
207
|
+
isSnapTarget,
|
|
208
|
+
findSnapTarget,
|
|
159
209
|
interpolateDragged,
|
|
160
210
|
snapTo
|
|
161
211
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { MagicTraySide } from '../../types/index.js';
|
|
1
|
+
import type { MagicTraySide, MagicTraySnapEntry, MagicTraySnapRange } from '../../types/index.js';
|
|
2
2
|
export declare function useTrayUtils(): {
|
|
3
3
|
clampWithOvershoot: (value: number, min: number, max: number, outer: number, inner: number) => any;
|
|
4
4
|
isVertical: (side: MagicTraySide) => side is "top" | "bottom";
|
|
5
5
|
oppositeSide: (side: MagicTraySide) => MagicTraySide;
|
|
6
|
+
isSnapRange: (entry: MagicTraySnapEntry) => entry is MagicTraySnapRange;
|
|
7
|
+
flattenSnapPoints: (entries: Array<MagicTraySnapEntry>) => import("../../types/index.js").MagicTraySnapPoint[];
|
|
6
8
|
};
|
|
@@ -24,9 +24,19 @@ export function useTrayUtils() {
|
|
|
24
24
|
return "left";
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
function isSnapRange(entry) {
|
|
28
|
+
return typeof entry === "object";
|
|
29
|
+
}
|
|
30
|
+
function flattenSnapPoints(entries) {
|
|
31
|
+
return entries.flatMap(
|
|
32
|
+
(entry) => isSnapRange(entry) ? [entry.min, entry.max] : [entry]
|
|
33
|
+
);
|
|
34
|
+
}
|
|
27
35
|
return {
|
|
28
36
|
clampWithOvershoot,
|
|
29
37
|
isVertical,
|
|
30
|
-
oppositeSide
|
|
38
|
+
oppositeSide,
|
|
39
|
+
isSnapRange,
|
|
40
|
+
flattenSnapPoints
|
|
31
41
|
};
|
|
32
42
|
}
|
|
@@ -2,6 +2,12 @@ import type { RequireAllNested } from '@maas/vue-equipment/utils';
|
|
|
2
2
|
import type { EasingKey } from '@maas/vue-equipment/composables/useEasings';
|
|
3
3
|
export type MagicTraySide = 'top' | 'right' | 'bottom' | 'left';
|
|
4
4
|
export type MagicTraySnapPoint = number | `${number}px`;
|
|
5
|
+
export interface MagicTraySnapRange {
|
|
6
|
+
min: MagicTraySnapPoint;
|
|
7
|
+
max: MagicTraySnapPoint;
|
|
8
|
+
momentum?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export type MagicTraySnapEntry = MagicTraySnapPoint | MagicTraySnapRange;
|
|
5
11
|
export interface MagicTraySnapPointPayload {
|
|
6
12
|
side: MagicTraySide;
|
|
7
13
|
point: MagicTraySnapPoint;
|
|
@@ -12,7 +18,7 @@ export interface MagicTraySidePayload {
|
|
|
12
18
|
}
|
|
13
19
|
export type MagicTraySnapMode = 'closest' | 'step';
|
|
14
20
|
export type MagicTrayDragMode = 'free' | 'snap';
|
|
15
|
-
export type TraySnapPoints = Partial<Record<MagicTraySide,
|
|
21
|
+
export type TraySnapPoints = Partial<Record<MagicTraySide, Array<MagicTraySnapEntry>>>;
|
|
16
22
|
export type TrayMagneticDirection = 'inner' | 'outer' | 'both';
|
|
17
23
|
export type TrayMagneticSide = Partial<Record<MagicTraySnapPoint, TrayMagneticDirection>>;
|
|
18
24
|
export type TrayMagneticSides = false | Partial<Record<MagicTraySide, TrayMagneticSide>>;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -88,6 +88,51 @@ interface SlugifyOptions {
|
|
|
88
88
|
}
|
|
89
89
|
declare function slugify(string: string, options?: SlugifyOptions): string;
|
|
90
90
|
|
|
91
|
+
type SnapRange = {
|
|
92
|
+
min: number;
|
|
93
|
+
max: number;
|
|
94
|
+
momentum?: boolean;
|
|
95
|
+
};
|
|
96
|
+
type SnapDirection = 'below' | 'above';
|
|
97
|
+
type SnapMode = 'closest' | 'step';
|
|
98
|
+
type SnapDrag = {
|
|
99
|
+
points: Array<number>;
|
|
100
|
+
ranges: Array<SnapRange>;
|
|
101
|
+
mode: SnapMode;
|
|
102
|
+
rest: number;
|
|
103
|
+
start: number;
|
|
104
|
+
position: number;
|
|
105
|
+
};
|
|
106
|
+
type SnapRangeAtArgs<RangeType extends SnapRange> = {
|
|
107
|
+
ranges: Array<RangeType>;
|
|
108
|
+
position: number;
|
|
109
|
+
};
|
|
110
|
+
type ClosestSnapPointArgs = {
|
|
111
|
+
points: Array<number>;
|
|
112
|
+
value: number;
|
|
113
|
+
direction?: SnapDirection | 'absolute';
|
|
114
|
+
};
|
|
115
|
+
type SnapTargetAtArgs = {
|
|
116
|
+
points: Array<number>;
|
|
117
|
+
ranges: Array<SnapRange>;
|
|
118
|
+
value: number;
|
|
119
|
+
};
|
|
120
|
+
type SnapCommitArgs = SnapDrag & {
|
|
121
|
+
distance: number;
|
|
122
|
+
flicked: boolean;
|
|
123
|
+
flickDirection?: SnapDirection;
|
|
124
|
+
};
|
|
125
|
+
type SnapReleaseArgs = SnapDrag & {
|
|
126
|
+
committed: number | undefined;
|
|
127
|
+
flicked: boolean;
|
|
128
|
+
tapped: boolean;
|
|
129
|
+
};
|
|
130
|
+
declare function snapRangeAt<RangeType extends SnapRange>(args: SnapRangeAtArgs<RangeType>): RangeType | undefined;
|
|
131
|
+
declare function closestSnapPoint(args: ClosestSnapPointArgs): number | undefined;
|
|
132
|
+
declare function snapTargetAt(args: SnapTargetAtArgs): number | undefined;
|
|
133
|
+
declare function snapCommit(args: SnapCommitArgs): number | undefined;
|
|
134
|
+
declare function snapRelease(args: SnapReleaseArgs): number;
|
|
135
|
+
|
|
91
136
|
declare function uniq<T extends unknown[]>(a: T): unknown[];
|
|
92
137
|
|
|
93
138
|
type PickPartial<T, K extends keyof T> = {
|
|
@@ -100,4 +145,4 @@ type RequireAllNested<T> = {
|
|
|
100
145
|
|
|
101
146
|
type ValueOf<T> = T[keyof T];
|
|
102
147
|
|
|
103
|
-
export { type CreateStore, type InterpolateArgs, type PickPartial, type RequireAllNested, type SlugifyOptions, type ValueOf, cancelEdgeNavigation, clampValue, convertToPixels, createStateStore, easeInCubic, easeInOutCubic, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInQuad, easeInQuart, easeInQuint, easeOutBack, easeOutCubic, easeOutQuad, easeOutQuart, easeOutQuint, formatTime, guardedReleasePointerCapture, guardedSetPointerCapture, hasEdgeNavigationGestures, interpolate, isAndroid, isIOS, isWithinRange, linear, lockSelection, mapValue, matchClass, rubberband, scrollbarGutterSupport, scrollbarWidth, slugify, uniq };
|
|
148
|
+
export { type CreateStore, type InterpolateArgs, type PickPartial, type RequireAllNested, type SlugifyOptions, type SnapDirection, type SnapDrag, type SnapMode, type SnapRange, type ValueOf, cancelEdgeNavigation, clampValue, closestSnapPoint, convertToPixels, createStateStore, easeInCubic, easeInOutCubic, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInQuad, easeInQuart, easeInQuint, easeOutBack, easeOutCubic, easeOutQuad, easeOutQuart, easeOutQuint, formatTime, guardedReleasePointerCapture, guardedSetPointerCapture, hasEdgeNavigationGestures, interpolate, isAndroid, isIOS, isWithinRange, linear, lockSelection, mapValue, matchClass, rubberband, scrollbarGutterSupport, scrollbarWidth, slugify, snapCommit, snapRangeAt, snapRelease, snapTargetAt, uniq };
|