@jskit-ai/shell-web 0.1.251 → 0.1.252
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/fixtures/adaptive-shell/src/main.js +6 -3
- package/package.json +2 -2
- package/patterns/application-shell/example/src/pages/home/index.vue +15 -5
- package/patterns/application-shell/example/tests/e2e/adaptive-shell.spec.ts +1 -1
- package/src/architecture/inspectVueArchitecture.js +1092 -336
- package/src/client/asyncModuleRecovery/runtime.js +116 -0
- package/src/client/components/ShellLayout.vue +18 -288
- package/src/client/components/ShellMenuLinkItem.vue +3 -21
- package/src/client/components/ShellOutlet.vue +2 -24
- package/src/client/components/ShellRouteTransition.vue +16 -114
- package/src/client/components/ShellSurfaceAwareMenuLinkItem.vue +5 -100
- package/src/client/components/ShellTabLinkItem.vue +5 -101
- package/src/client/composables/useShellNavigationLink.js +85 -0
- package/src/client/composables/useShellPullToRefresh.js +260 -0
- package/src/client/error/index.js +1 -1
- package/src/client/error/inject.js +4 -1
- package/src/client/error/policy.js +4 -13
- package/src/client/error/presenters.js +4 -9
- package/src/client/error/store.js +1 -1
- package/src/client/navigation/linkResolver.js +5 -27
- package/src/client/navigation/usePaths.js +1 -21
- package/src/client/placement/index.js +2 -0
- package/src/client/placement/inject.js +4 -1
- package/src/client/placement/runtime.js +2 -4
- package/src/client/placement/surfaceContext.js +11 -8
- package/src/client/placement/validators.js +18 -65
- package/src/client/providers/ShellWebClientProvider.js +100 -356
- package/src/client/requestRecovery/runtime.js +29 -77
- package/src/client/runtime/bootstrapRuntime.js +5 -4
- package/src/client/runtime/refreshRuntime.js +122 -0
- package/src/client/support/gestureTargets.js +26 -0
- package/src/client/support/menuLinkTarget.js +35 -19
- package/src/client/support/routeParams.js +26 -0
- package/src/client/support/routeSwipeGesture.js +88 -0
- package/src/client/support/routeTransitionKey.js +1 -3
- package/src/client/support/shellLayoutClass.js +32 -0
- package/test/bootstrapRuntime.test.js +98 -0
- package/test/errorActions.test.js +2 -1
- package/test/errorRuntime.test.js +30 -0
- package/test/linkResolver.test.js +23 -1
- package/test/menuLinkTarget.test.js +77 -0
- package/test/routeSwipeGesture.test.js +49 -0
- package/test/settingsPlacementContract.test.js +16 -6
- package/test/shellGestureSupport.test.js +46 -0
- package/test/surfaceContext.test.js +53 -0
- package/test/useShellPullToRefresh.test.js +123 -0
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
import { useRoute, useRouter } from "vue-router";
|
|
10
10
|
import { useDisplay } from "vuetify";
|
|
11
11
|
import { normalizePathname } from "@jskit-ai/kernel/shared";
|
|
12
|
-
import { resolveShellLinkPath } from "../navigation/linkResolver.js";
|
|
13
12
|
import {
|
|
14
13
|
useWebPlacementContext,
|
|
15
14
|
useWebPlacementRuntime
|
|
@@ -25,6 +24,9 @@ import {
|
|
|
25
24
|
resolveMenuLinkTarget
|
|
26
25
|
} from "../support/menuLinkTarget.js";
|
|
27
26
|
import { resolveShellRouteTransitionKey } from "../support/routeTransitionKey.js";
|
|
27
|
+
import { createRouteSwipeGesture } from "../support/routeSwipeGesture.js";
|
|
28
|
+
import { isPrimaryTouchPointer, isShellGestureIgnoredTarget } from "../support/gestureTargets.js";
|
|
29
|
+
import { readViewportWidth, resolveShellLayoutClass } from "../support/shellLayoutClass.js";
|
|
28
30
|
|
|
29
31
|
const props = defineProps({
|
|
30
32
|
enabled: {
|
|
@@ -55,13 +57,9 @@ const revision = ref(
|
|
|
55
57
|
);
|
|
56
58
|
const transitionDirection = ref("none");
|
|
57
59
|
let unsubscribe = null;
|
|
58
|
-
|
|
60
|
+
const swipeGesture = createRouteSwipeGesture();
|
|
59
61
|
let stopSwipeClassWatch = null;
|
|
60
62
|
|
|
61
|
-
const SWIPE_MIN_DISTANCE = 36;
|
|
62
|
-
const SWIPE_MAX_VERTICAL_DRIFT = 120;
|
|
63
|
-
const SWIPE_MIN_VELOCITY = 0.08;
|
|
64
|
-
|
|
65
63
|
onMounted(() => {
|
|
66
64
|
if (typeof placementRuntime.subscribe !== "function") {
|
|
67
65
|
unsubscribe = null;
|
|
@@ -111,16 +109,7 @@ onBeforeUnmount(() => {
|
|
|
111
109
|
}
|
|
112
110
|
});
|
|
113
111
|
|
|
114
|
-
const resolvedLayoutClass = computed(() =>
|
|
115
|
-
const displayName = String(display?.name?.value || "").trim().toLowerCase();
|
|
116
|
-
if (displayName === "xs" || displayName === "sm") {
|
|
117
|
-
return "compact";
|
|
118
|
-
}
|
|
119
|
-
if (displayName === "md") {
|
|
120
|
-
return "medium";
|
|
121
|
-
}
|
|
122
|
-
return "expanded";
|
|
123
|
-
});
|
|
112
|
+
const resolvedLayoutClass = computed(() => resolveShellLayoutClass(display?.name?.value, readViewportWidth()));
|
|
124
113
|
|
|
125
114
|
const currentPathname = computed(() =>
|
|
126
115
|
normalizeComparablePathname(resolveRuntimePathname(route?.path || route?.fullPath || "/"))
|
|
@@ -158,16 +147,7 @@ const primaryNavEntries = computed(() => {
|
|
|
158
147
|
placementContext: contextValue,
|
|
159
148
|
scopedSuffix: entryProps.scopedSuffix,
|
|
160
149
|
unscopedSuffix: entryProps.unscopedSuffix,
|
|
161
|
-
routeParams
|
|
162
|
-
resolvePagePath(relativePath, options = {}) {
|
|
163
|
-
return resolveShellLinkPath({
|
|
164
|
-
context: contextValue,
|
|
165
|
-
surface: options.surface,
|
|
166
|
-
relativePath,
|
|
167
|
-
params: routeParams,
|
|
168
|
-
strictParams: options.strictParams !== false
|
|
169
|
-
});
|
|
170
|
-
}
|
|
150
|
+
routeParams
|
|
171
151
|
});
|
|
172
152
|
const navigationTarget = resolveSurfaceNavigationTargetFromPlacementContext(contextValue, {
|
|
173
153
|
path: target,
|
|
@@ -259,18 +239,12 @@ const swipeNavigationEnabled = computed(() =>
|
|
|
259
239
|
);
|
|
260
240
|
|
|
261
241
|
function handlePointerDown(event) {
|
|
262
|
-
if (!swipeNavigationEnabled.value || !
|
|
263
|
-
|
|
242
|
+
if (!swipeNavigationEnabled.value || !isPrimaryTouchPointer(event) || isShellGestureIgnoredTarget(event.target)) {
|
|
243
|
+
swipeGesture.reset();
|
|
264
244
|
return;
|
|
265
245
|
}
|
|
266
246
|
|
|
267
|
-
|
|
268
|
-
pointerId: event.pointerId,
|
|
269
|
-
startX: event.clientX,
|
|
270
|
-
startY: event.clientY,
|
|
271
|
-
startTime: performance.now(),
|
|
272
|
-
cancelled: false
|
|
273
|
-
};
|
|
247
|
+
swipeGesture.start(event);
|
|
274
248
|
try {
|
|
275
249
|
event.target?.setPointerCapture?.(event.pointerId);
|
|
276
250
|
} catch {
|
|
@@ -279,60 +253,24 @@ function handlePointerDown(event) {
|
|
|
279
253
|
}
|
|
280
254
|
|
|
281
255
|
function handlePointerMove(event) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const deltaX = event.clientX - activeSwipe.startX;
|
|
287
|
-
const deltaY = event.clientY - activeSwipe.startY;
|
|
288
|
-
const absX = Math.abs(deltaX);
|
|
289
|
-
const absY = Math.abs(deltaY);
|
|
290
|
-
|
|
291
|
-
if (absY > SWIPE_MAX_VERTICAL_DRIFT || (absY > 28 && absY > absX * 1.3)) {
|
|
292
|
-
activeSwipe.cancelled = true;
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (absX > 10 && absX > absY) {
|
|
256
|
+
const { claim, offset } = swipeGesture.move(event);
|
|
257
|
+
if (claim) {
|
|
297
258
|
event.preventDefault();
|
|
298
259
|
}
|
|
299
|
-
|
|
300
|
-
if (isAcceptedSwipe({ deltaX, deltaY, elapsed: Math.max(performance.now() - activeSwipe.startTime, 1) })) {
|
|
301
|
-
const offset = deltaX < 0 ? 1 : -1;
|
|
302
|
-
activeSwipe = null;
|
|
260
|
+
if (offset) {
|
|
303
261
|
navigateBySwipe(offset);
|
|
304
262
|
}
|
|
305
263
|
}
|
|
306
264
|
|
|
307
265
|
function handlePointerEnd(event) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const swipe = activeSwipe;
|
|
313
|
-
activeSwipe = null;
|
|
314
|
-
|
|
315
|
-
if (swipe.cancelled || !swipeNavigationEnabled.value) {
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const deltaX = event.clientX - swipe.startX;
|
|
320
|
-
const deltaY = event.clientY - swipe.startY;
|
|
321
|
-
const elapsed = Math.max(performance.now() - swipe.startTime, 1);
|
|
322
|
-
const absX = Math.abs(deltaX);
|
|
323
|
-
const velocity = absX / elapsed;
|
|
324
|
-
|
|
325
|
-
if (!isAcceptedSwipe({ deltaX, deltaY, elapsed, velocity })) {
|
|
326
|
-
return;
|
|
266
|
+
const offset = swipeGesture.end(event);
|
|
267
|
+
if (offset && swipeNavigationEnabled.value) {
|
|
268
|
+
navigateBySwipe(offset);
|
|
327
269
|
}
|
|
328
|
-
|
|
329
|
-
navigateBySwipe(deltaX < 0 ? 1 : -1);
|
|
330
270
|
}
|
|
331
271
|
|
|
332
272
|
function handlePointerCancel(event) {
|
|
333
|
-
|
|
334
|
-
activeSwipe = null;
|
|
335
|
-
}
|
|
273
|
+
swipeGesture.cancel(event);
|
|
336
274
|
}
|
|
337
275
|
|
|
338
276
|
function navigateBySwipe(offset = 0) {
|
|
@@ -345,18 +283,6 @@ function navigateBySwipe(offset = 0) {
|
|
|
345
283
|
void router.push(nextEntry.href).catch(() => {});
|
|
346
284
|
}
|
|
347
285
|
|
|
348
|
-
function isAcceptedSwipe({ deltaX = 0, deltaY = 0, elapsed = 1, velocity = null } = {}) {
|
|
349
|
-
const absX = Math.abs(deltaX);
|
|
350
|
-
const absY = Math.abs(deltaY);
|
|
351
|
-
const resolvedVelocity = velocity == null ? absX / Math.max(elapsed, 1) : velocity;
|
|
352
|
-
return Boolean(
|
|
353
|
-
absX >= SWIPE_MIN_DISTANCE &&
|
|
354
|
-
absY <= SWIPE_MAX_VERTICAL_DRIFT &&
|
|
355
|
-
absX > absY &&
|
|
356
|
-
resolvedVelocity >= SWIPE_MIN_VELOCITY
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
286
|
function normalizeComparablePathname(value = "") {
|
|
361
287
|
const raw = String(value || "").trim();
|
|
362
288
|
if (!raw) {
|
|
@@ -384,30 +310,6 @@ function pathMatchesNavigationEntry(pathname = "", entry = {}) {
|
|
|
384
310
|
}
|
|
385
311
|
return pathname === target || pathname.startsWith(`${target}/`);
|
|
386
312
|
}
|
|
387
|
-
|
|
388
|
-
function isPrimaryPointerEvent(event) {
|
|
389
|
-
return event?.isPrimary !== false && event?.button === 0 && event?.pointerType !== "mouse";
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
function isSwipeIgnoredTarget(target) {
|
|
393
|
-
return Boolean(
|
|
394
|
-
target?.closest?.(
|
|
395
|
-
[
|
|
396
|
-
"a",
|
|
397
|
-
"button",
|
|
398
|
-
"input",
|
|
399
|
-
"select",
|
|
400
|
-
"textarea",
|
|
401
|
-
"summary",
|
|
402
|
-
"[role='button']",
|
|
403
|
-
"[role='link']",
|
|
404
|
-
"[role='slider']",
|
|
405
|
-
"[contenteditable='true']",
|
|
406
|
-
"[data-shell-swipe-ignore]"
|
|
407
|
-
].join(",")
|
|
408
|
-
)
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
313
|
</script>
|
|
412
314
|
|
|
413
315
|
<template>
|
|
@@ -1,108 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed } from "vue";
|
|
3
|
-
import { useRoute } from "vue-router";
|
|
4
|
-
import { resolveShellLinkPath } from "../navigation/linkResolver.js";
|
|
5
2
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "../placement/index.js";
|
|
10
|
-
import { resolveMenuLinkIcon } from "../lib/menuIcons.js";
|
|
11
|
-
import { resolveMenuLinkTarget } from "../support/menuLinkTarget.js";
|
|
3
|
+
shellNavigationLinkProps,
|
|
4
|
+
useShellNavigationLink
|
|
5
|
+
} from "../composables/useShellNavigationLink.js";
|
|
12
6
|
import { activateShellNavigationLinkOnSpace } from "../support/navigationLinkKeyboard.js";
|
|
13
7
|
import ShellNavigationTooltip from "./ShellNavigationTooltip.vue";
|
|
14
8
|
|
|
15
|
-
const props = defineProps(
|
|
16
|
-
|
|
17
|
-
type: String,
|
|
18
|
-
default: ""
|
|
19
|
-
},
|
|
20
|
-
to: {
|
|
21
|
-
type: String,
|
|
22
|
-
default: ""
|
|
23
|
-
},
|
|
24
|
-
icon: {
|
|
25
|
-
type: String,
|
|
26
|
-
default: ""
|
|
27
|
-
},
|
|
28
|
-
surface: {
|
|
29
|
-
type: String,
|
|
30
|
-
default: ""
|
|
31
|
-
},
|
|
32
|
-
scopedSuffix: {
|
|
33
|
-
type: String,
|
|
34
|
-
default: "/"
|
|
35
|
-
},
|
|
36
|
-
unscopedSuffix: {
|
|
37
|
-
type: String,
|
|
38
|
-
default: "/"
|
|
39
|
-
},
|
|
40
|
-
disabled: {
|
|
41
|
-
type: Boolean,
|
|
42
|
-
default: false
|
|
43
|
-
},
|
|
44
|
-
exact: {
|
|
45
|
-
type: Boolean,
|
|
46
|
-
default: false
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const route = useRoute();
|
|
51
|
-
const { context: placementContext } = useWebPlacementContext();
|
|
52
|
-
|
|
53
|
-
const currentSurfaceId = computed(() => {
|
|
54
|
-
return resolveSurfaceIdFromPlacementPathname(
|
|
55
|
-
placementContext.value,
|
|
56
|
-
String(route?.path || route?.fullPath || "").trim()
|
|
57
|
-
);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const resolvedTo = computed(() => {
|
|
61
|
-
return resolveMenuLinkTarget({
|
|
62
|
-
to: props.to,
|
|
63
|
-
surface: props.surface,
|
|
64
|
-
currentSurfaceId: currentSurfaceId.value,
|
|
65
|
-
placementContext: placementContext.value,
|
|
66
|
-
scopedSuffix: props.scopedSuffix,
|
|
67
|
-
unscopedSuffix: props.unscopedSuffix,
|
|
68
|
-
routeParams: route.params || {},
|
|
69
|
-
resolvePagePath(relativePath, options = {}) {
|
|
70
|
-
return resolveShellLinkPath({
|
|
71
|
-
context: placementContext.value,
|
|
72
|
-
surface: options.surface,
|
|
73
|
-
relativePath,
|
|
74
|
-
params: route.params || {},
|
|
75
|
-
strictParams: options.strictParams !== false
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const resolvedTarget = computed(() => {
|
|
82
|
-
const target = String(resolvedTo.value || "").trim();
|
|
83
|
-
if (!target) {
|
|
84
|
-
return {
|
|
85
|
-
href: "",
|
|
86
|
-
sameOrigin: true
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const navigationTarget = resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
91
|
-
path: target
|
|
92
|
-
});
|
|
93
|
-
return {
|
|
94
|
-
href: navigationTarget.href,
|
|
95
|
-
sameOrigin: navigationTarget.sameOrigin
|
|
96
|
-
};
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const resolvedIcon = computed(() =>
|
|
100
|
-
resolveMenuLinkIcon({
|
|
101
|
-
icon: props.icon,
|
|
102
|
-
label: props.label,
|
|
103
|
-
to: resolvedTarget.value.href || resolvedTo.value
|
|
104
|
-
})
|
|
105
|
-
);
|
|
9
|
+
const props = defineProps(shellNavigationLinkProps);
|
|
10
|
+
const { resolvedTarget, resolvedIcon } = useShellNavigationLink(props);
|
|
106
11
|
</script>
|
|
107
12
|
|
|
108
13
|
<template>
|
|
@@ -1,107 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed } from "vue";
|
|
3
|
-
import { useRoute } from "vue-router";
|
|
4
|
-
import { resolveShellLinkPath } from "../navigation/linkResolver.js";
|
|
5
2
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "../placement/index.js";
|
|
10
|
-
import { resolveMenuLinkIcon } from "../lib/menuIcons.js";
|
|
11
|
-
import { resolveMenuLinkTarget } from "../support/menuLinkTarget.js";
|
|
12
|
-
|
|
13
|
-
const props = defineProps({
|
|
14
|
-
label: {
|
|
15
|
-
type: String,
|
|
16
|
-
default: ""
|
|
17
|
-
},
|
|
18
|
-
to: {
|
|
19
|
-
type: String,
|
|
20
|
-
default: ""
|
|
21
|
-
},
|
|
22
|
-
icon: {
|
|
23
|
-
type: String,
|
|
24
|
-
default: ""
|
|
25
|
-
},
|
|
26
|
-
surface: {
|
|
27
|
-
type: String,
|
|
28
|
-
default: ""
|
|
29
|
-
},
|
|
30
|
-
scopedSuffix: {
|
|
31
|
-
type: String,
|
|
32
|
-
default: "/"
|
|
33
|
-
},
|
|
34
|
-
unscopedSuffix: {
|
|
35
|
-
type: String,
|
|
36
|
-
default: "/"
|
|
37
|
-
},
|
|
38
|
-
disabled: {
|
|
39
|
-
type: Boolean,
|
|
40
|
-
default: false
|
|
41
|
-
},
|
|
42
|
-
exact: {
|
|
43
|
-
type: Boolean,
|
|
44
|
-
default: false
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const route = useRoute();
|
|
49
|
-
const { context: placementContext } = useWebPlacementContext();
|
|
50
|
-
|
|
51
|
-
const currentSurfaceId = computed(() => {
|
|
52
|
-
return resolveSurfaceIdFromPlacementPathname(
|
|
53
|
-
placementContext.value,
|
|
54
|
-
String(route?.path || route?.fullPath || "").trim()
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const resolvedTo = computed(() => {
|
|
59
|
-
return resolveMenuLinkTarget({
|
|
60
|
-
to: props.to,
|
|
61
|
-
surface: props.surface,
|
|
62
|
-
currentSurfaceId: currentSurfaceId.value,
|
|
63
|
-
placementContext: placementContext.value,
|
|
64
|
-
scopedSuffix: props.scopedSuffix,
|
|
65
|
-
unscopedSuffix: props.unscopedSuffix,
|
|
66
|
-
routeParams: route.params || {},
|
|
67
|
-
resolvePagePath(relativePath, options = {}) {
|
|
68
|
-
return resolveShellLinkPath({
|
|
69
|
-
context: placementContext.value,
|
|
70
|
-
surface: options.surface,
|
|
71
|
-
relativePath,
|
|
72
|
-
params: route.params || {},
|
|
73
|
-
strictParams: options.strictParams !== false
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const resolvedTarget = computed(() => {
|
|
80
|
-
const target = String(resolvedTo.value || "").trim();
|
|
81
|
-
if (!target) {
|
|
82
|
-
return {
|
|
83
|
-
href: "",
|
|
84
|
-
sameOrigin: true
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const navigationTarget = resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
89
|
-
path: target
|
|
90
|
-
});
|
|
91
|
-
return {
|
|
92
|
-
href: navigationTarget.href,
|
|
93
|
-
sameOrigin: navigationTarget.sameOrigin
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const resolvedIcon = computed(() =>
|
|
98
|
-
resolveMenuLinkIcon({
|
|
99
|
-
icon: props.icon,
|
|
100
|
-
label: props.label,
|
|
101
|
-
to: resolvedTarget.value.href || resolvedTo.value
|
|
102
|
-
})
|
|
103
|
-
);
|
|
3
|
+
shellNavigationLinkProps,
|
|
4
|
+
useShellNavigationLink
|
|
5
|
+
} from "../composables/useShellNavigationLink.js";
|
|
104
6
|
|
|
7
|
+
const props = defineProps(shellNavigationLinkProps);
|
|
8
|
+
const { resolvedTarget, resolvedIcon } = useShellNavigationLink(props);
|
|
105
9
|
</script>
|
|
106
10
|
|
|
107
11
|
<template>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { useRoute } from "vue-router";
|
|
3
|
+
import {
|
|
4
|
+
resolveSurfaceIdFromPlacementPathname,
|
|
5
|
+
useWebPlacementContext
|
|
6
|
+
} from "../placement/index.js";
|
|
7
|
+
import { resolveMenuLinkIcon } from "../lib/menuIcons.js";
|
|
8
|
+
import { resolveMenuLinkHref, resolveMenuLinkTarget } from "../support/menuLinkTarget.js";
|
|
9
|
+
|
|
10
|
+
const shellNavigationLinkProps = Object.freeze({
|
|
11
|
+
label: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: ""
|
|
14
|
+
},
|
|
15
|
+
to: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: ""
|
|
18
|
+
},
|
|
19
|
+
icon: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: ""
|
|
22
|
+
},
|
|
23
|
+
surface: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: ""
|
|
26
|
+
},
|
|
27
|
+
scopedSuffix: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: "/"
|
|
30
|
+
},
|
|
31
|
+
unscopedSuffix: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: "/"
|
|
34
|
+
},
|
|
35
|
+
disabled: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false
|
|
38
|
+
},
|
|
39
|
+
exact: {
|
|
40
|
+
type: Boolean,
|
|
41
|
+
default: false
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Surface-aware link resolution shared by the shell menu and tab link items.
|
|
46
|
+
function useShellNavigationLink(props) {
|
|
47
|
+
const route = useRoute();
|
|
48
|
+
const { context: placementContext } = useWebPlacementContext();
|
|
49
|
+
|
|
50
|
+
const resolvedTo = computed(() => {
|
|
51
|
+
const currentSurfaceId = resolveSurfaceIdFromPlacementPathname(
|
|
52
|
+
placementContext.value,
|
|
53
|
+
String(route?.path || route?.fullPath || "").trim()
|
|
54
|
+
);
|
|
55
|
+
return resolveMenuLinkTarget({
|
|
56
|
+
to: props.to,
|
|
57
|
+
surface: props.surface,
|
|
58
|
+
currentSurfaceId,
|
|
59
|
+
placementContext: placementContext.value,
|
|
60
|
+
scopedSuffix: props.scopedSuffix,
|
|
61
|
+
unscopedSuffix: props.unscopedSuffix,
|
|
62
|
+
routeParams: route.params || {}
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const resolvedTarget = computed(() => resolveMenuLinkHref(placementContext.value, resolvedTo.value));
|
|
67
|
+
|
|
68
|
+
const resolvedIcon = computed(() =>
|
|
69
|
+
resolveMenuLinkIcon({
|
|
70
|
+
icon: props.icon,
|
|
71
|
+
label: props.label,
|
|
72
|
+
to: resolvedTarget.value.href || resolvedTo.value
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
resolvedTarget,
|
|
78
|
+
resolvedIcon
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export {
|
|
83
|
+
shellNavigationLinkProps,
|
|
84
|
+
useShellNavigationLink
|
|
85
|
+
};
|