57 lines
1.4 KiB
Vue
57 lines
1.4 KiB
Vue
|
<script setup lang="ts">
|
||
|
import type { AriaAnnounceType, AriaLive } from '~/composables/aria/types'
|
||
|
import { useAriaAnnouncer } from '~/composables/aria'
|
||
|
import type { LocaleObject } from '#i18n'
|
||
|
|
||
|
const router = useRouter()
|
||
|
const { t, locale, locales } = useI18n()
|
||
|
const { ariaAnnouncer, announce } = useAriaAnnouncer()
|
||
|
|
||
|
const localeMap = (locales.value as LocaleObject[]).reduce((acc, l) => {
|
||
|
acc[l.code!] = l.name!
|
||
|
return acc
|
||
|
}, {} as Record<string, string>)
|
||
|
|
||
|
let ariaLive = $ref<AriaLive>('polite')
|
||
|
let ariaMessage = $ref<string>('')
|
||
|
|
||
|
const onMessage = (event: AriaAnnounceType, message?: string) => {
|
||
|
if (event === 'announce')
|
||
|
ariaMessage = message!
|
||
|
else if (event === 'mute')
|
||
|
ariaLive = 'off'
|
||
|
else
|
||
|
ariaLive = 'polite'
|
||
|
}
|
||
|
|
||
|
watch(locale, (l, ol) => {
|
||
|
if (ol) {
|
||
|
announce(t('a11y.locale_changing', [localeMap[ol] ?? ol]))
|
||
|
setTimeout(() => {
|
||
|
announce(t('a11y.locale_changed', [localeMap[l] ?? l]))
|
||
|
}, 1000)
|
||
|
}
|
||
|
}, { immediate: true })
|
||
|
|
||
|
onMounted(() => {
|
||
|
ariaAnnouncer.on(onMessage)
|
||
|
router.beforeEach(() => {
|
||
|
announce(t('a11y.loading_page'))
|
||
|
})
|
||
|
router.afterEach((to, from) => {
|
||
|
from && setTimeout(() => {
|
||
|
requestAnimationFrame(() => {
|
||
|
const title = document.title.trim().split('|')
|
||
|
announce(t('a11y.route_loaded', [title[0]]))
|
||
|
})
|
||
|
}, 512)
|
||
|
})
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<p sr-only role="status" :aria-live="ariaLive">
|
||
|
{{ ariaMessage }}
|
||
|
</p>
|
||
|
</template>
|