@maas/vue-equipment 1.4.0 → 1.5.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.
@@ -0,0 +1,18 @@
1
+ import * as vue from 'vue';
2
+ import { MaybeRefOrGetter } from 'vue';
3
+
4
+ type TouchIntent = 'scroll' | 'swipe';
5
+ type TouchIntentAxis = 'x' | 'y';
6
+ interface UseTouchIntentOptions {
7
+ target?: MaybeRefOrGetter<Element | Document | null | undefined>;
8
+ axis?: MaybeRefOrGetter<TouchIntentAxis>;
9
+ threshold?: MaybeRefOrGetter<number>;
10
+ }
11
+ declare function useTouchIntent(options?: UseTouchIntentOptions): {
12
+ intent: Readonly<vue.Ref<TouchIntent | undefined, TouchIntent | undefined>>;
13
+ isScrolling: vue.ComputedRef<boolean>;
14
+ isSwiping: vue.ComputedRef<boolean>;
15
+ };
16
+ type UseTouchIntentReturn = ReturnType<typeof useTouchIntent>;
17
+
18
+ export { type TouchIntent, type TouchIntentAxis, type UseTouchIntentOptions, type UseTouchIntentReturn, useTouchIntent };
@@ -0,0 +1,74 @@
1
+ // useTouchIntent/index.ts
2
+ import { computed, readonly, ref, toValue } from "vue";
3
+ import {
4
+ defaultDocument,
5
+ tryOnScopeDispose,
6
+ useEventListener
7
+ } from "@vueuse/core";
8
+ var endEvents = ["pointerup", "pointercancel", "touchend", "touchcancel"];
9
+ function useTouchIntent(options = {}) {
10
+ const { target, axis = "y", threshold = 8 } = options;
11
+ let pressX = 0;
12
+ let pressY = 0;
13
+ let cancelMove = void 0;
14
+ let cancelEnd = void 0;
15
+ const intent = ref(void 0);
16
+ const isScrolling = computed(() => intent.value === "scroll");
17
+ const isSwiping = computed(() => intent.value === "swipe");
18
+ function end() {
19
+ cancelMove?.();
20
+ cancelEnd?.();
21
+ cancelMove = void 0;
22
+ cancelEnd = void 0;
23
+ intent.value = void 0;
24
+ }
25
+ function onPointermove(e) {
26
+ if (intent.value || e.isTrusted && !e.isPrimary) {
27
+ return;
28
+ }
29
+ const dx = Math.abs(e.clientX - pressX);
30
+ const dy = Math.abs(e.clientY - pressY);
31
+ const vertical = toValue(axis) === "y";
32
+ const along = vertical ? dy : dx;
33
+ const across = vertical ? dx : dy;
34
+ const limit = toValue(threshold);
35
+ if (along > limit && along > across) {
36
+ intent.value = "scroll";
37
+ } else if (across > limit && across > along) {
38
+ intent.value = "swipe";
39
+ }
40
+ }
41
+ function onPointerdown(e) {
42
+ if (e.isTrusted && !e.isPrimary) {
43
+ return;
44
+ }
45
+ end();
46
+ pressX = e.clientX;
47
+ pressY = e.clientY;
48
+ cancelMove = useEventListener(
49
+ defaultDocument,
50
+ "pointermove",
51
+ onPointermove,
52
+ { capture: true }
53
+ );
54
+ cancelEnd = useEventListener(defaultDocument, endEvents, end, {
55
+ capture: true
56
+ });
57
+ }
58
+ useEventListener(
59
+ () => toValue(target) ?? defaultDocument,
60
+ "pointerdown",
61
+ onPointerdown,
62
+ { capture: true }
63
+ );
64
+ tryOnScopeDispose(end);
65
+ return {
66
+ intent: readonly(intent),
67
+ isScrolling,
68
+ isSwiping
69
+ };
70
+ }
71
+ export {
72
+ useTouchIntent
73
+ };
74
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/composables/useTouchIntent/index.ts"],"sourcesContent":["import { computed, readonly, ref, toValue } from 'vue'\nimport {\n defaultDocument,\n tryOnScopeDispose,\n useEventListener,\n} from '@vueuse/core'\n\nimport type { MaybeRefOrGetter } from 'vue'\n\nexport type TouchIntent = 'scroll' | 'swipe'\nexport type TouchIntentAxis = 'x' | 'y'\n\nexport interface UseTouchIntentOptions {\n target?: MaybeRefOrGetter<Element | Document | null | undefined>\n axis?: MaybeRefOrGetter<TouchIntentAxis>\n threshold?: MaybeRefOrGetter<number>\n}\n\nconst endEvents = ['pointerup', 'pointercancel', 'touchend', 'touchcancel']\n\n// Tells a scroll from a swipe by the axis a press’s first move leans along\nexport function useTouchIntent(options: UseTouchIntentOptions = {}) {\n const { target, axis = 'y', threshold = 8 } = options\n\n // Private state\n let pressX = 0\n let pressY = 0\n let cancelMove: (() => void) | undefined = undefined\n let cancelEnd: (() => void) | undefined = undefined\n\n // Public state\n const intent = ref<TouchIntent | undefined>(undefined)\n const isScrolling = computed(() => intent.value === 'scroll')\n const isSwiping = computed(() => intent.value === 'swipe')\n\n // Private functions\n function end() {\n cancelMove?.()\n cancelEnd?.()\n cancelMove = undefined\n cancelEnd = undefined\n intent.value = undefined\n }\n\n // The first axis to pass the threshold with the larger move settles the press\n function onPointermove(e: PointerEvent) {\n if (intent.value || (e.isTrusted && !e.isPrimary)) {\n return\n }\n\n const dx = Math.abs(e.clientX - pressX)\n const dy = Math.abs(e.clientY - pressY)\n const vertical = toValue(axis) === 'y'\n const along = vertical ? dy : dx\n const across = vertical ? dx : dy\n const limit = toValue(threshold)\n\n if (along > limit && along > across) {\n intent.value = 'scroll'\n } else if (across > limit && across > along) {\n intent.value = 'swipe'\n }\n }\n\n function onPointerdown(e: PointerEvent) {\n if (e.isTrusted && !e.isPrimary) {\n return\n }\n\n end()\n pressX = e.clientX\n pressY = e.clientY\n cancelMove = useEventListener(\n defaultDocument,\n 'pointermove',\n onPointermove,\n { capture: true }\n )\n cancelEnd = useEventListener(defaultDocument, endEvents, end, {\n capture: true,\n })\n }\n\n useEventListener(\n () => toValue(target) ?? defaultDocument,\n 'pointerdown',\n onPointerdown,\n { capture: true }\n )\n\n tryOnScopeDispose(end)\n\n return {\n intent: readonly(intent),\n isScrolling,\n isSwiping,\n }\n}\n\nexport type UseTouchIntentReturn = ReturnType<typeof useTouchIntent>\n"],"mappings":";AAAA,SAAS,UAAU,UAAU,KAAK,eAAe;AACjD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAaP,IAAM,YAAY,CAAC,aAAa,iBAAiB,YAAY,aAAa;AAGnE,SAAS,eAAe,UAAiC,CAAC,GAAG;AAClE,QAAM,EAAE,QAAQ,OAAO,KAAK,YAAY,EAAE,IAAI;AAG9C,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,aAAuC;AAC3C,MAAI,YAAsC;AAG1C,QAAM,SAAS,IAA6B,MAAS;AACrD,QAAM,cAAc,SAAS,MAAM,OAAO,UAAU,QAAQ;AAC5D,QAAM,YAAY,SAAS,MAAM,OAAO,UAAU,OAAO;AAGzD,WAAS,MAAM;AACb,iBAAa;AACb,gBAAY;AACZ,iBAAa;AACb,gBAAY;AACZ,WAAO,QAAQ;AAAA,EACjB;AAGA,WAAS,cAAc,GAAiB;AACtC,QAAI,OAAO,SAAU,EAAE,aAAa,CAAC,EAAE,WAAY;AACjD;AAAA,IACF;AAEA,UAAM,KAAK,KAAK,IAAI,EAAE,UAAU,MAAM;AACtC,UAAM,KAAK,KAAK,IAAI,EAAE,UAAU,MAAM;AACtC,UAAM,WAAW,QAAQ,IAAI,MAAM;AACnC,UAAM,QAAQ,WAAW,KAAK;AAC9B,UAAM,SAAS,WAAW,KAAK;AAC/B,UAAM,QAAQ,QAAQ,SAAS;AAE/B,QAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,aAAO,QAAQ;AAAA,IACjB,WAAW,SAAS,SAAS,SAAS,OAAO;AAC3C,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,WAAS,cAAc,GAAiB;AACtC,QAAI,EAAE,aAAa,CAAC,EAAE,WAAW;AAC/B;AAAA,IACF;AAEA,QAAI;AACJ,aAAS,EAAE;AACX,aAAS,EAAE;AACX,iBAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,SAAS,KAAK;AAAA,IAClB;AACA,gBAAY,iBAAiB,iBAAiB,WAAW,KAAK;AAAA,MAC5D,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA;AAAA,IACE,MAAM,QAAQ,MAAM,KAAK;AAAA,IACzB;AAAA,IACA;AAAA,IACA,EAAE,SAAS,KAAK;AAAA,EAClB;AAEA,oBAAkB,GAAG;AAErB,SAAO;AAAA,IACL,QAAQ,SAAS,MAAM;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment/nuxt",
3
3
  "configKey": "vueEquipment",
