Skip to content

Commit d4dbcc6

Browse files
committedFeb 5, 2024
feat(client): add RouteLink component
1 parent 6edc2d2 commit d4dbcc6

File tree

5 files changed

+120
-91
lines changed

5 files changed

+120
-91
lines changed
 

‎packages/client/src/components/VPLink.ts ‎packages/client/src/components/RouteLink.ts

+36-7
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,55 @@ const guardEvent = (event: MouseEvent): boolean | void => {
2323
return true
2424
}
2525

26-
export interface VPLinkProps extends HTMLAttributes {
26+
export interface RouteLinkProps extends HTMLAttributes {
27+
/**
28+
* Whether the link is active to have an active class
29+
*
30+
* Notice that the active status is not automatically determined according to the current route.
31+
*
32+
* @default false
33+
*/
34+
active?: boolean
35+
36+
/**
37+
* The class to add when the link is active
38+
*
39+
* @default 'route-link-active'
40+
*/
41+
activeClass?: string
42+
43+
/**
44+
* The route path to link to
45+
*/
2746
to: string
2847
}
2948

30-
export const VPLink: FunctionalComponent<
31-
VPLinkProps,
49+
/**
50+
* Component to render a link to another route.
51+
*
52+
* It's similar to `RouterLink` in `vue-router`, but more lightweight.
53+
*
54+
* It's recommended to use `RouteLink` in VuePress.
55+
*/
56+
export const RouteLink: FunctionalComponent<
57+
RouteLinkProps,
3258
Record<never, never>,
3359
{
3460
default: () => string | VNode | (string | VNode)[]
3561
}
36-
> = ({ to = '', ...attrs }, { slots }) => {
62+
> = (
63+
{ active = false, activeClass = 'route-link-active', to, ...attrs },
64+
{ slots },
65+
) => {
3766
const router = useRouter()
3867
const path = withBase(resolveRoutePath(to))
3968

4069
return h(
4170
'a',
4271
{
43-
class: 'vp-link',
44-
href: path,
4572
...attrs,
73+
class: ['route-link', { [activeClass]: active }],
74+
href: path,
4675
onClick: (event: MouseEvent = {} as MouseEvent) => {
4776
guardEvent(event) ? router.push(to).catch() : Promise.resolve()
4877
},
@@ -51,4 +80,4 @@ export const VPLink: FunctionalComponent<
5180
)
5281
}
5382

54-
VPLink.displayName = 'VPLink'
83+
RouteLink.displayName = 'RouteLink'
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export * from './ClientOnly.js'
22
export * from './Content.js'
3-
export * from './VPLink.js'
3+
export * from './RouteLink.js'
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { App } from 'vue'
2-
import { ClientOnly, Content, VPLink } from './components/index.js'
2+
import { ClientOnly, Content, RouteLink } from './components/index.js'
33

44
/**
55
* Register global built-in components
@@ -8,6 +8,6 @@ export const setupGlobalComponents = (app: App): void => {
88
/* eslint-disable vue/match-component-file-name, vue/no-reserved-component-names */
99
app.component('ClientOnly', ClientOnly)
1010
app.component('Content', Content)
11-
app.component('VPLink', VPLink)
11+
app.component('RouteLink', RouteLink)
1212
/* eslint-enable vue/match-component-file-name, vue/no-reserved-component-names */
1313
}

‎packages/markdown/src/plugins/linksPlugin/linksPlugin.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export interface LinksPluginOptions {
88
/**
99
* Tag for internal links
1010
*
11-
* @default 'VPLink'
11+
* @default 'RouteLink'
1212
*/
13-
internalTag?: 'a' | 'VPLink' | 'RouterLink'
13+
internalTag?: 'a' | 'RouteLink' | 'RouterLink'
1414

1515
/**
1616
* Additional attributes for external links
@@ -37,7 +37,7 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
3737
options: LinksPluginOptions = {},
3838
): void => {
3939
// tag of internal links
40-
const internalTag = options.internalTag || 'VPLink'
40+
const internalTag = options.internalTag || 'RouteLink'
4141

4242
// attrs that going to be added to external links
4343
const externalAttrs = {
@@ -93,7 +93,7 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
9393
// convert
9494
// <a href="hrefLink">
9595
// to
96-
// <VPLink to="toProp">
96+
// <RouteLink to="toProp">
9797

9898
// notice that the path and hash are encoded by markdown-it
9999
const rawPath = internalLinkMatch[1]
@@ -106,14 +106,14 @@ export const linksPlugin: PluginWithOptions<LinksPluginOptions> = (
106106
filePathRelative,
107107
)
108108

109-
if (['RouterLink', 'VPLink'].includes(internalTag)) {
109+
if (['RouterLink', 'RouteLink'].includes(internalTag)) {
110110
// convert starting tag of internal link to `internalTag`
111111
token.tag = internalTag
112112
// replace the original `href` attr with `to` attr
113113
hrefAttr[0] = 'to'
114114
// normalize markdown file path to route path
115115
// we are removing the `base` from absolute path because it should not be
116-
// passed to `<VPLink>` or `<RouterLink>`
116+
// passed to `<RouteLink>` or `<RouterLink>`
117117
const normalizedPath = normalizeRoutePath(
118118
absolutePath.replace(new RegExp(`^${base}`), '/'),
119119
)

‎packages/markdown/tests/plugins/linksPlugin.spec.ts

+75-75
Original file line numberDiff line numberDiff line change
@@ -293,24 +293,24 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
293293

294294
expect(rendered).toEqual(
295295
[
296-
'<VPLink to="foo.html">foo1</VPLink>',
297-
'<VPLink to="foo.html#hash">foo2</VPLink>',
298-
'<VPLink to="foo.html">foo3</VPLink>',
299-
'<VPLink to="../bar.html">bar1</VPLink>',
300-
'<VPLink to="../bar.html#hash">bar2</VPLink>',
301-
'<VPLink to="../bar.html">bar3</VPLink>',
302-
'<VPLink to="foo/bar.html">foobar1</VPLink>',
303-
'<VPLink to="foo/bar.html#hash">foobar2</VPLink>',
304-
'<VPLink to="../foo/bar.html">foobar3</VPLink>',
305-
'<VPLink to="../foo/bar.html#hash">foobar4</VPLink>',
306-
'<VPLink to="index.html">index1</VPLink>',
307-
'<VPLink to="index.html#hash">index2</VPLink>',
308-
'<VPLink to="index.html">index3</VPLink>',
309-
'<VPLink to="../">index4</VPLink>',
310-
'<VPLink to="../foo/bar/">index5</VPLink>',
311-
'<VPLink to="index.html">readme1</VPLink>',
312-
'<VPLink to="../#hash">readme2</VPLink>',
313-
'<VPLink to="../foo/bar/">readme3</VPLink>',
296+
'<RouteLink to="foo.html">foo1</RouteLink>',
297+
'<RouteLink to="foo.html#hash">foo2</RouteLink>',
298+
'<RouteLink to="foo.html">foo3</RouteLink>',
299+
'<RouteLink to="../bar.html">bar1</RouteLink>',
300+
'<RouteLink to="../bar.html#hash">bar2</RouteLink>',
301+
'<RouteLink to="../bar.html">bar3</RouteLink>',
302+
'<RouteLink to="foo/bar.html">foobar1</RouteLink>',
303+
'<RouteLink to="foo/bar.html#hash">foobar2</RouteLink>',
304+
'<RouteLink to="../foo/bar.html">foobar3</RouteLink>',
305+
'<RouteLink to="../foo/bar.html#hash">foobar4</RouteLink>',
306+
'<RouteLink to="index.html">index1</RouteLink>',
307+
'<RouteLink to="index.html#hash">index2</RouteLink>',
308+
'<RouteLink to="index.html">index3</RouteLink>',
309+
'<RouteLink to="../">index4</RouteLink>',
310+
'<RouteLink to="../foo/bar/">index5</RouteLink>',
311+
'<RouteLink to="index.html">readme1</RouteLink>',
312+
'<RouteLink to="../#hash">readme2</RouteLink>',
313+
'<RouteLink to="../foo/bar/">readme3</RouteLink>',
314314
]
315315
.map((a) => `<p>${a}</p>`)
316316
.join('\n') + '\n',
@@ -420,24 +420,24 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
420420

421421
expect(rendered).toEqual(
422422
[
423-
'<VPLink to="/path/to/foo.html">foo1</VPLink>',
424-
'<VPLink to="/path/to/foo.html#hash">foo2</VPLink>',
425-
'<VPLink to="/path/to/foo.html">foo3</VPLink>',
426-
'<VPLink to="/path/bar.html">bar1</VPLink>',
427-
'<VPLink to="/path/bar.html#hash">bar2</VPLink>',
428-
'<VPLink to="/path/bar.html">bar3</VPLink>',
429-
'<VPLink to="/path/to/foo/bar.html">foobar1</VPLink>',
430-
'<VPLink to="/path/to/foo/bar.html#hash">foobar2</VPLink>',
431-
'<VPLink to="/path/foo/bar.html">foobar3</VPLink>',
432-
'<VPLink to="/path/foo/bar.html#hash">foobar4</VPLink>',
433-
'<VPLink to="/path/to/">index1</VPLink>',
434-
'<VPLink to="/path/to/#hash">index2</VPLink>',
435-
'<VPLink to="/path/to/">index3</VPLink>',
436-
'<VPLink to="/path/">index4</VPLink>',
437-
'<VPLink to="/path/foo/bar/">index5</VPLink>',
438-
'<VPLink to="/path/to/">readme1</VPLink>',
439-
'<VPLink to="/path/#hash">readme2</VPLink>',
440-
'<VPLink to="/path/foo/bar/">readme3</VPLink>',
423+
'<RouteLink to="/path/to/foo.html">foo1</RouteLink>',
424+
'<RouteLink to="/path/to/foo.html#hash">foo2</RouteLink>',
425+
'<RouteLink to="/path/to/foo.html">foo3</RouteLink>',
426+
'<RouteLink to="/path/bar.html">bar1</RouteLink>',
427+
'<RouteLink to="/path/bar.html#hash">bar2</RouteLink>',
428+
'<RouteLink to="/path/bar.html">bar3</RouteLink>',
429+
'<RouteLink to="/path/to/foo/bar.html">foobar1</RouteLink>',
430+
'<RouteLink to="/path/to/foo/bar.html#hash">foobar2</RouteLink>',
431+
'<RouteLink to="/path/foo/bar.html">foobar3</RouteLink>',
432+
'<RouteLink to="/path/foo/bar.html#hash">foobar4</RouteLink>',
433+
'<RouteLink to="/path/to/">index1</RouteLink>',
434+
'<RouteLink to="/path/to/#hash">index2</RouteLink>',
435+
'<RouteLink to="/path/to/">index3</RouteLink>',
436+
'<RouteLink to="/path/">index4</RouteLink>',
437+
'<RouteLink to="/path/foo/bar/">index5</RouteLink>',
438+
'<RouteLink to="/path/to/">readme1</RouteLink>',
439+
'<RouteLink to="/path/#hash">readme2</RouteLink>',
440+
'<RouteLink to="/path/foo/bar/">readme3</RouteLink>',
441441
]
442442
.map((a) => `<p>${a}</p>`)
443443
.join('\n') + '\n',
@@ -549,24 +549,24 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
549549

550550
expect(rendered).toEqual(
551551
[
552-
`<VPLink to="/${encoded中}/${encoded文}/foo.html">foo1</VPLink>`,
553-
`<VPLink to="/${encoded中}/${encoded文}/foo.html#hash">foo2</VPLink>`,
554-
`<VPLink to="/${encoded中}/${encoded文}/foo.html">foo3</VPLink>`,
555-
`<VPLink to="/${encoded中}/bar.html">bar1</VPLink>`,
556-
`<VPLink to="/${encoded中}/bar.html#hash">bar2</VPLink>`,
557-
`<VPLink to="/${encoded中}/bar.html">bar3</VPLink>`,
558-
`<VPLink to="/${encoded中}/${encoded文}/foo/bar.html">foobar1</VPLink>`,
559-
`<VPLink to="/${encoded中}/${encoded文}/foo/bar.html#hash">foobar2</VPLink>`,
560-
`<VPLink to="/${encoded中}/foo/bar.html">foobar3</VPLink>`,
561-
`<VPLink to="/${encoded中}/foo/bar.html#hash">foobar4</VPLink>`,
562-
`<VPLink to="/${encoded中}/${encoded文}/">index1</VPLink>`,
563-
`<VPLink to="/${encoded中}/${encoded文}/#hash">index2</VPLink>`,
564-
`<VPLink to="/${encoded中}/${encoded文}/">index3</VPLink>`,
565-
`<VPLink to="/${encoded中}/">index4</VPLink>`,
566-
`<VPLink to="/${encoded中}/foo/bar/">index5</VPLink>`,
567-
`<VPLink to="/${encoded中}/${encoded文}/">readme1</VPLink>`,
568-
`<VPLink to="/${encoded中}/#hash">readme2</VPLink>`,
569-
`<VPLink to="/${encoded中}/foo/bar/">readme3</VPLink>`,
552+
`<RouteLink to="/${encoded中}/${encoded文}/foo.html">foo1</RouteLink>`,
553+
`<RouteLink to="/${encoded中}/${encoded文}/foo.html#hash">foo2</RouteLink>`,
554+
`<RouteLink to="/${encoded中}/${encoded文}/foo.html">foo3</RouteLink>`,
555+
`<RouteLink to="/${encoded中}/bar.html">bar1</RouteLink>`,
556+
`<RouteLink to="/${encoded中}/bar.html#hash">bar2</RouteLink>`,
557+
`<RouteLink to="/${encoded中}/bar.html">bar3</RouteLink>`,
558+
`<RouteLink to="/${encoded中}/${encoded文}/foo/bar.html">foobar1</RouteLink>`,
559+
`<RouteLink to="/${encoded中}/${encoded文}/foo/bar.html#hash">foobar2</RouteLink>`,
560+
`<RouteLink to="/${encoded中}/foo/bar.html">foobar3</RouteLink>`,
561+
`<RouteLink to="/${encoded中}/foo/bar.html#hash">foobar4</RouteLink>`,
562+
`<RouteLink to="/${encoded中}/${encoded文}/">index1</RouteLink>`,
563+
`<RouteLink to="/${encoded中}/${encoded文}/#hash">index2</RouteLink>`,
564+
`<RouteLink to="/${encoded中}/${encoded文}/">index3</RouteLink>`,
565+
`<RouteLink to="/${encoded中}/">index4</RouteLink>`,
566+
`<RouteLink to="/${encoded中}/foo/bar/">index5</RouteLink>`,
567+
`<RouteLink to="/${encoded中}/${encoded文}/">readme1</RouteLink>`,
568+
`<RouteLink to="/${encoded中}/#hash">readme2</RouteLink>`,
569+
`<RouteLink to="/${encoded中}/foo/bar/">readme3</RouteLink>`,
570570
]
571571
.map((a) => `<p>${a}</p>`)
572572
.join('\n') + '\n',
@@ -677,24 +677,24 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
677677

678678
expect(rendered).toEqual(
679679
[
680-
'<VPLink to="/path/to/foo.html">foo1</VPLink>',
681-
'<VPLink to="/path/to/foo.html#hash">foo2</VPLink>',
682-
'<VPLink to="/path/to/foo.html">foo3</VPLink>',
683-
'<VPLink to="/path/bar.html">bar1</VPLink>',
684-
'<VPLink to="/path/bar.html#hash">bar2</VPLink>',
685-
'<VPLink to="/path/bar.html">bar3</VPLink>',
686-
'<VPLink to="/path/to/foo/bar.html">foobar1</VPLink>',
687-
'<VPLink to="/path/to/foo/bar.html#hash">foobar2</VPLink>',
688-
'<VPLink to="/path/foo/bar.html">foobar3</VPLink>',
689-
'<VPLink to="/path/foo/bar.html#hash">foobar4</VPLink>',
690-
'<VPLink to="/path/to/">index1</VPLink>',
691-
'<VPLink to="/path/to/#hash">index2</VPLink>',
692-
'<VPLink to="/path/to/">index3</VPLink>',
693-
'<VPLink to="/path/">index4</VPLink>',
694-
'<VPLink to="/path/foo/bar/">index5</VPLink>',
695-
'<VPLink to="/path/to/">readme1</VPLink>',
696-
'<VPLink to="/path/#hash">readme2</VPLink>',
697-
'<VPLink to="/path/foo/bar/">readme3</VPLink>',
680+
'<RouteLink to="/path/to/foo.html">foo1</RouteLink>',
681+
'<RouteLink to="/path/to/foo.html#hash">foo2</RouteLink>',
682+
'<RouteLink to="/path/to/foo.html">foo3</RouteLink>',
683+
'<RouteLink to="/path/bar.html">bar1</RouteLink>',
684+
'<RouteLink to="/path/bar.html#hash">bar2</RouteLink>',
685+
'<RouteLink to="/path/bar.html">bar3</RouteLink>',
686+
'<RouteLink to="/path/to/foo/bar.html">foobar1</RouteLink>',
687+
'<RouteLink to="/path/to/foo/bar.html#hash">foobar2</RouteLink>',
688+
'<RouteLink to="/path/foo/bar.html">foobar3</RouteLink>',
689+
'<RouteLink to="/path/foo/bar.html#hash">foobar4</RouteLink>',
690+
'<RouteLink to="/path/to/">index1</RouteLink>',
691+
'<RouteLink to="/path/to/#hash">index2</RouteLink>',
692+
'<RouteLink to="/path/to/">index3</RouteLink>',
693+
'<RouteLink to="/path/">index4</RouteLink>',
694+
'<RouteLink to="/path/foo/bar/">index5</RouteLink>',
695+
'<RouteLink to="/path/to/">readme1</RouteLink>',
696+
'<RouteLink to="/path/#hash">readme2</RouteLink>',
697+
'<RouteLink to="/path/foo/bar/">readme3</RouteLink>',
698698
]
699699
.map((a) => `<p>${a}</p>`)
700700
.join('\n') + '\n',
@@ -812,9 +812,9 @@ describe('@vuepress/markdown > plugins > linksPlugin', () => {
812812

813813
expect(rendered).toEqual(
814814
[
815-
'<VPLink to="/path/to/">md</VPLink>',
816-
'<VPLink to="/base/path/to/">md-with-redundant-base</VPLink>',
817-
'<VPLink to="/path/to/">html</VPLink>',
815+
'<RouteLink to="/path/to/">md</RouteLink>',
816+
'<RouteLink to="/base/path/to/">md-with-redundant-base</RouteLink>',
817+
'<RouteLink to="/path/to/">html</RouteLink>',
818818
]
819819
.map((a) => `<p>${a}</p>`)
820820
.join('\n') + '\n',

0 commit comments

Comments
 (0)
Please sign in to comment.