1
1
import { isLinkWithProtocol } from '@vuepress/shared'
2
- import type { SlotsType , VNode } from 'vue'
3
- import { computed , defineComponent , h } from 'vue'
2
+ import type { PropType , SlotsType , VNode } from 'vue'
3
+ import { computed , defineComponent , h , toRef } from 'vue'
4
4
import { useRoute } from 'vue-router'
5
5
import { useSiteData } from '../composables/index.js'
6
6
import { RouteLink } from './RouteLink.js'
7
7
8
- export interface AutoLinkProps {
8
+ export interface AutoLinkConfig {
9
9
/**
10
10
* Pattern to determine if the link should be active, which has higher priority than `exact`
11
11
*/
@@ -51,57 +51,11 @@ export interface AutoLinkProps {
51
51
export const AutoLink = defineComponent ( {
52
52
name : 'AutoLink' ,
53
53
54
- props : {
55
- /**
56
- * Pattern to determine if the link should be active, which has higher priority than `exact`
57
- */
58
- activeMatch : {
59
- type : [ String , RegExp ] ,
60
- default : '' ,
61
- } ,
62
-
63
- /**
64
- * The `aria-label` attribute
65
- */
66
- ariaLabel : {
67
- type : String ,
68
- default : '' ,
69
- } ,
70
-
71
- /**
72
- * Whether the link should be active only if the url is an exact match
73
- */
74
- exact : Boolean ,
75
-
76
- /**
77
- * URL of the auto link
78
- */
79
- link : {
80
- type : String ,
81
- required : true ,
82
- } ,
83
-
84
- /**
85
- * The `rel` attribute
86
- */
87
- rel : {
88
- type : String ,
89
- default : '' ,
90
- } ,
54
+ inheritAttrs : false ,
91
55
92
- /**
93
- * The `target` attribute
94
- */
95
- target : {
96
- type : String ,
97
- default : '' ,
98
- } ,
99
-
100
- /**
101
- * Text of the auto link
102
- */
103
- text : {
104
- type : String ,
56
+ props : {
57
+ config : {
58
+ type : Object as PropType < AutoLinkConfig > ,
105
59
required : true ,
106
60
} ,
107
61
} ,
@@ -113,15 +67,16 @@ export const AutoLink = defineComponent({
113
67
} > ,
114
68
115
69
setup ( props , { slots } ) {
70
+ const config = toRef ( props , 'config' )
116
71
const route = useRoute ( )
117
72
const siteData = useSiteData ( )
118
73
119
74
// If the link has non-http protocol
120
- const withProtocol = computed ( ( ) => isLinkWithProtocol ( props . link ) )
75
+ const withProtocol = computed ( ( ) => isLinkWithProtocol ( config . value . link ) )
121
76
122
77
// Resolve the `target` attr
123
78
const linkTarget = computed (
124
- ( ) => props . target || ( withProtocol . value ? '_blank' : undefined ) ,
79
+ ( ) => config . value . target || ( withProtocol . value ? '_blank' : undefined ) ,
125
80
)
126
81
127
82
// If the `target` attr is "_blank"
@@ -134,57 +89,65 @@ export const AutoLink = defineComponent({
134
89
135
90
// Resolve the `rel` attr
136
91
const linkRel = computed (
137
- ( ) => props . rel || ( isBlankTarget . value ? 'noopener noreferrer' : null ) ,
92
+ ( ) =>
93
+ config . value . rel ||
94
+ ( isBlankTarget . value ? 'noopener noreferrer' : null ) ,
138
95
)
139
96
140
97
// Resolve the `aria-label` attr
141
- const linkAriaLabel = computed ( ( ) => props . ariaLabel ?? props . text )
98
+ const linkAriaLabel = computed (
99
+ ( ) => config . value . ariaLabel ?? config . value . text ,
100
+ )
142
101
143
102
// Should be active when current route is a subpath of this link
144
103
const shouldBeActiveInSubpath = computed ( ( ) => {
145
104
// Should not be active in `exact` mode
146
- if ( props . exact ) return false
105
+ if ( config . value . exact ) return false
147
106
148
107
const localePaths = Object . keys ( siteData . value . locales )
149
108
150
109
return localePaths . length
151
110
? // Check all the locales
152
- localePaths . every ( ( key ) => key !== props . link )
111
+ localePaths . every ( ( key ) => key !== config . value . link )
153
112
: // Check root
154
- props . link !== '/'
113
+ config . value . link !== '/'
155
114
} )
156
115
157
116
// If this link is active
158
117
const isActive = computed ( ( ) => {
159
118
if ( ! isInternal . value ) return false
160
119
161
- if ( props . activeMatch ) {
120
+ if ( config . value . activeMatch ) {
162
121
return (
163
- props . activeMatch instanceof RegExp
164
- ? props . activeMatch
165
- : new RegExp ( props . activeMatch , 'u' )
122
+ config . value . activeMatch instanceof RegExp
123
+ ? config . value . activeMatch
124
+ : new RegExp ( config . value . activeMatch , 'u' )
166
125
) . test ( route . path )
167
126
}
168
127
169
128
// If this link is active in subpath
170
129
if ( shouldBeActiveInSubpath . value ) {
171
- return route . path . startsWith ( props . link )
130
+ return route . path . startsWith ( config . value . link )
172
131
}
173
132
174
- return route . path === props . link
133
+ return route . path === config . value . link
175
134
} )
176
135
177
136
return ( ) => {
178
137
const { before, after, default : defaultSlot } = slots
179
138
180
- const content = defaultSlot ?.( ) || [ before ?.( ) , props . text , after ?.( ) ]
139
+ const content = defaultSlot ?.( ) || [
140
+ before ?.( ) ,
141
+ config . value . text ,
142
+ after ?.( ) ,
143
+ ]
181
144
182
145
return isInternal . value
183
146
? h (
184
147
RouteLink ,
185
148
{
186
149
'class' : 'auto-link' ,
187
- 'to' : props . link ,
150
+ 'to' : config . value . link ,
188
151
'active' : isActive . value ,
189
152
'aria-label' : linkAriaLabel . value ,
190
153
} ,
@@ -194,7 +157,7 @@ export const AutoLink = defineComponent({
194
157
'a' ,
195
158
{
196
159
'class' : 'auto-link external-link' ,
197
- 'href' : props . link ,
160
+ 'href' : config . value . link ,
198
161
'aria-label' : linkAriaLabel . value ,
199
162
'rel' : linkRel . value ,
200
163
'target' : linkTarget . value ,
0 commit comments