@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.
Files changed (24) hide show
  1. package/dist/nuxt/module.json +1 -1
  2. package/dist/nuxt/module.mjs +2 -2
  3. package/dist/plugins/MagicDrawer/index.d.ts +2 -2
  4. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerDrag.mjs +127 -168
  5. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.d.ts +16 -11
  6. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerSnap.mjs +178 -175
  7. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerState.mjs +2 -1
  8. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerUtils.d.ts +3 -0
  9. package/dist/plugins/MagicDrawer/src/composables/private/useDrawerUtils.mjs +11 -1
  10. package/dist/plugins/MagicDrawer/src/composables/useMagicDrawer.d.ts +1 -0
  11. package/dist/plugins/MagicDrawer/src/composables/useMagicDrawer.mjs +2 -1
  12. package/dist/plugins/MagicDrawer/src/types/index.d.ts +8 -1
  13. package/dist/plugins/MagicTray/index.d.ts +2 -2
  14. package/dist/plugins/MagicTray/src/composables/private/useTrayDrag.mjs +99 -51
  15. package/dist/plugins/MagicTray/src/composables/private/useTrayMagnetism.mjs +3 -1
  16. package/dist/plugins/MagicTray/src/composables/private/useTraySnap.d.ts +12 -7
  17. package/dist/plugins/MagicTray/src/composables/private/useTraySnap.mjs +89 -39
  18. package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.d.ts +3 -1
  19. package/dist/plugins/MagicTray/src/composables/private/useTrayUtils.mjs +11 -1
  20. package/dist/plugins/MagicTray/src/types/index.d.ts +7 -1
  21. package/dist/utils/index.d.ts +46 -1
  22. package/dist/utils/index.js +75 -0
  23. package/dist/utils/index.js.map +1 -1
  24. 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
- snapPointsMap,
49
- findClosestSnapPoint,
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 ? snapPointsMap(side)[points[0]] : void 0;
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 snapReference(side) {
90
- return snapMode.value === "step" ? state.lastDragged[side] : state.dragged[side];
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 = findClosestSnapPoint({ side, value: inset });
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] = snapPoint;
222
- if (snapPoint || snapPoint === 0) {
223
- emitter.emit("beforeSnap", {
224
- id: toValue(id),
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 checkPosition(side) {
234
- const delta = state.dragged[side] - state.lastDragged[side];
235
- if (Math.abs(delta) > toValue(threshold).distance) {
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 = state.interpolateTo ?? state.snapped[side];
247
- if (target === lastPendingTarget) {
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 = target;
251
- const snapPoint = snapPointsMap(side)[target];
252
- if (!snapPoint && snapPoint !== 0) {
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
- if (velocity > toValue(threshold).momentum) {
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
- if (state.interpolateTo || state.interpolateTo === 0) {
290
- interpolateDragged({ side, to: state.interpolateTo });
291
- state.snapped[side] = state.interpolateTo;
292
- state.activeSnapPoint[side] = snapPointsMap(side)[state.interpolateTo];
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 (!isSnapDrag(side)) {
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 (!isSnapDrag(side)) {
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 initial = state.options.initial.snapPoints?.[side] ?? openSnapPoint(side);
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 FindClosestSnapPointArgs = {
20
- side: MagicTraySide;
21
- value: number;
22
- direction?: 'below' | 'above' | 'absolute';
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
- snapPointsMap: (side: MagicTraySide) => Record<number, MagicTraySnapPoint>;
32
- findClosestSnapPoint: (args: FindClosestSnapPointArgs) => number | undefined;
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 { clampValue, interpolate } from "@maas/vue-equipment/utils";
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 || mapped === 0) {
67
+ if (isMapped(mapped)) {
58
68
  map[mapped] = snapPoint;
59
69
  }
60
70
  }
61
71
  return map;
62
72
  }
63
- function findClosestNumber(value, numbers, direction) {
64
- if (!numbers.length) {
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
- let filtered = numbers;
68
- switch (direction) {
69
- case "above":
70
- filtered = numbers.filter((num) => num > value);
71
- break;
72
- case "below":
73
- filtered = numbers.filter((num) => num < value);
74
- break;
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
- if (filtered.length === 0) {
77
- switch (direction) {
78
- case "above":
79
- return Math.max(...numbers);
80
- case "below":
81
- return Math.min(...numbers);
82
- default:
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 filtered.reduce(
87
- (closest, current) => Math.abs(current - value) < Math.abs(closest - value) ? current : closest
121
+ return !!rangeAt(side, mapped) || mappedSnapPoints(side).some(
122
+ (point) => Math.abs(point - mapped) < SNAP_TOLERANCE
88
123
  );
89
124
  }
90
- function findClosestSnapPoint(args2) {
91
- const { side, value, direction = "absolute" } = args2;
92
- return findClosestNumber(value, mappedSnapPoints(side), direction);
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 = snapPointsMap(side)[to];
102
- if (!snapPoint && snapPoint !== 0) {
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 = findClosestSnapPoint({ side, value: mapped }) ?? mapped;
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
- snapPointsMap,
158
- findClosestSnapPoint,
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, MagicTraySnapPoint[]>>;
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>>;
@@ -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 };