Skip to content

Commit

Permalink
Merge fdc75f6 into e6455e0
Browse files Browse the repository at this point in the history
  • Loading branch information
Mister-Hope authored Apr 9, 2024
2 parents e6455e0 + fdc75f6 commit fa2f3bb
Show file tree
Hide file tree
Showing 12 changed files with 494 additions and 146 deletions.
27 changes: 27 additions & 0 deletions e2e/docs/components/route-link.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,37 @@

- <RouteLink to="/README.md" active="">text</RouteLink>
- <RouteLink to="/README.md" active>text</RouteLink>
- <RouteLink to="/" active="">text</RouteLink>
- <RouteLink to="/" active>text</RouteLink>
- <RouteLink to="/README.md" :active="false">text</RouteLink>
- <RouteLink to="/README.md">text</RouteLink>
- <RouteLink to="/" :active="false">text</RouteLink>
- <RouteLink to="/">text</RouteLink>

### Class

- <RouteLink to="/README.md" class="custom-class">text</RouteLink>
- <RouteLink to="/README.md" active class="custom-class">text</RouteLink>
- <RouteLink to="/" class="custom-class">text</RouteLink>
- <RouteLink to="/" active class="custom-class">text</RouteLink>

### Attrs

- <RouteLink to="/README.md" title="Title">text</RouteLink>
- <RouteLink to="/README.md" target="_blank">text</RouteLink>
- <RouteLink to="/README.md" rel="noopener">text</RouteLink>
- <RouteLink to="/README.md" aria-label="test">text</RouteLink>
- <RouteLink to="/" title="Title">text</RouteLink>
- <RouteLink to="/" target="_blank">text</RouteLink>
- <RouteLink to="/" rel="noopener">text</RouteLink>
- <RouteLink to="/" aria-label="test">text</RouteLink>

### Slots

- <RouteLink to="/README.md"><span>text</span></RouteLink>
- <RouteLink to="/README.md"><span>text</span><span>text</span></RouteLink>
- <RouteLink to="/"><span>text</span></RouteLink>
- <RouteLink to="/"><span>text</span><span>text</span></RouteLink>

### Hash and query

Expand All @@ -56,9 +68,24 @@
- <RouteLink to="/README.md?query=1#hash">text</RouteLink>
- <RouteLink to="/README.md?query=1&query=2#hash">text</RouteLink>
- <RouteLink to="/README.md#hash?query=1&query=2">text</RouteLink>
- <RouteLink to="/#hash">text</RouteLink>
- <RouteLink to="/?query">text</RouteLink>
- <RouteLink to="/?query#hash">text</RouteLink>
- <RouteLink to="/?query=1#hash">text</RouteLink>
- <RouteLink to="/?query=1&query=2#hash">text</RouteLink>
- <RouteLink to="/#hash?query=1&query=2">text</RouteLink>
- <RouteLink to="#hash">text</RouteLink>
- <RouteLink to="?query">text</RouteLink>
- <RouteLink to="?query#hash">text</RouteLink>
- <RouteLink to="?query=1#hash">text</RouteLink>
- <RouteLink to="?query=1&query=2#hash">text</RouteLink>
- <RouteLink to="#hash?query=1&query=2">text</RouteLink>

### Relative

