@dnax/ui 0.0.31 → 0.0.32
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,16 +1,26 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
// QSidebarMenuButton — bouton/lien de menu (équivalent SidebarMenuButton).
|
|
3
|
+
// Avec `to`, le bouton devient un lien routeur : navigation au clic + état actif
|
|
4
|
+
// automatique selon la route courante (pattern QRouteTab).
|
|
3
5
|
import { computed } from "vue"
|
|
4
6
|
import { Icon } from "@iconify/vue"
|
|
5
7
|
import { cn } from "../lib/utils"
|
|
8
|
+
import { useRoute, useRouter } from "vue-router"
|
|
9
|
+
import type { RouteLocationRaw } from "vue-router"
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
label?: string
|
|
9
13
|
/** Icône Iconify (ex. : "lucide:settings") */
|
|
10
14
|
icon?: string
|
|
11
|
-
/** Lien natif (<a>)
|
|
15
|
+
/** Lien natif (<a href>) — sans routeur */
|
|
12
16
|
href?: string
|
|
13
|
-
/**
|
|
17
|
+
/** Destination routeur : rend un lien et active le bouton selon la route courante */
|
|
18
|
+
to?: RouteLocationRaw
|
|
19
|
+
/** Match exact (path + hash) — sinon préfixe de segment de chemin */
|
|
20
|
+
exact?: boolean
|
|
21
|
+
/** router.replace au lieu de router.push */
|
|
22
|
+
replace?: boolean
|
|
23
|
+
/** État actif manuel (ignoré quand `to` est fourni — l'activation suit la route) */
|
|
14
24
|
active?: boolean
|
|
15
25
|
activeClass?: string
|
|
16
26
|
disable?: boolean
|
|
@@ -20,35 +30,75 @@ interface Props {
|
|
|
20
30
|
|
|
21
31
|
const props = withDefaults(defineProps<Props>(), {
|
|
22
32
|
active: false,
|
|
33
|
+
exact: false,
|
|
34
|
+
replace: false,
|
|
23
35
|
activeClass: "",
|
|
24
36
|
disable: false,
|
|
25
37
|
})
|
|
26
38
|
|
|
27
39
|
const emit = defineEmits<{ click: [event: MouseEvent] }>()
|
|
28
40
|
|
|
41
|
+
// Routeur optionnel : sans router installé, `to` dégrade en simple bouton (@click)
|
|
42
|
+
let router: ReturnType<typeof useRouter> | undefined
|
|
43
|
+
let route: ReturnType<typeof useRoute> | undefined
|
|
44
|
+
try {
|
|
45
|
+
router = useRouter()
|
|
46
|
+
route = useRoute()
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
router = undefined
|
|
50
|
+
route = undefined
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// La route courante matche-t-elle `to` ? (même logique que QRouteTab)
|
|
54
|
+
const matches = computed(() => {
|
|
55
|
+
if (!router || !route || !props.to) return false
|
|
56
|
+
const resolved = router.resolve(props.to)
|
|
57
|
+
if (props.exact) {
|
|
58
|
+
return resolved.path === route.path && resolved.hash === route.hash
|
|
59
|
+
}
|
|
60
|
+
const prefix = resolved.path.endsWith("/") ? resolved.path : resolved.path + "/"
|
|
61
|
+
return route.path === resolved.path || route.path.startsWith(prefix)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const effectiveActive = computed(() => (props.to ? matches.value : props.active))
|
|
65
|
+
|
|
66
|
+
const resolvedHref = computed(() => {
|
|
67
|
+
if (props.href) return props.href
|
|
68
|
+
if (props.to && router) return router.resolve(props.to).href
|
|
69
|
+
return undefined
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const tag = computed(() => (resolvedHref.value ? "a" : "button"))
|
|
73
|
+
|
|
29
74
|
const buttonClasses = computed(() =>
|
|
30
75
|
cn(
|
|
31
76
|
"q-sidebar__menu-button",
|
|
32
|
-
|
|
33
|
-
|
|
77
|
+
effectiveActive.value && "q-sidebar__menu-button--active",
|
|
78
|
+
effectiveActive.value && props.activeClass,
|
|
34
79
|
props.disable && "q-sidebar__menu-button--disabled",
|
|
35
80
|
),
|
|
36
81
|
)
|
|
37
82
|
|
|
38
83
|
const onClick = (e: MouseEvent) => {
|
|
39
84
|
if (props.disable) return
|
|
85
|
+
if (props.to && router && !e.defaultPrevented) {
|
|
86
|
+
e.preventDefault()
|
|
87
|
+
if (props.replace) router.replace(props.to)
|
|
88
|
+
else router.push(props.to)
|
|
89
|
+
}
|
|
40
90
|
emit("click", e)
|
|
41
91
|
}
|
|
42
92
|
</script>
|
|
43
93
|
|
|
44
94
|
<template>
|
|
45
95
|
<component
|
|
46
|
-
:is="
|
|
47
|
-
:href="
|
|
48
|
-
:disabled="
|
|
96
|
+
:is="tag"
|
|
97
|
+
:href="resolvedHref"
|
|
98
|
+
:disabled="tag === 'button' ? disable : undefined"
|
|
49
99
|
class="q-sidebar__menu-button"
|
|
50
100
|
:class="buttonClasses"
|
|
51
|
-
:aria-current="
|
|
101
|
+
:aria-current="effectiveActive ? 'page' : undefined"
|
|
52
102
|
@click="onClick"
|
|
53
103
|
>
|
|
54
104
|
<Icon :icon="icon" v-if="icon" class="q-sidebar__menu-button-icon" aria-hidden="true" />
|