perf(a11y): make menu traversable only when it is open (#1491)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/1740/head
Urata Daiki 2 years ago committed by GitHub
parent 7a737845e5
commit 257f9e68e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -22,6 +22,7 @@ watch(() => route.path, closeSidebar)
useCloseSidebarOnEscape(isSidebarOpen, closeSidebar) useCloseSidebarOnEscape(isSidebarOpen, closeSidebar)
provide('close-sidebar', closeSidebar) provide('close-sidebar', closeSidebar)
provide('is-sidebar-open', isSidebarOpen)
const { frontmatter } = useData() const { frontmatter } = useData()
</script> </script>

@ -1,11 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { DefaultTheme } from 'vitepress/theme' import type { DefaultTheme } from 'vitepress/theme'
import { computed, inject } from 'vue' import { Ref, computed, inject, ref, watchEffect } from 'vue'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar.js'
import { isActive } from '../support/utils.js' import { isActive } from '../support/utils.js'
import VPLink from './VPLink.vue' import VPLink from './VPLink.vue'
withDefaults( const props = withDefaults(
defineProps<{ item: DefaultTheme.SidebarItem; depth?: number }>(), defineProps<{ item: DefaultTheme.SidebarItem; depth?: number }>(),
{ depth: 1 } { depth: 1 }
) )
@ -14,16 +15,32 @@ const { page, frontmatter } = useData()
const maxDepth = computed<number>( const maxDepth = computed<number>(
() => frontmatter.value.sidebarDepth || Infinity () => frontmatter.value.sidebarDepth || Infinity
) )
const active = computed(() =>
isActive(page.value.relativePath, props.item.link)
)
const { isSidebarEnabled } = useSidebar()
const closeSideBar = inject('close-sidebar') as () => void const closeSideBar = inject('close-sidebar') as () => void
const isSidebarOpen = inject('is-sidebar-open') as Ref<boolean>
const link = ref<InstanceType<typeof VPLink> | null>(null)
watchEffect(() => {
if (isSidebarOpen.value && active.value) {
link.value?.$el?.focus()
}
})
</script> </script>
<template> <template>
<VPLink <VPLink
class="link" class="link"
:class="{ active: isActive(page.relativePath, item.link) }" :class="{ active }"
:style="{ paddingLeft: 16 * (depth - 1) + 'px' }" :style="{ paddingLeft: 16 * (depth - 1) + 'px' }"
:href="item.link" :href="item.link"
:tabindex="isSidebarEnabled || isSidebarOpen ? 0 : -1"
@click="closeSideBar" @click="closeSideBar"
ref="link"
> >
<span v-html="item.text" class="link-text" :class="{ light: depth > 1 }"></span> <span v-html="item.text" class="link-text" :class="{ light: depth > 1 }"></span>
</VPLink> </VPLink>

@ -1,10 +1,12 @@
import { computed, onMounted, onUnmounted, Ref, ref, watchEffect } from 'vue' import { computed, onMounted, onUnmounted, Ref, ref, watchEffect } from 'vue'
import { useData, useRoute } from 'vitepress' import { useData, useRoute } from 'vitepress'
import { useMediaQuery } from '@vueuse/core'
import { getSidebar } from '../support/sidebar.js' import { getSidebar } from '../support/sidebar.js'
export function useSidebar() { export function useSidebar() {
const route = useRoute() const route = useRoute()
const { theme, frontmatter } = useData() const { theme, frontmatter } = useData()
const is960 = useMediaQuery('(min-width: 960px)')
const isOpen = ref(false) const isOpen = ref(false)
@ -28,6 +30,8 @@ export function useSidebar() {
) )
}) })
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value)
function open() { function open() {
isOpen.value = true isOpen.value = true
} }
@ -45,6 +49,7 @@ export function useSidebar() {
sidebar, sidebar,
hasSidebar, hasSidebar,
hasAside, hasAside,
isSidebarEnabled,
open, open,
close, close,
toggle toggle

Loading…
Cancel
Save