@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
@@ -1,7 +1,20 @@
1
1
  import { computed, nextTick, shallowRef, toValue } from "vue";
2
- import { computedWithControl } from "@vueuse/core";
3
- import { interpolate, mapValue } from "@maas/vue-equipment/utils";
2
+ import {
3
+ clampValue,
4
+ interpolate,
5
+ mapValue,
6
+ snapRangeAt,
7
+ snapTargetAt
8
+ } from "@maas/vue-equipment/utils";
4
9
  import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
10
+ import { useDrawerUtils } from "./useDrawerUtils.mjs";
11
+ const SNAP_TOLERANCE = 0.01;
12
+ function isMapped(value) {
13
+ return value !== void 0 && !Number.isNaN(value);
14
+ }
15
+ function roundDecimal(value) {
16
+ return Math.round(value * 1e4) / 1e4;
17
+ }
5
18
  export function useDrawerSnap(args) {
6
19
  const {
7
20
  id,
@@ -12,43 +25,21 @@ export function useDrawerSnap(args) {
12
25
  overshoot,
13
26
  draggedY,
14
27
  draggedX,
28
+ activeSnapPoint,
15
29
  preventDragClose
16
30
  } = args;
17
- const mappedSnapPoints = computedWithControl(
18
- () => toValue(wrapperRect),
19
- () => {
20
- const extended = toValue(preventDragClose) ? toValue(snapPoints) : [...toValue(snapPoints), 0];
21
- const mapped = extended.map((snapPoint) => {
22
- return mapSnapPoint(snapPoint);
23
- });
24
- const filtered = mapped.filter(
25
- (snapPoint) => !!snapPoint || snapPoint === 0
26
- ).sort((a, b) => a - b);
27
- return filtered;
28
- }
29
- );
30
- const snapPointsMap = computedWithControl(
31
- () => toValue(snapPoints),
32
- () => {
33
- const extended = toValue(preventDragClose) ? toValue(snapPoints) : [...toValue(snapPoints), 0];
34
- const mapped = extended.reduce(
35
- (acc, current) => {
36
- const key = mapSnapPoint(current);
37
- if (key || key === 0) {
38
- acc[key] = current;
39
- }
40
- return acc;
41
- },
42
- {}
43
- );
44
- return mapped;
45
- }
46
- );
31
+ const { isSnapRange, flattenSnapPoints } = useDrawerUtils();
32
+ const emitter = useMagicEmitter();
33
+ const isVertical = computed(() => {
34
+ const side = toValue(position);
35
+ return side === "top" || side === "bottom";
36
+ });
37
+ const configuredPoints = computed(() => {
38
+ const flattened = flattenSnapPoints(toValue(snapPoints));
39
+ return toValue(preventDragClose) ? flattened : [...flattened, 0];
40
+ });
47
41
  const snappedY = shallowRef(0);
48
42
  const snappedX = shallowRef(0);
49
- const activeSnapPoint = shallowRef(
50
- void 0
51
- );
52
43
  const drawerHeight = computed(() => {
53
44
  const rect = toValue(wrapperRect);
54
45
  if (rect === void 0) {
@@ -63,36 +54,27 @@ export function useDrawerSnap(args) {
63
54
  }
64
55
  return rect.width - toValue(overshoot);
65
56
  });
66
- const emitter = useMagicEmitter();
67
- function findClosestNumber(args2) {
68
- const { number, numbers, direction } = args2;
69
- let filtered = numbers;
70
- if (!numbers.length) {
71
- return void 0;
72
- }
73
- switch (direction) {
74
- case "above":
75
- filtered = numbers.filter((num) => num > number);
76
- break;
77
- case "below":
78
- filtered = numbers.filter((num) => num < number);
79
- break;
80
- }
81
- if (filtered.length === 0) {
82
- switch (direction) {
83
- case "above":
84
- return Math.max(...numbers);
85
- case "below":
86
- return Math.min(...numbers);
87
- default:
88
- return void 0;
57
+ const mappedSnapPoints = computed(() => {
58
+ const mapped = configuredPoints.value.map(mapSnapPoint).filter(isMapped);
59
+ return [...new Set(mapped)].sort((a, b) => a - b);
60
+ });
61
+ const mappedRanges = computed(
62
+ () => toValue(snapPoints).filter(isSnapRange).flatMap((range) => {
63
+ const min = mapSnapPoint(range.min);
64
+ const max = mapSnapPoint(range.max);
65
+ if (!isMapped(min) || !isMapped(max)) {
66
+ return [];
89
67
  }
90
- }
91
- const closestNumber = filtered.reduce(
92
- (closest, current) => Math.abs(current - number) < Math.abs(closest - number) ? current : closest
93
- );
94
- return closestNumber;
95
- }
68
+ return [
69
+ {
70
+ min: Math.min(min, max),
71
+ max: Math.max(min, max),
72
+ momentum: range.momentum,
73
+ range
74
+ }
75
+ ];
76
+ })
77
+ );
96
78
  function mapSnapPoint(snapPoint) {
97
79
  if (typeof snapPoint === "number") {
98
80
  const reversedSnapPoint = mapValue(snapPoint, 0, 1, 1, 0);
@@ -176,49 +158,116 @@ export function useDrawerSnap(args) {
176
158
  }
177
159
  }
178
160
  }
179
- async function snapTo(args2) {
180
- const { snapPoint, interpolate: interpolate2, duration } = args2;
181
- await nextTick();
161
+ function decimalAt(offset) {
162
+ const rect = toValue(wrapperRect);
163
+ if (!rect) {
164
+ return 0;
165
+ }
182
166
  switch (position) {
167
+ case "bottom":
168
+ return 1 - (offset + rect.top) / window.innerHeight;
183
169
  case "top":
184
- case "bottom": {
185
- const mappedSnapPointY = mapSnapPoint(snapPoint);
186
- if (!mappedSnapPointY && mappedSnapPointY !== 0) {
187
- return;
188
- }
189
- const closestY = findClosestSnapPoint({
190
- draggedX,
191
- draggedY: mappedSnapPointY
192
- }) || 0;
193
- if (interpolate2) {
194
- interpolateDragged({ to: closestY, duration });
195
- } else {
196
- draggedY.value = closestY;
197
- }
198
- snappedY.value = closestY;
199
- activeSnapPoint.value = toValue(snapPoint);
200
- break;
201
- }
170
+ return 1 - (offset + rect.bottom) / window.innerHeight;
171
+ case "right":
172
+ return 1 - (offset + rect.left) / window.innerWidth;
202
173
  case "left":
203
- case "right": {
204
- const mappedSnapPointX = mapSnapPoint(toValue(snapPoint));
205
- if (!mappedSnapPointX && mappedSnapPointX !== 0) {
206
- return;
207
- }
208
- const closestX = findClosestSnapPoint({
209
- draggedX: mappedSnapPointX,
210
- draggedY
211
- }) || 0;
212
- if (interpolate2) {
213
- interpolateDragged({ to: closestX, duration });
214
- } else {
215
- draggedX.value = closestX;
216
- snappedX.value = closestX;
217
- }
218
- snappedX.value = closestX;
219
- activeSnapPoint.value = toValue(snapPoint);
220
- break;
221
- }
174
+ return 1 - (offset + rect.right) / window.innerWidth;
175
+ default:
176
+ return 0;
177
+ }
178
+ }
179
+ function pixelsAt(offset) {
180
+ switch (position) {
181
+ case "bottom":
182
+ return drawerHeight.value - offset;
183
+ case "top":
184
+ return drawerHeight.value + offset;
185
+ case "right":
186
+ return drawerWidth.value - offset;
187
+ case "left":
188
+ return drawerWidth.value + offset;
189
+ default:
190
+ return offset;
191
+ }
192
+ }
193
+ function configuredPointAt(offset) {
194
+ return configuredPoints.value.find((snapPoint) => {
195
+ const mapped = mapSnapPoint(snapPoint);
196
+ return isMapped(mapped) && Math.abs(mapped - offset) < SNAP_TOLERANCE;
197
+ });
198
+ }
199
+ function draggedOnAxis() {
200
+ return isVertical.value ? draggedY.value : draggedX.value;
201
+ }
202
+ function setDraggedOnAxis(value) {
203
+ if (isVertical.value) {
204
+ draggedY.value = value;
205
+ } else {
206
+ draggedX.value = value;
207
+ }
208
+ }
209
+ function setSnappedOnAxis(value) {
210
+ if (isVertical.value) {
211
+ snappedY.value = value;
212
+ } else {
213
+ snappedX.value = value;
214
+ }
215
+ }
216
+ function rangeAt(offset) {
217
+ return snapRangeAt({ ranges: mappedRanges.value, position: offset });
218
+ }
219
+ function snapPointAt(offset) {
220
+ const configured = configuredPointAt(offset);
221
+ if (configured !== void 0) {
222
+ return configured;
223
+ }
224
+ const mapped = rangeAt(offset);
225
+ if (!mapped) {
226
+ return void 0;
227
+ }
228
+ const { min, max } = mapped.range;
229
+ return typeof min === "number" && typeof max === "number" ? roundDecimal(decimalAt(offset)) : `${Math.round(pixelsAt(offset))}px`;
230
+ }
231
+ function restingOffset(offset) {
232
+ const range = rangeAt(offset);
233
+ const snapPoint = snapPointAt(offset);
234
+ if (!range || snapPoint === void 0) {
235
+ return offset;
236
+ }
237
+ const mapped = mapSnapPoint(snapPoint);
238
+ return isMapped(mapped) ? clampValue(mapped, range.min, range.max) : offset;
239
+ }
240
+ function isSnapTarget(snapPoint) {
241
+ const mapped = mapSnapPoint(snapPoint);
242
+ if (!isMapped(mapped)) {
243
+ return false;
244
+ }
245
+ return !!rangeAt(mapped) || mappedSnapPoints.value.some(
246
+ (point) => Math.abs(point - mapped) < SNAP_TOLERANCE
247
+ );
248
+ }
249
+ function findSnapTarget(offset) {
250
+ const target = snapTargetAt({
251
+ points: mappedSnapPoints.value,
252
+ ranges: mappedRanges.value,
253
+ value: offset
254
+ });
255
+ return target === void 0 ? void 0 : restingOffset(target);
256
+ }
257
+ async function snapTo(args2) {
258
+ const { snapPoint, interpolate: shouldInterpolate, duration } = args2;
259
+ await nextTick();
260
+ const mapped = mapSnapPoint(snapPoint);
261
+ if (!isMapped(mapped)) {
262
+ return;
263
+ }
264
+ const closest = findSnapTarget(mapped) ?? 0;
265
+ setSnappedOnAxis(closest);
266
+ activeSnapPoint.value = snapPointAt(closest) ?? snapPoint;
267
+ if (shouldInterpolate) {
268
+ interpolateDragged({ to: closest, duration });
269
+ } else {
270
+ setDraggedOnAxis(closest);
222
271
  }
223
272
  }
224
273
  function interpolateDragged(args2) {
@@ -227,86 +276,40 @@ export function useDrawerSnap(args) {
227
276
  duration = toValue(animation).snap.duration,
228
277
  easing = toValue(animation).snap.easing
229
278
  } = args2;
230
- const snapPoint = snapPointsMap.value[to];
231
- if (!snapPoint && snapPoint !== 0) {
279
+ const snapPoint = snapPointAt(to);
280
+ if (snapPoint === void 0) {
232
281
  return;
233
282
  }
234
283
  emitter.emit("beforeSnap", { id: toValue(id), snapPoint });
235
- switch (position) {
236
- case "bottom":
237
- case "top":
238
- interpolate({
239
- from: draggedY.value,
240
- to,
241
- duration,
242
- easing,
243
- callback: (value) => {
244
- draggedY.value = value;
245
- if (draggedY.value === to) {
246
- emitter.emit("afterSnap", {
247
- id: toValue(id),
248
- snapPoint
249
- });
250
- }
251
- }
252
- });
253
- break;
254
- case "right":
255
- case "left":
256
- interpolate({
257
- from: draggedX.value,
258
- to,
259
- duration,
260
- easing,
261
- callback: (value) => {
262
- draggedX.value = value;
263
- if (draggedX.value === to) {
264
- emitter.emit("afterSnap", {
265
- id: toValue(id),
266
- snapPoint
267
- });
268
- }
269
- }
270
- });
271
- break;
284
+ if (draggedOnAxis() === to) {
285
+ emitter.emit("afterSnap", { id: toValue(id), snapPoint });
286
+ return;
272
287
  }
273
- }
274
- function findClosestSnapPoint(args2) {
275
- const { draggedY: draggedY2, draggedX: draggedX2, direction = "absolute" } = args2;
276
- let closest = void 0;
277
- switch (position) {
278
- case "bottom":
279
- case "top":
280
- if (!!toValue(draggedY2) || toValue(draggedY2) === 0) {
281
- closest = findClosestNumber({
282
- number: toValue(draggedY2),
283
- numbers: mappedSnapPoints.value,
284
- direction
285
- });
286
- }
287
- break;
288
- case "right":
289
- case "left":
290
- if (!!toValue(draggedX2) || toValue(draggedX2) === 0) {
291
- closest = findClosestNumber({
292
- number: toValue(draggedX2),
293
- numbers: mappedSnapPoints.value,
294
- direction
295
- });
288
+ interpolate({
289
+ from: draggedOnAxis(),
290
+ to,
291
+ duration,
292
+ easing,
293
+ callback: (value) => {
294
+ setDraggedOnAxis(value);
295
+ if (value === to) {
296
+ emitter.emit("afterSnap", { id: toValue(id), snapPoint });
296
297
  }
297
- break;
298
- }
299
- return closest;
298
+ }
299
+ });
300
300
  }
301
301
  return {
302
302
  snappedY,
303
303
  snappedX,
304
- activeSnapPoint,
305
- snapTo,
306
- findClosestSnapPoint,
307
- interpolateDragged,
308
- snapPointsMap,
309
304
  drawerHeight,
310
- drawerWidth
305
+ drawerWidth,
306
+ mappedSnapPoints,
307
+ mappedRanges,
308
+ rangeAt,
309
+ snapPointAt,
310
+ restingOffset,
311
+ isSnapTarget,
312
+ snapTo,
313
+ interpolateDragged
311
314
  };
312
315
  }
@@ -38,7 +38,8 @@ export function useDrawerState(id) {
38
38
  absDirectionX: void 0,
39
39
  elRect: void 0,
40
40
  wrapperRect: void 0,
41
- progress: { x: 0, y: 0 }
41
+ progress: { x: 0, y: 0 },
42
+ activeSnapPoint: void 0
42
43
  };
43
44
  return reactive(state);
44
45
  }
@@ -1,3 +1,6 @@
1
+ import type { MagicDrawerSnapEntry, MagicDrawerSnapRange } from '../../types/index.js';
1
2
  export declare function useDrawerUtils(): {
2
3
  clamp: (value: number, from: number, to: number, flip: boolean) => any;
4
+ isSnapRange: (entry: MagicDrawerSnapEntry) => entry is MagicDrawerSnapRange;
5
+ flattenSnapPoints: (entries: Array<MagicDrawerSnapEntry>) => import("../../types/index.js").MagicDrawerSnapPoint[];
3
6
  };
@@ -10,7 +10,17 @@ export function useDrawerUtils() {
10
10
  return flip ? Math.min(value, to) : Math.max(value, to);
11
11
  }
12
12
  }
13
+ function isSnapRange(entry) {
14
+ return typeof entry === "object";
15
+ }
16
+ function flattenSnapPoints(entries) {
17
+ return entries.flatMap(
18
+ (entry) => isSnapRange(entry) ? [entry.min, entry.max] : [entry]
19
+ );
20
+ }
13
21
  return {
14
- clamp
22
+ clamp,
23
+ isSnapRange,
24
+ flattenSnapPoints
15
25
  };
16
26
  }
@@ -3,6 +3,7 @@ import type { MagicDrawerOptions, MagicDrawerSnapPoint } from '../types/index.js
3
3
  export declare function useMagicDrawer(id: MaybeRef<string>, options?: MagicDrawerOptions): {
4
4
  isActive: import("vue").ComputedRef<any>;
5
5
  progress: any;
6
+ activeSnapPoint: any;
6
7
  state: any;
7
8
  open: () => void;
8
9
  close: () => void;
@@ -4,7 +4,7 @@ import { useDrawerState } from "./private/useDrawerState.mjs";
4
4
  export function useMagicDrawer(id, options) {
5
5
  const { initializeState } = useDrawerState(toValue(id));
6
6
  const state = initializeState(options);
7
- const { progress, active } = toRefs(state);
7
+ const { progress, active, activeSnapPoint } = toRefs(state);
8
8
  const emitter = useMagicEmitter();
9
9
  const isActive = computed(() => active.value);
10
10
  function open() {
@@ -23,6 +23,7 @@ export function useMagicDrawer(id, options) {
23
23
  return {
24
24
  isActive,
25
25
  progress,
26
+ activeSnapPoint,
26
27
  state,
27
28
  open,
28
29
  close,
@@ -1,6 +1,12 @@
1
1
  import type { Options as FocusTrapOptions } from 'focus-trap';
2
2
  import type { RequireAllNested } from '@maas/vue-equipment/utils';
3
3
  export type MagicDrawerSnapPoint = number | `${number}px`;
4
+ export interface MagicDrawerSnapRange {
5
+ min: MagicDrawerSnapPoint;
6
+ max: MagicDrawerSnapPoint;
7
+ momentum?: boolean;
8
+ }
9
+ export type MagicDrawerSnapEntry = MagicDrawerSnapPoint | MagicDrawerSnapRange;
4
10
  export type DrawerSnapMode = 'closest' | 'step';
5
11
  export interface MagicDrawerOptions {
6
12
  position?: 'top' | 'right' | 'bottom' | 'left';
@@ -9,7 +15,7 @@ export interface MagicDrawerOptions {
9
15
  scrollLock?: boolean | {
10
16
  padding: boolean;
11
17
  };
12
- snapPoints?: MagicDrawerSnapPoint[];
18
+ snapPoints?: Array<MagicDrawerSnapEntry>;
13
19
  snap?: {
14
20
  mode?: DrawerSnapMode;
15
21
  };
@@ -64,6 +70,7 @@ export interface DrawerState {
64
70
  x: number;
65
71
  y: number;
66
72
  };
73
+ activeSnapPoint: MagicDrawerSnapPoint | undefined;
67
74
  shouldClose: boolean;
68
75
  interpolateTo: number | undefined;
69
76
  originX: number;
@@ -5,7 +5,7 @@ import MagicTrayHandle from './src/components/MagicTrayHandle.vue.js';
5
5
  import MagicTrayTransform from './src/components/MagicTrayTransform.vue.js';
6
6
  import { useMagicTray } from './src/composables/useMagicTray.js';
7
7
  import type { Plugin } from 'vue';
8
- import type { MagicTrayDragMode, MagicTrayOptions, MagicTraySide, MagicTraySidePayload, MagicTraySnapMode, MagicTraySnapPoint, MagicTraySnapPointPayload, MagicTrayTransformAxis, MagicTrayWillSnapToPayload } from './src/types/index.js';
8
+ import type { MagicTrayDragMode, MagicTrayOptions, MagicTraySide, MagicTraySidePayload, MagicTraySnapEntry, MagicTraySnapMode, MagicTraySnapPoint, MagicTraySnapPointPayload, MagicTraySnapRange, MagicTrayTransformAxis, MagicTrayWillSnapToPayload } from './src/types/index.js';
9
9
  declare const MagicTrayPlugin: Plugin;
10
10
  export { MagicTrayPlugin, MagicTray, MagicTrayProvider, MagicTrayContent, MagicTrayHandle, MagicTrayTransform, useMagicTray, };
11
- export type { MagicTrayOptions, MagicTraySide, MagicTraySidePayload, MagicTraySnapMode, MagicTrayDragMode, MagicTraySnapPoint, MagicTraySnapPointPayload, MagicTrayWillSnapToPayload, MagicTrayTransformAxis, };
11
+ export type { MagicTrayOptions, MagicTraySide, MagicTraySidePayload, MagicTraySnapMode, MagicTrayDragMode, MagicTraySnapPoint, MagicTraySnapRange, MagicTraySnapEntry, MagicTraySnapPointPayload, MagicTrayWillSnapToPayload, MagicTrayTransformAxis, };