4
- "version": "1.3.0",
4
+ "version": "1.4.1",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.3",
7
7
  "unbuild": "unknown"
@@ -161,6 +161,13 @@ const functions$1 = [
161
161
  lastUpdated: 1787864792000,
162
162
  docs: "https://vue.equipment/composables/useScrollTo",
163
163
  description: "Scroll to an element with consistent speed"
164
+ },
165
+ {
166
+ name: "useTouchIntent",
167
+ "package": "composables",
168
+ lastUpdated: 1793702872000,
169
+ docs: "https://vue.equipment/composables/useTouchIntent",
170
+ description: "Tell a swipe from a scroll: a press that moves sideways is a swipe"
164
171
  }
165
172
  ];
166
173
 
@@ -1,9 +1,9 @@
1
- import type { MaybeRef } from 'vue';
1
+ import type { MaybeRef, MaybeRefOrGetter } from 'vue';
2
2
  import type { MagicTraySide } from '../types/index.js';
3
3
  interface MagicTrayTriggerProps {
4
4
  id?: MaybeRef<string>;
5
5
  side: MagicTraySide | Array<MagicTraySide>;
6
- disabled?: boolean;
6
+ disabled?: MaybeRefOrGetter<boolean>;
7
7
  preventEdgeNavigation?: boolean;
8
8
  asChild?: boolean;
9
9
  }
