@maas/vue-equipment 1.0.0-beta.69 → 1.0.0-beta.70

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@maas/vue-equipment/nuxt",
3
3
  "configKey": "vueEquipment",
4
- "version": "1.0.0-beta.68",
4
+ "version": "1.0.0-beta.69",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -109,7 +109,7 @@ const functions$1 = [
109
109
  {
110
110
  name: "MagicTray",
111
111
  "package": "plugins",
112
- lastUpdated: 1781787163000,
112
+ lastUpdated: 1781870441000,
113
113
  docs: "https://maas.egineering/vue-equipment/plugins/MagicTray/",
114
114
  description: "MagicTray is a flexible"
115
115
  },
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div
3
3
  class="magic-tray-content"
4
- :data-id="mappedId"
4
+ :data-id="instanceId"
5
5
  :data-dragging="state.dragging"
6
6
  :data-dragging-side="state.draggingSide"
7
7
  :data-dragged="hasDragged"
@@ -35,6 +35,7 @@
35
35
  <magic-tray-handle
36
36
  v-for="side in visibleHandles"
37
37
  :key="side"
38
+ :ref="`${side}Handle`"
38
39
  :side="side"
39
40
  :style="handleStyle(side)"
40
41
  @pointerdown="guardedPointerdown(side, $event)"
@@ -56,7 +57,12 @@
56
57
  </template>
57
58
 
58
59
  <script setup>
59
- import { useTemplateRef, useSlots, computed, inject } from "vue";
60
+ import {
61
+ useTemplateRef,
62
+ useSlots,
63
+ computed,
64
+ inject
65
+ } from "vue";
60
66
  import {
61
67
  useMagicError
62
68
  } from "@maas/vue-equipment/plugins/MagicError";
@@ -78,10 +84,19 @@ magicError.assert(instanceId, {
78
84
  message: "MagicTrayContent must be nested inside MagicTrayProvider",
79
85
  errorCode: "missing_instance_id"
80
86
  });
81
- const mappedId = instanceId ?? "";
82
- const { initializeState } = useTrayState(mappedId);
87
+ const { initializeState } = useTrayState(instanceId);
83
88
  const state = initializeState();
84
89
  const elRef = useTemplateRef("el");
90
+ const topHandleRef = useTemplateRef("topHandle");
91
+ const rightHandleRef = useTemplateRef("rightHandle");
92
+ const bottomHandleRef = useTemplateRef("bottomHandle");
93
+ const leftHandleRef = useTemplateRef("leftHandle");
94
+ const handleRefs = {
95
+ top: topHandleRef,
96
+ right: rightHandleRef,
97
+ bottom: bottomHandleRef,
98
+ left: leftHandleRef
99
+ };
85
100
  const disabled = computed(() => state.options.disabled);
86
101
  const inset = computed(() => state.options.inset);
87
102
  const slots = useSlots();
@@ -93,11 +108,11 @@ const {
93
108
  onHandlePointerdown,
94
109
  onHandleTouchstart
95
110
  } = useTrayDrag({
96
- id: mappedId,
111
+ id: instanceId,
97
112
  elRef
98
113
  });
99
- useTrayMagnetism({ id: mappedId, elRef, state });
100
- useTrayProgress({ id: mappedId, state });
114
+ useTrayMagnetism({ id: instanceId, elRef, handleRefs, state });
115
+ useTrayProgress({ id: instanceId, state });
101
116
  const visibleHandles = computed(() => {
102
117
  const { handles } = state.options;
103
118
  if (handles === false) {
@@ -174,7 +189,6 @@ function guardedTouchstart(side, event) {
174
189
  box-sizing: border-box;
175
190
  width: 100%;
176
191
  height: 100%;
177
- will-change: clip-path;
178
192
  }
179
193
 
180
194
  .magic-tray-content__bg {
@@ -229,4 +243,8 @@ dialog.magic-tray-content__inner {
229
243
  .magic-tray-content[data-disabled='true'] .magic-tray-content__handles {
230
244
  display: none;
231
245
  }
246
+
247
+ .magic-tray-content[data-dragging='true'] .magic-tray-handle {
248
+ cursor: var(--magic-tray-handle-cursor-dragging, grabbing);
249
+ }
232
250
  </style>
@@ -29,6 +29,7 @@ const orientation = computed(
29
29
  pointer-events: auto;
30
30
  touch-action: none;
31
31
  user-select: none;
32
+ cursor: var(--magic-tray-handle-cursor, grab);
32
33
  }
33
34
 
34
35
  .magic-tray-handle[data-side='top'],
@@ -52,10 +53,12 @@ const orientation = computed(
52
53
  --magic-tray-handle-height-top,
53
54
  var(--magic-tray-handle-height-x, 4rem)
54
55
  );
55
- cursor: var(--magic-tray-handle-cursor-top, row-resize);
56
56
  transform: translate(
57
57
  var(--magic-tray-handle-offset-x-top, 0%),
58
- var(--magic-tray-handle-offset-y-top, -50%)
58
+ calc(
59
+ var(--magic-tray-handle-offset-y-top, -50%) +
60
+ var(--magic-tray-handle-magnetic, 0px)
61
+ )
59
62
  );
60
63
  }
61
64
 
@@ -68,10 +71,12 @@ const orientation = computed(
68
71
  --magic-tray-handle-height-bottom,
69
72
  var(--magic-tray-handle-height-x, 4rem)
70
73
  );
71
- cursor: var(--magic-tray-handle-cursor-bottom, row-resize);
72
74
  transform: translate(
73
75
  var(--magic-tray-handle-offset-x-bottom, 0%),
74
- var(--magic-tray-handle-offset-y-bottom, 50%)
76
+ calc(
77
+ var(--magic-tray-handle-offset-y-bottom, 50%) -
78
+ var(--magic-tray-handle-magnetic, 0px)
79
+ )
75
80
  );
76
81
  }
77
82
 
@@ -84,9 +89,11 @@ const orientation = computed(
84
89
  --magic-tray-handle-height-left,
85
90
  var(--magic-tray-handle-height-y, 100%)
86
91
  );
87
- cursor: var(--magic-tray-handle-cursor-left, col-resize);
88
92
  transform: translate(
89
- var(--magic-tray-handle-offset-x-left, -50%),
93
+ calc(
94
+ var(--magic-tray-handle-offset-x-left, -50%) +
95
+ var(--magic-tray-handle-magnetic, 0px)
96
+ ),
90
97
  var(--magic-tray-handle-offset-y-left, 0%)
91
98
  );
92
99
  }
@@ -100,9 +107,11 @@ const orientation = computed(
100
107
  --magic-tray-handle-height-right,
101
108
  var(--magic-tray-handle-height-y, 100%)
102
109
  );
103
- cursor: var(--magic-tray-handle-cursor-right, col-resize);
104
110
  transform: translate(
105
- var(--magic-tray-handle-offset-x-right, 50%),
111
+ calc(
112
+ var(--magic-tray-handle-offset-x-right, 50%) -
113
+ var(--magic-tray-handle-magnetic, 0px)
114
+ ),
106
115
  var(--magic-tray-handle-offset-y-right, 0%)
107
116
  );
108
117
  }
@@ -44,9 +44,3 @@ const transform = computed(() => {
44
44
  return `translate3d(${x}px, ${y}px, 0)`;
45
45
  });
46
46
  </script>
47
-
48
- <style>
49
- .magic-tray-transform {
50
- will-change: transform;
51
- }
52
- </style>
@@ -11,21 +11,25 @@ export declare function useTrayDrag(args: UseTrayDragArgs): {
11
11
  top: string;
12
12
  left: string;
13
13
  right: string;
14
+ '--magic-tray-handle-magnetic': string;
14
15
  bottom?: undefined;
15
16
  } | {
16
17
  bottom: string;
17
18
  left: string;
18
19
  right: string;
20
+ '--magic-tray-handle-magnetic': string;
19
21
  top?: undefined;
20
22
  } | {
21
23
  left: string;
22
24
  top: string;
23
25
  bottom: string;
26
+ '--magic-tray-handle-magnetic': string;
24
27
  right?: undefined;
25
28
  } | {
26
29
  right: string;
27
30
  top: string;
28
31
  bottom: string;
32
+ '--magic-tray-handle-magnetic': string;
29
33
  left?: undefined;
30
34
  };
31
35
  hasDragged: import("vue").ComputedRef<boolean>;
@@ -100,16 +100,37 @@ export function useTrayDrag(args) {
100
100
  return `inset(${top}px ${right}px ${bottom}px ${left}px round var(--magic-tray-radius, 0px))`;
101
101
  });
102
102
  function handleStyle(side) {
103
- const offset = `${state.dragged[side] + state.magnetic[side]}px`;
103
+ const rest = `${state.dragged[side]}px`;
104
+ const magnetic = `${state.magnetic[side]}px`;
104
105
  switch (side) {
105
106
  case "top":
106
- return { top: offset, left: "0px", right: "0px" };
107
+ return {
108
+ top: rest,
109
+ left: "0px",
110
+ right: "0px",
111
+ "--magic-tray-handle-magnetic": magnetic
112
+ };
107
113
  case "bottom":
108
- return { bottom: offset, left: "0px", right: "0px" };
114
+ return {
115
+ bottom: rest,
116
+ left: "0px",
117
+ right: "0px",
118
+ "--magic-tray-handle-magnetic": magnetic
119
+ };
109
120
  case "left":
110
- return { left: offset, top: "0px", bottom: "0px" };
121
+ return {
122
+ left: rest,
123
+ top: "0px",
124
+ bottom: "0px",
125
+ "--magic-tray-handle-magnetic": magnetic
126
+ };
111
127
  case "right":
112
- return { right: offset, top: "0px", bottom: "0px" };
128
+ return {
129
+ right: rest,
130
+ top: "0px",
131
+ bottom: "0px",
132
+ "--magic-tray-handle-magnetic": magnetic
133
+ };
113
134
  }
114
135
  }
115
136
  async function getSizes() {
@@ -1,8 +1,9 @@
1
- import { type Ref, type MaybeRef } from 'vue';
2
- import type { TrayState } from '../../types/index.js';
1
+ import { type Ref, type ShallowRef, type MaybeRef, type ComponentPublicInstance } from 'vue';
2
+ import type { TrayState, TraySide } from '../../types/index.js';
3
3
  type UseTrayMagnetismArgs = {
4
4
  id: MaybeRef<string>;
5
5
  elRef: Ref<HTMLElement | null>;
6
+ handleRefs: Record<TraySide, Readonly<ShallowRef<ComponentPublicInstance[] | null>>>;
6
7
  state: TrayState;
7
8
  };
8
9
  export declare function useTrayMagnetism(args: UseTrayMagnetismArgs): {};
@@ -5,7 +5,7 @@ import {
5
5
  onScopeDispose
6
6
  } from "vue";
7
7
  import { unrefElement, useEventListener, useRafFn } from "@vueuse/core";
8
- import { clampValue } from "@maas/vue-equipment/utils";
8
+ import { clampValue, interpolate } from "@maas/vue-equipment/utils";
9
9
  import { useMagicEmitter } from "@maas/vue-equipment/plugins/MagicEmitter";
10
10
  import { useMagicError } from "@maas/vue-equipment/plugins/MagicError";
11
11
  import { useEasings } from "@maas/vue-equipment/composables/useEasings";
@@ -13,7 +13,7 @@ import { useTraySnap } from "./useTraySnap.mjs";
13
13
  const SIDES = ["top", "right", "bottom", "left"];
14
14
  const EPSILON = 0.5;
15
15
  export function useTrayMagnetism(args) {
16
- const { id, elRef, state } = args;
16
+ const { id, elRef, handleRefs, state } = args;
17
17
  const { throwError } = useMagicError({
18
18
  prefix: "MagicTray",
19
19
  source: "useTrayMagnetism"
@@ -27,6 +27,7 @@ export function useTrayMagnetism(args) {
27
27
  const magnetism = computed(() => state.options.magnetism);
28
28
  const easing = computed(() => easings[magnetism.value.easing]);
29
29
  const disabled = computed(() => state.options.disabled);
30
+ const animation = computed(() => state.options.animation);
30
31
  function sideConfig(side) {
31
32
  const { sides } = magnetism.value;
32
33
  return sides ? sides[side] : void 0;
@@ -62,11 +63,17 @@ export function useTrayMagnetism(args) {
62
63
  }
63
64
  return result;
64
65
  });
65
- const engaged = {
66
- top: false,
67
- right: false,
68
- bottom: false,
69
- left: false
66
+ const progress = {
67
+ top: 0,
68
+ right: 0,
69
+ bottom: 0,
70
+ left: 0
71
+ };
72
+ const pullPx = {
73
+ top: 0,
74
+ right: 0,
75
+ bottom: 0,
76
+ left: 0
70
77
  };
71
78
  const armedDir = {
72
79
  top: null,
@@ -74,11 +81,23 @@ export function useTrayMagnetism(args) {
74
81
  bottom: null,
75
82
  left: null
76
83
  };
77
- const progress = {
78
- top: 0,
79
- right: 0,
80
- bottom: 0,
81
- left: 0
84
+ const latched = {
85
+ top: false,
86
+ right: false,
87
+ bottom: false,
88
+ left: false
89
+ };
90
+ const settleId = {
91
+ top: void 0,
92
+ right: void 0,
93
+ bottom: void 0,
94
+ left: void 0
95
+ };
96
+ const settling = {
97
+ top: false,
98
+ right: false,
99
+ bottom: false,
100
+ left: false
82
101
  };
83
102
  const { resume, pause } = useRafFn(
84
103
  () => {
@@ -117,24 +136,69 @@ export function useTrayMagnetism(args) {
117
136
  );
118
137
  return match ? match.direction : null;
119
138
  }
139
+ function handleHalfThickness(side) {
140
+ const handle = unrefElement(handleRefs[side].value?.[0]);
141
+ if (!handle) {
142
+ return 0;
143
+ }
144
+ const rect = handle.getBoundingClientRect();
145
+ const size = side === "top" || side === "bottom" ? rect.height : rect.width;
146
+ return size / 2;
147
+ }
148
+ function cancelSettle(side) {
149
+ if (settleId[side] !== void 0) {
150
+ cancelAnimationFrame(settleId[side]);
151
+ settleId[side] = void 0;
152
+ }
153
+ settling[side] = false;
154
+ }
120
155
  function resetSide(side) {
156
+ cancelSettle(side);
121
157
  if (state.magnetic[side] !== 0) {
122
158
  state.magnetic[side] = 0;
123
159
  }
124
160
  }
161
+ function settleSide(side) {
162
+ if (settling[side]) {
163
+ return;
164
+ }
165
+ if (Math.abs(state.magnetic[side]) <= EPSILON) {
166
+ resetSide(side);
167
+ return;
168
+ }
169
+ const { duration, easing: snapEasing } = animation.value.snap;
170
+ settling[side] = true;
171
+ settleId[side] = interpolate({
172
+ from: state.magnetic[side],
173
+ to: 0,
174
+ duration,
175
+ easing: snapEasing,
176
+ interpolationIdCallback: (newId) => settleId[side] = newId,
177
+ callback: (value) => {
178
+ state.magnetic[side] = value;
179
+ if (value === 0) {
180
+ settling[side] = false;
181
+ settleId[side] = void 0;
182
+ }
183
+ }
184
+ });
185
+ }
125
186
  function resetAll() {
126
187
  for (const side of SIDES) {
188
+ armedDir[side] = null;
189
+ latched[side] = false;
127
190
  resetSide(side);
128
191
  }
129
192
  }
130
193
  function axisOverflow(value, min, max) {
131
- if (value < min) {
132
- return min - value;
194
+ switch (true) {
195
+ case value < min:
196
+ return min - value;
197
+ case value > max:
198
+ return value - max;
199
+ default:
200
+ return 0;
133
201
  }
134
- if (value > max) {
135
- return value - max;
136
- }
137
- return 0;
138
202
  }
139
203
  function update(x, y) {
140
204
  if (state.dragging || disabled.value) {
@@ -146,22 +210,28 @@ export function useTrayMagnetism(args) {
146
210
  resetAll();
147
211
  return;
148
212
  }
149
- const { radius, pull } = magnetism.value;
150
- if (radius <= 0) {
151
- resetAll();
152
- return;
153
- }
213
+ const { pull: configuredPull, radius: configuredRadius } = magnetism.value;
154
214
  const rect = el.getBoundingClientRect();
155
215
  for (const side of magneticSides.value) {
156
216
  const direction = restDirection(side);
157
217
  if (!direction) {
158
218
  armedDir[side] = null;
159
- engaged[side] = false;
219
+ latched[side] = false;
160
220
  resetSide(side);
161
221
  continue;
162
222
  }
163
223
  const allowInner = direction === "inner" || direction === "both";
164
224
  const allowOuter = direction === "outer" || direction === "both";
225
+ const anchorHalf = handleHalfThickness(side);
226
+ const radius = configuredRadius > 0 ? configuredRadius : anchorHalf / 2;
227
+ const pull = configuredPull > 0 ? configuredPull : anchorHalf / 2;
228
+ pullPx[side] = pull;
229
+ if (radius <= 0) {
230
+ armedDir[side] = null;
231
+ latched[side] = false;
232
+ resetSide(side);
233
+ continue;
234
+ }
165
235
  let perp = 0;
166
236
  let overflow = 0;
167
237
  switch (side) {
@@ -182,40 +252,57 @@ export function useTrayMagnetism(args) {
182
252
  overflow = axisOverflow(y, rect.top, rect.bottom);
183
253
  break;
184
254
  }
185
- if (perp > radius) {
186
- armedDir[side] = allowInner ? "inner" : null;
187
- engaged[side] = false;
188
- resetSide(side);
189
- continue;
255
+ if (overflow === 0) {
256
+ switch (true) {
257
+ case (allowInner && perp >= anchorHalf):
258
+ armedDir[side] = "inner";
259
+ break;
260
+ case (allowOuter && perp <= -anchorHalf):
261
+ armedDir[side] = "outer";
262
+ break;
263
+ }
190
264
  }
191
- if (perp < -radius) {
192
- armedDir[side] = allowOuter ? "outer" : null;
193
- engaged[side] = false;
265
+ const dir = armedDir[side];
266
+ if (!dir) {
194
267
  resetSide(side);
195
268
  continue;
196
269
  }
197
- const gap = Math.hypot(perp, overflow);
198
- if (gap > radius) {
199
- if (engaged[side]) {
200
- armedDir[side] = null;
201
- engaged[side] = false;
202
- }
203
- resetSide(side);
204
- continue;
270
+ let t = 0;
271
+ let sign = 0;
272
+ switch (dir) {
273
+ case "inner":
274
+ t = clampValue((anchorHalf - perp) / radius, 0, 1);
275
+ sign = 1;
276
+ break;
277
+ case "outer":
278
+ t = clampValue((anchorHalf + perp) / radius, 0, 1);
279
+ sign = -1;
280
+ break;
205
281
  }
206
- if (!armedDir[side]) {
207
- resetSide(side);
208
- continue;
282
+ switch (true) {
283
+ case overflow === 0:
284
+ latched[side] = t >= 1;
285
+ break;
286
+ case !latched[side]:
287
+ armedDir[side] = null;
288
+ resetSide(side);
289
+ continue;
209
290
  }
210
- const eased = easing.value((radius - gap) / radius);
211
- const magnitude = pull * eased;
212
- const offset = armedDir[side] === "outer" ? -magnitude : magnitude;
213
- state.magnetic[side] = clampValue(
291
+ const magnitude = overflow === 0 ? easing.value(t) : 1;
292
+ const offset = sign * pull * magnitude;
293
+ const target = clampValue(
214
294
  offset,
215
295
  -state.dragged[side],
216
296
  maxInset(side) - state.dragged[side]
217
297
  );
218
- engaged[side] = true;
298
+ switch (true) {
299
+ case Math.abs(target) > EPSILON:
300
+ cancelSettle(side);
301
+ state.magnetic[side] = target;
302
+ break;
303
+ default:
304
+ settleSide(side);
305
+ }
219
306
  }
220
307
  }
221
308
  function onPointermove(e) {
@@ -237,21 +324,12 @@ export function useTrayMagnetism(args) {
237
324
  pause();
238
325
  resetAll();
239
326
  }
240
- watch(
241
- () => state.draggingSide,
242
- (side) => {
243
- if (side && enabled.value) {
244
- armedDir[side] = null;
245
- engaged[side] = false;
246
- }
247
- }
248
- );
249
327
  watch(
250
328
  () => ({ ...state.magnetic }),
251
329
  (magnetic) => {
252
- const { pull } = magnetism.value;
253
330
  for (const side of SIDES) {
254
- const value = pull > 0 ? clampValue(magnetic[side] / pull, -1, 1) : 0;
331
+ const max = pullPx[side];
332
+ const value = max > 0 ? clampValue(magnetic[side] / max, -1, 1) : 0;
255
333
  if (value !== progress[side]) {
256
334
  progress[side] = value;
257
335
  emitter.emit("magnet", {
@@ -10,8 +10,8 @@ const defaultOptions = {
10
10
  handles: true,
11
11
  magnetism: {
12
12
  sides: false,
13
- radius: 80,
14
- pull: 24,
13
+ radius: 0,
14
+ pull: 0,
15
15
  easing: "easeInOutQuad"
16
16
  },
17
17
  threshold: {
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.0.0-beta.69",
4
+ "version": "1.0.0-beta.70",
5
5
  "contributors": [
6
6
  {
7
7
  "name": "Robin Scholz",