- <RouteLink to="../README.md">text</RouteLink>
- <RouteLink to="../404.md">text</RouteLink>
- <RouteLink to="not-exist.md">text</RouteLink>
- <RouteLink to="../">text</RouteLink>
- <RouteLink to="../404.html">text</RouteLink>
- <RouteLink to="not-exist.html">text</RouteLink>
24 changes: 21 additions & 3 deletions e2e/tests/components/route-link.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ it('RouteLink', () => {

cy.get(`.e2e-theme-content #active + ul > li`).each((el, index) => {
cy.wrap(el).within(() => {
if (index < 2) {
if (index < 4) {
cy.get('a').should('have.attr', 'class', 'route-link route-link-active')
} else {
cy.get('a').should('have.attr', 'class', 'route-link')
Expand All @@ -60,7 +60,7 @@ it('RouteLink', () => {
]
cy.get(`.e2e-theme-content #class + ul > li`).each((el, index) => {
cy.wrap(el).within(() => {
cy.get('a').should('have.attr', 'class', classResults[index])
cy.get('a').should('have.attr', 'class', classResults[index % 2])
cy.get('a').should('have.text', 'text')
})
})
Expand All @@ -70,7 +70,7 @@ it('RouteLink', () => {

cy.get(`.e2e-theme-content #attrs + ul > li`).each((el, index) => {
cy.wrap(el).within(() => {
cy.get('a').should('have.attr', attrName[index], attrValue[index])
cy.get('a').should('have.attr', attrName[index % 4], attrValue[index % 4])
})
})

Expand All @@ -86,6 +86,12 @@ it('RouteLink', () => {
})

const HASH_AND_QUERY_RESULTS = [
`${E2E_BASE}#hash`,
`${E2E_BASE}?query`,
`${E2E_BASE}?query#hash`,
`${E2E_BASE}?query=1#hash`,
`${E2E_BASE}?query=1&query=2#hash`,
`${E2E_BASE}#hash?query=1&query=2`,
`${E2E_BASE}#hash`,
`${E2E_BASE}?query`,
`${E2E_BASE}?query#hash`,
Expand All @@ -105,4 +111,16 @@ it('RouteLink', () => {
cy.get('a').should('have.attr', 'href', HASH_AND_QUERY_RESULTS[index])
})
})

const RELATIVE_RESULTS = [
E2E_BASE,
`${E2E_BASE}404.html`,
`${E2E_BASE}components/not-exist.html`,
]

cy.get(`.e2e-theme-content #relative + ul > li`).each((el, index) => {
cy.wrap(el).within(() => {
cy.get('a').should('have.attr', 'href', RELATIVE_RESULTS[index % 3])
})
})
})
171 changes: 171 additions & 0 deletions packages/client/src/components/AutoLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { isLinkWithProtocol } from '@vuepress/shared'
import type { PropType, SlotsType, VNode } from 'vue'
import { computed, defineComponent, h, toRef } from 'vue'
import { useRoute } from 'vue-router'
import { useSiteData } from '../composables/index.js'
import { RouteLink } from './RouteLink.js'

export interface AutoLinkProps {
/**
* Text of item
*
* 项目文字
*/
text: string

/**
* Aria label of item
*
* 项目无障碍标签
*/
ariaLabel?: string

/**
* Link of item
*
* 当前页面链接
*/
link: string

/**
* Rel of `<a>` tag
*
* `<a>` 标签的 `rel` 属性
*/
rel?: string

/**
* Target of `<a>` tag
*
* `<a>` 标签的 `target` 属性
*/
target?: string

/**
* Regexp mode to be active
*
* 匹配激活的正则表达式
*/
activeMatch?: string
}

export const AutoLink = defineComponent({
name: 'AutoLink',

props: {
/**
* @description Autolink config
*/
config: {
type: Object as PropType<AutoLinkProps>,
required: true,
},

/**
* @description Whether it's active only when exact match
*/
exact: Boolean,
},

slots: Object as SlotsType<{
default?: () => VNode[] | VNode
before?: () => VNode[] | VNode | null
after?: () => VNode[] | VNode | null
}>,

setup(props, { slots }) {
const route = useRoute()
const siteData = useSiteData()

const config = toRef(props, 'config')

// If the link has non-http protocol
const withProtocol = computed(() => isLinkWithProtocol(config.value.link))

// Resolve the `target` attr
const linkTarget = computed(
() => config.value.target || (withProtocol.value ? '_blank' : undefined),
)

// If the `target` attr is "_blank"
const isBlankTarget = computed(() => linkTarget.value === '_blank')

// Render `<RouteLink>` or not
const renderRouteLink = computed(
() => !withProtocol.value && !isBlankTarget.value,
)

// Resolve the `rel` attr
const linkRel = computed(
() =>
config.value.rel ||
(isBlankTarget.value ? 'noopener noreferrer' : null),
)

// Resolve the `aria-label` attr
const linkAriaLabel = computed(
() => config.value.ariaLabel || config.value.text,
)

// Should be active when current route is a subpath of this link
const shouldBeActiveInSubpath = computed(() => {
// Should not be active in `exact` mode
if (props.exact) return false

const localeKeys = Object.keys(siteData.value.locales)

return localeKeys.length
? // Check all the locales
localeKeys.every((key) => key !== config.value.link)
: // Check root
config.value.link !== '/'
})

// If this link is active
const isActive = computed(() =>
renderRouteLink.value
? config.value.activeMatch
? new RegExp(config.value.activeMatch, 'u').test(route.path)
: // If this link is active in subpath
shouldBeActiveInSubpath.value
? route.path.startsWith(config.value.link)
: route.path === config.value.link
: false,
)

return (): VNode => {
const { text, link } = config.value
const { before, after, default: defaultSlot } = slots

const content = defaultSlot?.() || [
before ? before() : null,
text,
after?.(),
]

return renderRouteLink.value
? h(
RouteLink,
{
'class': 'auto-link',
'to': link,
'active': isActive.value,
'aria-label': linkAriaLabel.value,
// Class needs to be merged manually
},
() => content,
)
: h(
'a',
{
'class': 'auto-link anchor-link',
'href': link,
'rel': linkRel.value,
'target': linkTarget.value,
'aria-label': linkAriaLabel.value,
},
content,
)
}
},
})
Loading

0 comments on commit fa2f3bb

Please sign in to comment.