@@ -29,6 +29,10 @@ export interface LinkProps extends Partial<Omit<RouterLinkProps, 'custom'>>, /**
2929 * A rel attribute value to apply on the link. Defaults to "noopener noreferrer" for external links.
3030 */
3131 rel? : ' noopener' | ' noreferrer' | ' nofollow' | ' sponsored' | ' ugc' | (string & {}) | null
32+ /**
33+ * If set to true, no rel attribute will be added to the link
34+ */
35+ noRel? : boolean
3236 /**
3337 * The type of the button when not a link.
3438 * @defaultValue 'button'
@@ -66,6 +70,7 @@ import { hasProtocol } from 'ufo'
6670import { useRoute , RouterLink } from ' vue-router'
6771import { useAppConfig } from ' #imports'
6872import { tv } from ' ../../utils/tv'
73+ import { mergeClasses } from ' ../../utils'
6974import { isPartiallyEqual } from ' ../../utils/link'
7075import ULinkBase from ' ../../components/LinkBase.vue'
7176
@@ -75,25 +80,23 @@ const props = withDefaults(defineProps<LinkProps>(), {
7580 as: ' button' ,
7681 type: ' button' ,
7782 ariaCurrentValue: ' page' ,
78- active: undefined ,
79- activeClass: ' ' ,
80- inactiveClass: ' '
83+ active: undefined
8184})
8285defineSlots <LinkSlots >()
8386
8487const route = useRoute ()
8588
8689const appConfig = useAppConfig () as Link [' AppConfig' ]
8790
88- const routerLinkProps = useForwardProps (reactiveOmit (props , ' as' , ' type' , ' disabled' , ' active' , ' exact' , ' exactQuery' , ' exactHash' , ' activeClass' , ' inactiveClass' , ' to' , ' href' , ' raw' , ' custom' , ' class' ))
91+ const routerLinkProps = useForwardProps (reactiveOmit (props , ' as' , ' type' , ' disabled' , ' active' , ' exact' , ' exactQuery' , ' exactHash' , ' activeClass' , ' inactiveClass' , ' to' , ' href' , ' raw' , ' custom' , ' class' , ' noRel ' ))
8992
9093const ui = computed (() => tv ({
9194 extend: tv (theme ),
9295 ... defu ({
9396 variants: {
9497 active: {
95- true: props .activeClass ,
96- false: props .inactiveClass
98+ true: mergeClasses ( appConfig . ui ?. link ?. variants ?. active ?. true , props .activeClass ) ,
99+ false: mergeClasses ( appConfig . ui ?. link ?. variants ?. active ?. false , props .inactiveClass )
97100 }
98101 }
99102 }, appConfig .ui ?.link || {})
@@ -113,6 +116,27 @@ const isExternal = computed(() => {
113116 return typeof to .value === ' string' && hasProtocol (to .value , { acceptRelative: true })
114117})
115118
119+ const hasTarget = computed (() => !! props .target && props .target !== ' _self' )
120+
121+ const rel = computed (() => {
122+ // If noRel is explicitly set, return null
123+ if (props .noRel ) {
124+ return null
125+ }
126+
127+ // If rel is explicitly set, use it
128+ if (props .rel !== undefined ) {
129+ return props .rel || null
130+ }
131+
132+ // Default to "noopener noreferrer" for external links or links with target
133+ if (isExternal .value || hasTarget .value ) {
134+ return ' noopener noreferrer'
135+ }
136+
137+ return null
138+ })
139+
116140function isLinkActive({ route : linkRoute , isActive , isExactActive }: any ) {
117141 if (props .active !== undefined ) {
118142 return props .active
@@ -168,6 +192,9 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
168192 disabled,
169193 href,
170194 navigate,
195+ rel,
196+ target,
197+ isExternal,
171198 active: isLinkActive({ route: linkRoute, isActive, isExactActive })
172199 }"
173200 />
@@ -181,7 +208,10 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
181208 type,
182209 disabled,
183210 href,
184- navigate
211+ navigate,
212+ rel,
213+ target,
214+ isExternal
185215 }"
186216 :class =" resolveLinkClass({ route: linkRoute, isActive, isExactActive })"
187217 >
@@ -199,7 +229,8 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
199229 type,
200230 disabled,
201231 href: to,
202- target: isExternal ? '_blank' : undefined,
232+ rel,
233+ target,
203234 active,
204235 isExternal
205236 }"
@@ -213,7 +244,8 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
213244 type,
214245 disabled,
215246 href: (to as string),
216- target: isExternal ? '_blank' : undefined,
247+ rel,
248+ target,
217249 isExternal
218250 }"
219251 :class =" resolveLinkClass()"
0 commit comments