mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-16 13:08:06 +01:00
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Benjamin Canac <canacb1@gmail.com> Co-authored-by: Sébastien Chopin <atinux@gmail.com>
118 lines
3.0 KiB
Vue
118 lines
3.0 KiB
Vue
<template>
|
|
<component
|
|
:is="as"
|
|
v-if="!to"
|
|
:type="type"
|
|
:disabled="disabled"
|
|
v-bind="$attrs"
|
|
:class="active ? activeClass : inactiveClass"
|
|
>
|
|
<slot v-bind="{ isActive: active }" />
|
|
</component>
|
|
<NuxtLink
|
|
v-else
|
|
v-slot="{ route, href, target, rel, navigate, isActive, isExactActive, isExternal }"
|
|
v-bind="$props"
|
|
custom
|
|
>
|
|
<a
|
|
v-bind="$attrs"
|
|
:href="!disabled ? href : undefined"
|
|
:aria-disabled="disabled ? 'true' : undefined"
|
|
:role="disabled ? 'link' : undefined"
|
|
:rel="rel"
|
|
:target="target"
|
|
:class="active !== undefined ? (active ? activeClass : inactiveClass) : resolveLinkClass(route, $route, { isActive, isExactActive })"
|
|
:tabindex="disabled ? -1 : undefined"
|
|
@click="(e) => (!isExternal && !disabled) && navigate(e)"
|
|
>
|
|
<slot v-bind="{ isActive: active !== undefined ? active : (exact ? isExactActive : isActive) }" />
|
|
</a>
|
|
</NuxtLink>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { isEqual, diff } from 'ohash/utils'
|
|
import { type PropType, defineComponent } from 'vue'
|
|
import { nuxtLinkProps } from '../../utils'
|
|
|
|
export default defineComponent({
|
|
inheritAttrs: false,
|
|
props: {
|
|
...nuxtLinkProps,
|
|
as: {
|
|
type: String,
|
|
default: 'button'
|
|
},
|
|
type: {
|
|
type: String,
|
|
default: 'button'
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
active: {
|
|
type: Boolean,
|
|
default: undefined
|
|
},
|
|
exact: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
exactQuery: {
|
|
type: [Boolean, String] as PropType<boolean | 'partial'>,
|
|
default: false
|
|
},
|
|
exactHash: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
inactiveClass: {
|
|
type: String,
|
|
default: undefined
|
|
}
|
|
},
|
|
setup(props) {
|
|
function isPartiallyEqual(item1: any, item2: any) {
|
|
const diffedKeys = diff(item1, item2).reduce((filtered, q) => {
|
|
if (q.type === 'added') {
|
|
filtered.add(q.key)
|
|
}
|
|
return filtered
|
|
}, new Set<string>())
|
|
|
|
const item1Filtered = Object.fromEntries(Object.entries(item1).filter(([key]) => !diffedKeys.has(key)))
|
|
const item2Filtered = Object.fromEntries(Object.entries(item2).filter(([key]) => !diffedKeys.has(key)))
|
|
|
|
return isEqual(item1Filtered, item2Filtered)
|
|
}
|
|
|
|
function resolveLinkClass(route, $route, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }) {
|
|
if (props.exactQuery === 'partial') {
|
|
if (!isPartiallyEqual(route.query, $route.query)) return props.inactiveClass
|
|
} else if (props.exactQuery === true) {
|
|
if (!isEqual(route.query, $route.query)) return props.inactiveClass
|
|
}
|
|
if (props.exactHash && route.hash !== $route.hash) {
|
|
return props.inactiveClass
|
|
}
|
|
|
|
if (props.exact && isExactActive) {
|
|
return props.activeClass
|
|
}
|
|
|
|
if (!props.exact && isActive) {
|
|
return props.activeClass
|
|
}
|
|
|
|
return props.inactiveClass
|
|
}
|
|
|
|
return {
|
|
resolveLinkClass
|
|
}
|
|
}
|
|
})
|
|
</script>
|