mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 20:19:34 +01:00
74 lines
2.3 KiB
Vue
74 lines
2.3 KiB
Vue
<script lang="ts">
|
|
import type { PrimitiveProps } from 'radix-vue'
|
|
import type { NuxtLinkProps } from '#app'
|
|
|
|
export interface LinkProps extends NuxtLinkProps, Omit<PrimitiveProps, 'asChild'> {
|
|
type?: string
|
|
disabled?: boolean
|
|
active?: boolean
|
|
exact?: boolean
|
|
exactQuery?: boolean
|
|
exactHash?: boolean
|
|
inactiveClass?: string
|
|
}
|
|
</script>
|
|
|
|
<script setup lang="ts">
|
|
import { isEqual } from 'ohash'
|
|
import { Primitive, useForwardProps } from 'radix-vue'
|
|
import { reactiveOmit } from '@vueuse/core'
|
|
import type { RouteLocation } from '#vue-router'
|
|
|
|
defineOptions({ inheritAttrs: false })
|
|
|
|
const props = withDefaults(defineProps<LinkProps>(), { as: 'button', type: 'button', active: undefined })
|
|
|
|
const forward = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'exactQuery', 'exactHash', 'activeClass', 'inactiveClass'))
|
|
|
|
function resolveLinkClass (route: RouteLocation, currentRoute: RouteLocation, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }) {
|
|
if (props.exactQuery && !isEqual(route.query, currentRoute.query)) {
|
|
return props.inactiveClass
|
|
}
|
|
if (props.exactHash && route.hash !== currentRoute.hash) {
|
|
return props.inactiveClass
|
|
}
|
|
|
|
if (props.exact && isExactActive) {
|
|
return props.activeClass
|
|
}
|
|
|
|
if (!props.exact && isActive) {
|
|
return props.activeClass
|
|
}
|
|
|
|
return props.inactiveClass
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Primitive
|
|
v-if="!to"
|
|
:as="as"
|
|
:type="type"
|
|
:disabled="disabled"
|
|
v-bind="$attrs"
|
|
:class="active ? activeClass : inactiveClass"
|
|
>
|
|
<slot v-bind="{ isActive: active }" />
|
|
</Primitive>
|
|
<NuxtLink v-else v-slot="{ route, href, target, rel, navigate, isActive, isExactActive, isExternal }" v-bind="forward" 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 })"
|
|
@click="(e: any) => (!isExternal && !disabled) && navigate(e)"
|
|
>
|
|
<slot v-bind="{ isActive: active !== undefined ? active : (exact ? isExactActive : isActive) }" />
|
|
</a>
|
|
</NuxtLink>
|
|
</template>
|