@@ -31,7 +31,7 @@ const {
31
31
  } = defineProps({
32
32
  id: { type: null, required: false },
33
33
  side: { type: [String, Array], required: true },
34
- disabled: { type: Boolean, required: false },
34
+ disabled: { type: null, required: false },
35
35
  preventEdgeNavigation: { type: Boolean, required: false },
36
36
  asChild: { type: Boolean, required: false }
37
37
  });
@@ -52,9 +52,12 @@ const { active, hasDragged, onPointerdown, onTouchstart } = useTrayGesture({
52
52
  id: mappedId,
53
53
  state,
54
54
  selectionLock: "drag",
55
+ disabled: () => toValue(disabled) === true,
55
56
  preventEdgeNavigation: () => preventEdgeNavigation ?? state.options.preventEdgeNavigation
56
57
  });
57
- const mappedDisabled = computed(() => disabled || state.options.disabled);
58
+ const mappedDisabled = computed(
59
+ () => toValue(disabled) === true || state.options.disabled
60
+ );
58
61
  const sides = computed(() => Array.isArray(side) ? side : [side]);
59
62
  const mappedSide = computed(() => sides.value.join(" "));
60
63
  const axis = computed(() => {
@@ -1,9 +1,9 @@
1
- import type { MaybeRef } from 'vue';
1
+ import type { MaybeRef, MaybeRefOrGetter } from 'vue';
2
2
  import type { MagicTraySide } from '../types/index.js';
3
3
  interface MagicTrayTriggerProps {
4
4
  id?: MaybeRef<string>;
5
5
  side: MagicTraySide | Array<MagicTraySide>;
6
- disabled?: boolean;
6
+ disabled?: MaybeRefOrGetter<boolean>;
7
7
  preventEdgeNavigation?: boolean;
8
8
  asChild?: boolean;
9
9
  }
@@ -4,6 +4,7 @@ type UseTrayGestureArgs = {
4
4
  id: MaybeRef<string>;
5
5
  state: TrayState;
6
6
  selectionLock?: 'press' | 'drag';
7
+ disabled?: MaybeRefOrGetter<boolean>;
7
8
  preventEdgeNavigation: MaybeRefOrGetter<boolean>;
8
9
  };
9
10
  export declare function useTrayGesture(args: UseTrayGestureArgs): {
@@ -15,7 +15,13 @@ import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
15
15
  import { useTraySnap } from "./useTraySnap.mjs";
16
16
  import { SIDES, useTrayUtils } from "./useTrayUtils.mjs";
17
17
  export function useTrayGesture(args) {
18
- const { id, state, selectionLock = "press", preventEdgeNavigation } = args;
18
+ const {
19
+ id,
20
+ state,
21
+ selectionLock = "press",
22
+ disabled: ownDisabled,
23
+ preventEdgeNavigation
24
+ } = args;
19
25
  const { clampWithOvershoot, isVertical, isDraggableSide } = useTrayUtils();
20
26
  const emitter = useMagicEmitter();
21
27
  const {
@@ -41,7 +47,9 @@ export function useTrayGesture(args) {
41
47
  let releaseSelection = void 0;
42
48
  let pending = void 0;
43
49
  const threshold = computed(() => state.options.threshold);
44
- const disabled = computed(() => state.options.disabled);
50
+ const disabled = computed(
51
+ () => state.options.disabled || toValue(ownDisabled) === true
52
+ );
45
53
  const snapMode = computed(() => state.options.snap.mode);
46
54
  const dragMode = computed(() => state.options.drag.mode);
47
55
  const active = ref(false);
@@ -67,25 +75,37 @@ export function useTrayGesture(args) {
67
75
  (side2) => isDraggableSide({ snapPoints: state.options.snapPoints, side: side2 })
68
76
  );
69
77
  }
78
+ function isOpen(side) {
79
+ return state.dragged[side] > dragBounds(side).min;
80
+ }
70
81
  function resolveSide(sides, dx, dy) {
71
82
  const horizontal = sides.filter((side) => !isVertical(side));
72
83
  const vertical = sides.filter(isVertical);
73
84
  const alongX = horizontal.length > 0 && (!vertical.length || Math.abs(dx) >= Math.abs(dy));
74
85
  const delta = alongX ? dx : dy;
75
- if (Math.abs(delta) <= toValue(threshold).lock) {
86
+ if (delta === 0) {
76
87
  return void 0;
77
88
  }
78
89
  const candidates = alongX ? horizontal : vertical;
79
- const preferred = alongX ? delta > 0 ? "left" : "right" : delta > 0 ? "top" : "bottom";
80
- return candidates.includes(preferred) ? preferred : candidates[0];
90
+ const [opens, closes] = alongX ? delta > 0 ? ["left", "right"] : ["right", "left"] : delta > 0 ? ["top", "bottom"] : ["bottom", "top"];
91
+ if (candidates.includes(closes) && isOpen(closes)) {
92
+ return closes;
93
+ }
94
+ return candidates.includes(opens) ? opens : candidates[0];
95
+ }
96
+ function dropPending(e) {
97
+ pending = void 0;
98
+ resetListeners();
99
+ if (e) {
100
+ guardedReleasePointerCapture({ event: e, element: pointerdownTarget });
101
+ }
81
102
  }
82
- function resolvePending(x, y) {
103
+ function resolvePending(x, y, e) {
83
104
  if (!pending) {
84
105
  return void 0;
85
106
  }
86
107
  if (!canStart()) {
87
- pending = void 0;
88
- resetListeners();
108
+ dropPending(e);
89
109
  return void 0;
90
110
  }
91
111
  const side = resolveSide(pending.sides, x - pending.x, y - pending.y);
@@ -265,7 +285,7 @@ export function useTrayGesture(args) {
265
285
  if (e.isTrusted && !e.isPrimary) {
266
286
  return;
267
287
  }
268
- const side = state.draggingSide ?? resolvePending(e.clientX, e.clientY);
288
+ const side = state.draggingSide ?? resolvePending(e.clientX, e.clientY, e);
269
289
  if (!side) {
270
290
  return;
271
291
  }
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.0",
4
+ "version": "1.5.0",
5
5
  "contributors": [
6
6
  {
7
7
  "name": "Robin Scholz",
@@ -148,17 +148,8 @@
148
148
  "update:deps:major": "pnpm dlx taze major -r -w"
149
149
  },
150
150
  "type": "module",
151
- "packageManager": "pnpm@10.34.5",
152
- "pnpm": {
153
- "overrides": {
154
- "typescript": "catalog:"
155
- },
156
- "onlyBuiltDependencies": [
157
- "@bundled-es-modules/glob",
158
- "@parcel/watcher",
159
- "esbuild",
160
- "style-dictionary",
161
- "vue-demi"
162
- ]
163
- }
151
+ "engines": {
152
+ "pnpm": ">=12"
153
+ },
154
+ "packageManager": "pnpm@12.16.1"
164
155
  }