@maas/vue-equipment 0.30.0 → 0.30.2
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/MagicAutoSize/src/components/MagicAutoSize.vue +13 -8
- package/dist/plugins/MagicMenu/index.mjs +4 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuChannel.vue +69 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuChannel.vue.d.ts +21 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuContent.vue +61 -16
- package/dist/plugins/MagicMenu/src/components/MagicMenuContent.vue.d.ts +0 -2
- package/dist/plugins/MagicMenu/src/components/MagicMenuFloat.vue +2 -2
- package/dist/plugins/MagicMenu/src/components/MagicMenuItem.vue +1 -1
- package/dist/plugins/MagicMenu/src/components/MagicMenuProvider.vue +1 -5
- package/dist/plugins/MagicMenu/src/components/MagicMenuRemote.vue +84 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuRemote.vue.d.ts +29 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuTrigger.vue +25 -31
- package/dist/plugins/MagicMenu/src/components/MagicMenuView.vue +26 -0
- package/dist/plugins/MagicMenu/src/components/MagicMenuView.vue.d.ts +2 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuCallback.d.ts +2 -1
- package/dist/plugins/MagicMenu/src/composables/private/useMenuCallback.mjs +6 -1
- package/dist/plugins/MagicMenu/src/composables/private/useMenuChannel.d.ts +15 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuChannel.mjs +70 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuCursor.d.ts +21 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuCursor.mjs +212 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuItem.mjs +2 -2
- package/dist/plugins/MagicMenu/src/composables/private/useMenuKeyListener.mjs +4 -4
- package/dist/plugins/MagicMenu/src/composables/private/useMenuRemote.d.ts +13 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuRemote.mjs +23 -0
- package/dist/plugins/MagicMenu/src/composables/private/useMenuTrigger.d.ts +1 -3
- package/dist/plugins/MagicMenu/src/composables/private/useMenuTrigger.mjs +2 -180
- package/dist/plugins/MagicMenu/src/composables/private/useMenuView.d.ts +4 -3
- package/dist/plugins/MagicMenu/src/composables/private/useMenuView.mjs +28 -15
- package/dist/plugins/MagicMenu/src/composables/useMagicMenu.d.ts +8 -1
- package/dist/plugins/MagicMenu/src/composables/useMagicMenu.mjs +10 -2
- package/dist/plugins/MagicMenu/src/symbols/index.d.ts +3 -1
- package/dist/plugins/MagicMenu/src/symbols/index.mjs +5 -1
- package/dist/plugins/MagicMenu/src/types/index.d.ts +9 -6
- package/dist/plugins/MagicMenu/src/utils/defaultOptions.mjs +3 -3
- package/dist/plugins/MagicPlayer/src/components/MagicPlayer.vue.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toValue } from "vue";
|
|
2
2
|
import { useMagicEmitter } from "@maas/vue-equipment/plugins";
|
|
3
3
|
export function useMenuCallback(args) {
|
|
4
|
-
const { state, instanceId, viewId, lockScroll, unlockScroll } = args;
|
|
4
|
+
const { state, instanceId, viewId, lockScroll, unlockScroll, wrapperActive } = args;
|
|
5
5
|
const emitter = useMagicEmitter();
|
|
6
6
|
function onBeforeEnter(_el) {
|
|
7
7
|
emitter.emit("beforeEnter", { id: toValue(instanceId), view: viewId });
|
|
@@ -17,6 +17,8 @@ export function useMenuCallback(args) {
|
|
|
17
17
|
break;
|
|
18
18
|
case "menubar":
|
|
19
19
|
break;
|
|
20
|
+
case "navigation":
|
|
21
|
+
break;
|
|
20
22
|
case "context":
|
|
21
23
|
lockScroll();
|
|
22
24
|
break;
|
|
@@ -36,10 +38,13 @@ export function useMenuCallback(args) {
|
|
|
36
38
|
break;
|
|
37
39
|
case "menubar":
|
|
38
40
|
break;
|
|
41
|
+
case "navigation":
|
|
42
|
+
break;
|
|
39
43
|
case "context":
|
|
40
44
|
unlockScroll();
|
|
41
45
|
break;
|
|
42
46
|
}
|
|
47
|
+
wrapperActive.value = false;
|
|
43
48
|
}
|
|
44
49
|
return {
|
|
45
50
|
onBeforeEnter,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MaybeRef } from 'vue';
|
|
2
|
+
import type { MenuChannel } from '../../types.js';
|
|
3
|
+
type UseMenuChannelArgs = {
|
|
4
|
+
instanceId: MaybeRef<string>;
|
|
5
|
+
viewId: string;
|
|
6
|
+
};
|
|
7
|
+
type InitializeChannelArgs = Pick<MenuChannel, 'id'>;
|
|
8
|
+
export declare function useMenuChannel(args: UseMenuChannelArgs): {
|
|
9
|
+
initializeChannel: (args: InitializeChannelArgs) => MenuChannel;
|
|
10
|
+
deleteChannel: (id: string) => void;
|
|
11
|
+
getChannel: (id: string) => MenuChannel | undefined;
|
|
12
|
+
selectChannel: (id: string) => void;
|
|
13
|
+
unselectChannel: (id: string) => void;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { reactive } from "vue";
|
|
2
|
+
import { useMenuView } from "./useMenuView.mjs";
|
|
3
|
+
import { useMenuState } from "./useMenuState.mjs";
|
|
4
|
+
export function useMenuChannel(args) {
|
|
5
|
+
const { instanceId, viewId } = args;
|
|
6
|
+
const { initializeState } = useMenuState(instanceId);
|
|
7
|
+
const state = initializeState();
|
|
8
|
+
const { getView } = useMenuView(instanceId);
|
|
9
|
+
const view = getView(viewId);
|
|
10
|
+
function createChannel(args2) {
|
|
11
|
+
const { id } = args2;
|
|
12
|
+
const channel = {
|
|
13
|
+
id,
|
|
14
|
+
active: false
|
|
15
|
+
};
|
|
16
|
+
return reactive(channel);
|
|
17
|
+
}
|
|
18
|
+
function addChannel(args2) {
|
|
19
|
+
const channel = createChannel(args2);
|
|
20
|
+
if (view?.channels) {
|
|
21
|
+
view.channels = [...view?.channels, channel];
|
|
22
|
+
}
|
|
23
|
+
return channel;
|
|
24
|
+
}
|
|
25
|
+
function unselectSiblings(id) {
|
|
26
|
+
return view?.channels.filter((channel) => channel.id !== id).forEach((channel) => channel.active = false);
|
|
27
|
+
}
|
|
28
|
+
function initializeChannel(args2) {
|
|
29
|
+
const { id } = args2;
|
|
30
|
+
const instance = getChannel(id);
|
|
31
|
+
if (!instance) {
|
|
32
|
+
const channel = addChannel(args2);
|
|
33
|
+
return channel;
|
|
34
|
+
}
|
|
35
|
+
return instance;
|
|
36
|
+
}
|
|
37
|
+
function deleteChannel(id) {
|
|
38
|
+
if (!view?.channels)
|
|
39
|
+
return;
|
|
40
|
+
view.channels = view.channels.filter((x) => x.id !== id);
|
|
41
|
+
}
|
|
42
|
+
function getChannel(id) {
|
|
43
|
+
return view?.channels.find((channel) => {
|
|
44
|
+
return channel.id === id;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function selectChannel(id) {
|
|
48
|
+
const instance = getChannel(id);
|
|
49
|
+
if (instance) {
|
|
50
|
+
instance.active = true;
|
|
51
|
+
unselectSiblings(id);
|
|
52
|
+
if (view) {
|
|
53
|
+
state.input.view = view.id;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function unselectChannel(id) {
|
|
58
|
+
const instance = getChannel(id);
|
|
59
|
+
if (instance) {
|
|
60
|
+
instance.active = false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
initializeChannel,
|
|
65
|
+
deleteChannel,
|
|
66
|
+
getChannel,
|
|
67
|
+
selectChannel,
|
|
68
|
+
unselectChannel
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type MaybeRef } from 'vue';
|
|
2
|
+
import type { Coordinates } from '../../types.js';
|
|
3
|
+
import type { Placement } from '@floating-ui/vue';
|
|
4
|
+
interface UseMenuCursorArgs {
|
|
5
|
+
from: MaybeRef<HTMLElement | undefined>;
|
|
6
|
+
to: MaybeRef<HTMLElement | undefined>;
|
|
7
|
+
placement: MaybeRef<Placement>;
|
|
8
|
+
click: MaybeRef<Coordinates | undefined>;
|
|
9
|
+
}
|
|
10
|
+
export declare function useMenuCursor(args: UseMenuCursorArgs): {
|
|
11
|
+
coords: import("vue").Ref<{
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
}[]>;
|
|
15
|
+
isInsideFrom: import("vue").Ref<boolean>;
|
|
16
|
+
isInsideTo: import("vue").Ref<boolean>;
|
|
17
|
+
isInsideTriangle: import("vue").Ref<boolean>;
|
|
18
|
+
initialize: () => void;
|
|
19
|
+
destroy: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { ref, toValue } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
useEventListener,
|
|
4
|
+
useElementBounding,
|
|
5
|
+
useResizeObserver,
|
|
6
|
+
usePointer
|
|
7
|
+
} from "@vueuse/core";
|
|
8
|
+
export function useMenuCursor(args) {
|
|
9
|
+
const cancelListener = ref(new AbortController());
|
|
10
|
+
const { x, y } = usePointer();
|
|
11
|
+
const { from, to, placement, click } = args;
|
|
12
|
+
const coords = ref([
|
|
13
|
+
{ x: 0, y: 0 },
|
|
14
|
+
{ x: 0, y: 0 },
|
|
15
|
+
{ x: 0, y: 0 }
|
|
16
|
+
]);
|
|
17
|
+
const isInsideFrom = ref(false);
|
|
18
|
+
const isInsideTo = ref(false);
|
|
19
|
+
const isInsideTriangle = ref(false);
|
|
20
|
+
function extendTriangle(vertices, pixelAmount) {
|
|
21
|
+
const [a, b, c] = vertices;
|
|
22
|
+
switch (toValue(placement)) {
|
|
23
|
+
case "bottom":
|
|
24
|
+
case "bottom-start":
|
|
25
|
+
case "bottom-end":
|
|
26
|
+
case "top":
|
|
27
|
+
case "top-start":
|
|
28
|
+
case "top-end":
|
|
29
|
+
switch (true) {
|
|
30
|
+
case (a.y < b.y && a.y < c.y):
|
|
31
|
+
b.y += pixelAmount;
|
|
32
|
+
b.x -= pixelAmount;
|
|
33
|
+
c.y += pixelAmount;
|
|
34
|
+
c.x += pixelAmount;
|
|
35
|
+
break;
|
|
36
|
+
case (a.y > b.y && a.y > c.y):
|
|
37
|
+
b.y -= pixelAmount;
|
|
38
|
+
b.x -= pixelAmount;
|
|
39
|
+
c.y -= pixelAmount;
|
|
40
|
+
c.x += pixelAmount;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case "right":
|
|
45
|
+
case "right-start":
|
|
46
|
+
case "right-end":
|
|
47
|
+
case "left":
|
|
48
|
+
case "left-start":
|
|
49
|
+
case "left-end":
|
|
50
|
+
switch (true) {
|
|
51
|
+
case (a.x < b.x && a.x < c.x):
|
|
52
|
+
b.x += pixelAmount;
|
|
53
|
+
b.y -= pixelAmount;
|
|
54
|
+
c.x += pixelAmount;
|
|
55
|
+
c.y += pixelAmount;
|
|
56
|
+
break;
|
|
57
|
+
case (a.x > b.x && a.x > c.x):
|
|
58
|
+
b.x -= pixelAmount;
|
|
59
|
+
b.y -= pixelAmount;
|
|
60
|
+
c.x -= pixelAmount;
|
|
61
|
+
c.y += pixelAmount;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
coords.value = [a, b, c];
|
|
67
|
+
return [a, b, c];
|
|
68
|
+
}
|
|
69
|
+
function isPointInTriangle(args2) {
|
|
70
|
+
const { p, a, b, c } = args2;
|
|
71
|
+
const v0 = { x: c.x - a.x, y: c.y - a.y };
|
|
72
|
+
const v1 = { x: b.x - a.x, y: b.y - a.y };
|
|
73
|
+
const v2 = { x: p.x - a.x, y: p.y - a.y };
|
|
74
|
+
const dot00 = v0.x * v0.x + v0.y * v0.y;
|
|
75
|
+
const dot01 = v0.x * v1.x + v0.y * v1.y;
|
|
76
|
+
const dot02 = v0.x * v2.x + v0.y * v2.y;
|
|
77
|
+
const dot11 = v1.x * v1.x + v1.y * v1.y;
|
|
78
|
+
const dot12 = v1.x * v2.x + v1.y * v2.y;
|
|
79
|
+
const invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
|
80
|
+
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
81
|
+
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
|
82
|
+
return u >= 0 && v >= 0 && u + v <= 1;
|
|
83
|
+
}
|
|
84
|
+
function isPointInRectangle(args2) {
|
|
85
|
+
const { p, top, left, bottom, right } = args2;
|
|
86
|
+
return p.x >= left && p.x <= right && p.y >= top && p.y <= bottom;
|
|
87
|
+
}
|
|
88
|
+
function triangleOverlap(cursor, from2, to2) {
|
|
89
|
+
const fromBounding = useElementBounding(from2, {
|
|
90
|
+
windowScroll: false,
|
|
91
|
+
windowResize: false
|
|
92
|
+
});
|
|
93
|
+
const toBounding = useElementBounding(to2, {
|
|
94
|
+
windowScroll: false,
|
|
95
|
+
windowResize: false
|
|
96
|
+
});
|
|
97
|
+
const { top, left, bottom, right } = toBounding;
|
|
98
|
+
const centerPoint = toValue(click) ?? {
|
|
99
|
+
x: (fromBounding.left.value + fromBounding.right.value) / 2,
|
|
100
|
+
y: (fromBounding.top.value + fromBounding.bottom.value) / 2
|
|
101
|
+
};
|
|
102
|
+
const sidePoints = [];
|
|
103
|
+
switch (toValue(placement)) {
|
|
104
|
+
case "top":
|
|
105
|
+
case "top-start":
|
|
106
|
+
case "top-end":
|
|
107
|
+
case "bottom":
|
|
108
|
+
case "bottom-start":
|
|
109
|
+
case "bottom-end":
|
|
110
|
+
const topDist = Math.abs(top.value - centerPoint.y);
|
|
111
|
+
const bottomDist = Math.abs(bottom.value - centerPoint.y);
|
|
112
|
+
const mappedY = topDist < bottomDist ? top : bottom;
|
|
113
|
+
sidePoints.push({ x: left.value, y: mappedY.value });
|
|
114
|
+
sidePoints.push({ x: right.value, y: mappedY.value });
|
|
115
|
+
break;
|
|
116
|
+
case "right":
|
|
117
|
+
case "right-start":
|
|
118
|
+
case "right-end":
|
|
119
|
+
case "left":
|
|
120
|
+
case "left-start":
|
|
121
|
+
case "left-end":
|
|
122
|
+
const rightDist = Math.abs(right.value - centerPoint.x);
|
|
123
|
+
const leftDist = Math.abs(left.value - centerPoint.x);
|
|
124
|
+
const mappedX = rightDist < leftDist ? right : left;
|
|
125
|
+
sidePoints.push({ x: mappedX.value, y: top.value });
|
|
126
|
+
sidePoints.push({ x: mappedX.value, y: bottom.value });
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
const [a, b, c] = extendTriangle(
|
|
130
|
+
[centerPoint, sidePoints[0], sidePoints[1]],
|
|
131
|
+
16
|
|
132
|
+
);
|
|
133
|
+
return isPointInTriangle({
|
|
134
|
+
p: cursor,
|
|
135
|
+
a,
|
|
136
|
+
b,
|
|
137
|
+
c
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function elementOverlap(cursor, element) {
|
|
141
|
+
const { top, left, bottom, right } = useElementBounding(element, {
|
|
142
|
+
windowScroll: false,
|
|
143
|
+
windowResize: false
|
|
144
|
+
});
|
|
145
|
+
return isPointInRectangle({
|
|
146
|
+
p: cursor,
|
|
147
|
+
top: top.value,
|
|
148
|
+
left: left.value,
|
|
149
|
+
bottom: bottom.value,
|
|
150
|
+
right: right.value
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function onMousemove(e) {
|
|
154
|
+
const cursor = { x: e.clientX, y: e.clientY };
|
|
155
|
+
isInsideFrom.value = elementOverlap(cursor, from);
|
|
156
|
+
isInsideTo.value = elementOverlap(cursor, to);
|
|
157
|
+
isInsideTriangle.value = triangleOverlap(cursor, from, to);
|
|
158
|
+
}
|
|
159
|
+
function fromMouseenter() {
|
|
160
|
+
isInsideFrom.value = true;
|
|
161
|
+
}
|
|
162
|
+
function fromMouseleave() {
|
|
163
|
+
isInsideFrom.value = false;
|
|
164
|
+
}
|
|
165
|
+
function toMouseenter() {
|
|
166
|
+
isInsideTo.value = true;
|
|
167
|
+
}
|
|
168
|
+
function toMouseleave(e) {
|
|
169
|
+
isInsideTo.value = false;
|
|
170
|
+
}
|
|
171
|
+
function onResize() {
|
|
172
|
+
const cursor = { x: x.value, y: y.value };
|
|
173
|
+
isInsideFrom.value = elementOverlap(cursor, from);
|
|
174
|
+
isInsideTo.value = elementOverlap(cursor, to);
|
|
175
|
+
isInsideTriangle.value = triangleOverlap(cursor, from, to);
|
|
176
|
+
}
|
|
177
|
+
function initialize() {
|
|
178
|
+
cancelListener.value.abort();
|
|
179
|
+
cancelListener.value = new AbortController();
|
|
180
|
+
useEventListener(from, "mouseenter", fromMouseenter, {
|
|
181
|
+
signal: cancelListener.value.signal
|
|
182
|
+
});
|
|
183
|
+
useEventListener(from, "mouseleave", fromMouseleave, {
|
|
184
|
+
signal: cancelListener.value.signal
|
|
185
|
+
});
|
|
186
|
+
useEventListener(to, "mouseenter", toMouseenter, {
|
|
187
|
+
signal: cancelListener.value.signal
|
|
188
|
+
});
|
|
189
|
+
useEventListener(to, "mouseleave", toMouseleave, {
|
|
190
|
+
signal: cancelListener.value.signal
|
|
191
|
+
});
|
|
192
|
+
useEventListener(document, "mousemove", onMousemove, {
|
|
193
|
+
signal: cancelListener.value.signal
|
|
194
|
+
});
|
|
195
|
+
useResizeObserver(to, onResize);
|
|
196
|
+
}
|
|
197
|
+
function destroy() {
|
|
198
|
+
coords.value = [];
|
|
199
|
+
isInsideFrom.value = false;
|
|
200
|
+
isInsideTo.value = false;
|
|
201
|
+
isInsideTriangle.value = false;
|
|
202
|
+
cancelListener.value.abort();
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
coords,
|
|
206
|
+
isInsideFrom,
|
|
207
|
+
isInsideTo,
|
|
208
|
+
isInsideTriangle,
|
|
209
|
+
initialize,
|
|
210
|
+
destroy
|
|
211
|
+
};
|
|
212
|
+
}
|
|
@@ -5,7 +5,7 @@ export function useMenuItem(args) {
|
|
|
5
5
|
const { instanceId, viewId } = args;
|
|
6
6
|
const { initializeState } = useMenuState(instanceId);
|
|
7
7
|
const state = initializeState();
|
|
8
|
-
const { getView,
|
|
8
|
+
const { getView, unselectDescendingViews } = useMenuView(instanceId);
|
|
9
9
|
const view = getView(viewId);
|
|
10
10
|
if (!view) {
|
|
11
11
|
throw new Error(`View ${viewId} not found`);
|
|
@@ -53,7 +53,7 @@ export function useMenuItem(args) {
|
|
|
53
53
|
if (instance) {
|
|
54
54
|
instance.active = true;
|
|
55
55
|
unselectSiblings(id);
|
|
56
|
-
|
|
56
|
+
unselectDescendingViews(viewId);
|
|
57
57
|
if (view) {
|
|
58
58
|
state.input.view = view.id;
|
|
59
59
|
}
|
|
@@ -7,7 +7,7 @@ export function useMenuKeyListener(instanceId) {
|
|
|
7
7
|
const {
|
|
8
8
|
selectView,
|
|
9
9
|
unselectView,
|
|
10
|
-
|
|
10
|
+
unselectUnrelatedViews,
|
|
11
11
|
unselectAllViews,
|
|
12
12
|
getView,
|
|
13
13
|
getNextView,
|
|
@@ -101,11 +101,11 @@ export function useMenuKeyListener(instanceId) {
|
|
|
101
101
|
if (prevIndex >= 0) {
|
|
102
102
|
const { selectItem } = useMenuItem({ instanceId, viewId });
|
|
103
103
|
selectItem(enabledItems[prevIndex]?.id);
|
|
104
|
-
|
|
104
|
+
unselectUnrelatedViews(viewId);
|
|
105
105
|
} else if (prevIndex !== -1) {
|
|
106
106
|
const { selectItem } = useMenuItem({ instanceId, viewId });
|
|
107
107
|
selectItem(enabledItems[enabledItems.length - 1]?.id);
|
|
108
|
-
|
|
108
|
+
unselectUnrelatedViews(viewId);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
function onArrowDown(e) {
|
|
@@ -125,7 +125,7 @@ export function useMenuKeyListener(instanceId) {
|
|
|
125
125
|
if (nextIndex >= 0) {
|
|
126
126
|
const { selectItem } = useMenuItem({ instanceId, viewId });
|
|
127
127
|
selectItem(enabledItems[nextIndex]?.id);
|
|
128
|
-
|
|
128
|
+
unselectUnrelatedViews(viewId);
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
function onEscape(e) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type MaybeRef, type ComputedRef } from 'vue';
|
|
2
|
+
import type { Interaction } from '../../types.js';
|
|
3
|
+
interface UseMenuRemoteArgs {
|
|
4
|
+
viewId: string;
|
|
5
|
+
instanceId: MaybeRef<string>;
|
|
6
|
+
mappedChannelId: MaybeRef<string>;
|
|
7
|
+
mappedTrigger: ComputedRef<Interaction[]>;
|
|
8
|
+
}
|
|
9
|
+
export declare function useMenuRemote(args: UseMenuRemoteArgs): {
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
onMouseenter: () => void;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { toValue } from "vue";
|
|
2
|
+
import { useMenuChannel } from "./useMenuChannel.mjs";
|
|
3
|
+
export function useMenuRemote(args) {
|
|
4
|
+
const { viewId, instanceId, mappedChannelId, mappedTrigger } = args;
|
|
5
|
+
const { selectChannel } = useMenuChannel({
|
|
6
|
+
instanceId,
|
|
7
|
+
viewId
|
|
8
|
+
});
|
|
9
|
+
function onClick() {
|
|
10
|
+
if (mappedTrigger.value.includes("click")) {
|
|
11
|
+
selectChannel(toValue(mappedChannelId));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function onMouseenter() {
|
|
15
|
+
if (mappedTrigger.value.includes("mouseenter")) {
|
|
16
|
+
selectChannel(toValue(mappedChannelId));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
onClick,
|
|
21
|
+
onMouseenter
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -11,8 +11,6 @@ type UseMenuTriggerArgs = {
|
|
|
11
11
|
export declare function useMenuTrigger(args: UseMenuTriggerArgs): {
|
|
12
12
|
onMouseenter: () => void;
|
|
13
13
|
onClick: (e: MouseEvent) => void;
|
|
14
|
-
|
|
15
|
-
initialize: () => void;
|
|
16
|
-
destroy: () => void;
|
|
14
|
+
onEnter: (e: KeyboardEvent) => void;
|
|
17
15
|
};
|
|
18
16
|
export {};
|
|
@@ -1,139 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ref,
|
|
3
|
-
computed,
|
|
4
|
-
watch,
|
|
5
|
-
toValue
|
|
6
|
-
} from "vue";
|
|
7
|
-
import {
|
|
8
|
-
useEventListener,
|
|
9
|
-
useElementBounding,
|
|
10
|
-
useMagicKeys,
|
|
11
|
-
useFocus,
|
|
12
|
-
onKeyStroke
|
|
13
|
-
} from "@vueuse/core";
|
|
1
|
+
import { useMagicKeys, useFocus } from "@vueuse/core";
|
|
14
2
|
import { useMenuView } from "./useMenuView.mjs";
|
|
15
3
|
import { useMenuState } from "./useMenuState.mjs";
|
|
16
4
|
export function useMenuTrigger(args) {
|
|
17
5
|
const { instanceId, viewId, itemId, mappedTrigger, mappedDisabled, elRef } = args;
|
|
18
|
-
let cancelPointermove = void 0;
|
|
19
|
-
const mouseleaveCoordinates = ref(void 0);
|
|
20
6
|
const { getView, selectView, unselectView } = useMenuView(instanceId);
|
|
21
7
|
const view = getView(viewId);
|
|
22
8
|
const { initializeState } = useMenuState(instanceId);
|
|
23
9
|
const state = initializeState();
|
|
24
10
|
const { focused } = useFocus(elRef);
|
|
25
|
-
const isInsideTriangle = ref(false);
|
|
26
|
-
const isInsideTrigger = ref(false);
|
|
27
|
-
const isInsideContent = ref(false);
|
|
28
|
-
const isOutside = computed(() => {
|
|
29
|
-
return !isInsideTrigger.value && !isInsideContent.value && !isInsideTriangle.value;
|
|
30
|
-
});
|
|
31
11
|
const { shift, control } = useMagicKeys();
|
|
32
|
-
function resetState() {
|
|
33
|
-
mouseleaveCoordinates.value = void 0;
|
|
34
|
-
isInsideTriangle.value = false;
|
|
35
|
-
}
|
|
36
|
-
function disableCursor() {
|
|
37
|
-
state.input.disabled = [...state.input.disabled, "pointer"];
|
|
38
|
-
}
|
|
39
|
-
function enableCursor() {
|
|
40
|
-
state.input.disabled = state.input.disabled.filter((x) => x !== "pointer");
|
|
41
|
-
}
|
|
42
|
-
function extendTriangle(vertices, pixelAmount) {
|
|
43
|
-
const centroid = {
|
|
44
|
-
x: (vertices[0].x + vertices[1].x + vertices[2].x) / 3,
|
|
45
|
-
y: (vertices[0].y + vertices[1].y + vertices[2].y) / 3
|
|
46
|
-
};
|
|
47
|
-
function extendPoint(vertex) {
|
|
48
|
-
const dir = {
|
|
49
|
-
x: vertex.x - centroid.x,
|
|
50
|
-
y: vertex.y - centroid.y
|
|
51
|
-
};
|
|
52
|
-
const distance = Math.sqrt(dir.x * dir.x + dir.y * dir.y);
|
|
53
|
-
const unitDir = {
|
|
54
|
-
x: dir.x / distance,
|
|
55
|
-
y: dir.y / distance
|
|
56
|
-
};
|
|
57
|
-
const scaledDir = {
|
|
58
|
-
x: unitDir.x * pixelAmount,
|
|
59
|
-
y: unitDir.y * pixelAmount
|
|
60
|
-
};
|
|
61
|
-
return {
|
|
62
|
-
x: vertex.x + scaledDir.x,
|
|
63
|
-
y: vertex.y + scaledDir.y
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return [
|
|
67
|
-
extendPoint(vertices[0]),
|
|
68
|
-
extendPoint(vertices[1]),
|
|
69
|
-
extendPoint(vertices[2])
|
|
70
|
-
];
|
|
71
|
-
}
|
|
72
|
-
function isPointInTriangle(args2) {
|
|
73
|
-
const { p, a, b, c } = args2;
|
|
74
|
-
const v0 = { x: c.x - a.x, y: c.y - a.y };
|
|
75
|
-
const v1 = { x: b.x - a.x, y: b.y - a.y };
|
|
76
|
-
const v2 = { x: p.x - a.x, y: p.y - a.y };
|
|
77
|
-
const dot00 = v0.x * v0.x + v0.y * v0.y;
|
|
78
|
-
const dot01 = v0.x * v1.x + v0.y * v1.y;
|
|
79
|
-
const dot02 = v0.x * v2.x + v0.y * v2.y;
|
|
80
|
-
const dot11 = v1.x * v1.x + v1.y * v1.y;
|
|
81
|
-
const dot12 = v1.x * v2.x + v1.y * v2.y;
|
|
82
|
-
const invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
|
83
|
-
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
84
|
-
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
|
85
|
-
return u >= 0 && v >= 0 && u + v <= 1;
|
|
86
|
-
}
|
|
87
|
-
function isPointInRectangle(args2) {
|
|
88
|
-
const { p, top, left, bottom, right } = args2;
|
|
89
|
-
return p.x >= left && p.x <= right && p.y >= top && p.y <= bottom;
|
|
90
|
-
}
|
|
91
|
-
async function onPointermove(e) {
|
|
92
|
-
if (!mouseleaveCoordinates.value || !view?.children.content) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const mouseCoordinates = { x: e.clientX, y: e.clientY };
|
|
96
|
-
const { top, left, bottom, right } = useElementBounding(
|
|
97
|
-
view.children.content
|
|
98
|
-
);
|
|
99
|
-
const {
|
|
100
|
-
top: topTrigger,
|
|
101
|
-
left: leftTrigger,
|
|
102
|
-
bottom: bottomTrigger,
|
|
103
|
-
right: rightTrigger
|
|
104
|
-
} = useElementBounding(elRef);
|
|
105
|
-
const rightDistance = Math.abs(right.value - mouseleaveCoordinates.value.x);
|
|
106
|
-
const leftDistance = Math.abs(left.value - mouseleaveCoordinates.value.x);
|
|
107
|
-
const mappedX = rightDistance < leftDistance ? right : left;
|
|
108
|
-
const [a, b, c] = extendTriangle(
|
|
109
|
-
[
|
|
110
|
-
mouseleaveCoordinates.value,
|
|
111
|
-
{ x: mappedX.value, y: top.value },
|
|
112
|
-
{ x: mappedX.value, y: bottom.value }
|
|
113
|
-
],
|
|
114
|
-
16
|
|
115
|
-
);
|
|
116
|
-
isInsideTriangle.value = isPointInTriangle({
|
|
117
|
-
p: mouseCoordinates,
|
|
118
|
-
a,
|
|
119
|
-
b,
|
|
120
|
-
c
|
|
121
|
-
});
|
|
122
|
-
isInsideContent.value = isPointInRectangle({
|
|
123
|
-
p: mouseCoordinates,
|
|
124
|
-
top: top.value,
|
|
125
|
-
left: left.value,
|
|
126
|
-
bottom: bottom.value,
|
|
127
|
-
right: right.value
|
|
128
|
-
});
|
|
129
|
-
isInsideTrigger.value = isPointInRectangle({
|
|
130
|
-
p: mouseCoordinates,
|
|
131
|
-
top: topTrigger.value,
|
|
132
|
-
left: leftTrigger.value,
|
|
133
|
-
bottom: bottomTrigger.value,
|
|
134
|
-
right: rightTrigger.value
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
12
|
function onRightClick(e) {
|
|
138
13
|
switch (e.button) {
|
|
139
14
|
case 2:
|
|
@@ -162,8 +37,6 @@ export function useMenuTrigger(args) {
|
|
|
162
37
|
}
|
|
163
38
|
}
|
|
164
39
|
function onMouseenter() {
|
|
165
|
-
cancelPointermove?.();
|
|
166
|
-
resetState();
|
|
167
40
|
if (mappedTrigger.value.includes("mouseenter") && !mappedDisabled.value && viewId && view) {
|
|
168
41
|
if (mappedTrigger.value[0].includes("mouseenter")) {
|
|
169
42
|
state.active = true;
|
|
@@ -173,9 +46,6 @@ export function useMenuTrigger(args) {
|
|
|
173
46
|
if (!itemId) {
|
|
174
47
|
state.input.view = viewId;
|
|
175
48
|
}
|
|
176
|
-
if (itemId) {
|
|
177
|
-
disableCursor();
|
|
178
|
-
}
|
|
179
49
|
}
|
|
180
50
|
}
|
|
181
51
|
}
|
|
@@ -211,57 +81,9 @@ export function useMenuTrigger(args) {
|
|
|
211
81
|
}
|
|
212
82
|
}
|
|
213
83
|
}
|
|
214
|
-
function onMouseleave(e) {
|
|
215
|
-
if (mappedTrigger.value.includes("mouseleave") && viewId) {
|
|
216
|
-
mouseleaveCoordinates.value = { x: e.clientX, y: e.clientY };
|
|
217
|
-
cancelPointermove = useEventListener("pointermove", onPointermove);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
function initialize() {
|
|
221
|
-
watch(
|
|
222
|
-
() => view?.active,
|
|
223
|
-
async (value) => {
|
|
224
|
-
if (value) {
|
|
225
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
226
|
-
toValue(elRef)?.blur();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
);
|
|
230
|
-
watch(isInsideTriangle, async (value, oldValue) => {
|
|
231
|
-
if (value && !oldValue) {
|
|
232
|
-
disableCursor();
|
|
233
|
-
} else if (!value && oldValue) {
|
|
234
|
-
enableCursor();
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
watch(isInsideContent, (value, oldValue) => {
|
|
238
|
-
if (value && !oldValue) {
|
|
239
|
-
cancelPointermove?.();
|
|
240
|
-
resetState();
|
|
241
|
-
enableCursor();
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
watch(isOutside, (value, oldValue) => {
|
|
245
|
-
if (!cancelPointermove) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (value && !oldValue) {
|
|
249
|
-
unselectView(viewId);
|
|
250
|
-
cancelPointermove();
|
|
251
|
-
enableCursor();
|
|
252
|
-
resetState();
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
onKeyStroke("Enter", onEnter);
|
|
256
|
-
}
|
|
257
|
-
function destroy() {
|
|
258
|
-
cancelPointermove?.();
|
|
259
|
-
}
|
|
260
84
|
return {
|
|
261
85
|
onMouseenter,
|
|
262
86
|
onClick,
|
|
263
|
-
|
|
264
|
-
initialize,
|
|
265
|
-
destroy
|
|
87
|
+
onEnter
|
|
266
88
|
};
|
|
267
89
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type MaybeRef } from 'vue';
|
|
2
2
|
import type { MenuView } from '../../types/index.js';
|
|
3
|
-
type
|
|
3
|
+
type InitializeViewArgs = Pick<MenuView, 'id' | 'parent' | 'placement'>;
|
|
4
4
|
export declare function useMenuView(instanceId: MaybeRef<string>): {
|
|
5
5
|
currentView: import("vue").ComputedRef<MenuView>;
|
|
6
|
-
initializeView: (args:
|
|
6
|
+
initializeView: (args: InitializeViewArgs) => MenuView;
|
|
7
7
|
deleteView: (id: string) => void;
|
|
8
8
|
getView: (id: string) => MenuView | undefined;
|
|
9
9
|
getRelativeViewIndex: (id: string) => number;
|
|
@@ -14,7 +14,8 @@ export declare function useMenuView(instanceId: MaybeRef<string>): {
|
|
|
14
14
|
getParentView: (id: string) => MenuView | undefined;
|
|
15
15
|
selectView: (id: string) => void;
|
|
16
16
|
unselectView: (id: string) => void;
|
|
17
|
-
|
|
17
|
+
unselectUnrelatedViews: (id: string) => void;
|
|
18
|
+
unselectDescendingViews: (id: string) => void;
|
|
18
19
|
unselectAllViews: () => void;
|
|
19
20
|
};
|
|
20
21
|
export {};
|