Skip to content

Commit a581219

Browse files
committed
fix: switch to useAnnouncer + <NuxtAnnouncer>
1 parent eced357 commit a581219

File tree

2 files changed

+73
-76
lines changed

2 files changed

+73
-76
lines changed

app/app.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ if (import.meta.client) {
136136

137137
<AppHeader :show-logo="!isHomepage" />
138138

139+
<NuxtAnnouncer />
140+
139141
<NuxtRouteAnnouncer v-slot="{ message }">
140142
{{ route.name === 'search' ? `${$t('search.title_packages')} - npmx` : message }}
141143
</NuxtRouteAnnouncer>

app/pages/search.vue

Lines changed: 71 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ async function loadMore() {
283283
}
284284
onBeforeUnmount(() => {
285285
updateUrlPage.cancel()
286+
cancelPendingAnnouncements()
286287
})
287288
288289
// Update URL when page changes from scrolling
@@ -584,94 +585,92 @@ defineOgImageComponent('Default', {
584585
})
585586
586587
// -----------------------------------
587-
// Live region debouncing logic
588+
// Live region announcements
588589
// -----------------------------------
589590
const isMobile = useIsMobile()
591+
const { polite } = useAnnouncer()
590592
591-
// Evaluate the text that should be announced to screen readers
592-
const rawLiveRegionMessage = computed(() => {
593-
if (isRateLimited.value) {
594-
return $t('search.rate_limited')
595-
}
596-
597-
// If status is pending, no update phrase needed yet
598-
if (status.value === 'pending') {
599-
return ''
600-
}
601-
602-
if (visibleResults.value && displayResults.value.length > 0) {
603-
if (viewMode.value === 'table' || paginationMode.value === 'paginated') {
604-
const pSize = Math.min(preferredPageSize.value, effectiveTotal.value)
605-
606-
return $t(
607-
'filters.count.showing_paginated',
608-
{
609-
pageSize: pSize.toString(),
610-
count: $n(effectiveTotal.value),
611-
},
612-
effectiveTotal.value,
613-
)
614-
}
615-
616-
if (isRelevanceSort.value) {
617-
return $t(
618-
'search.found_packages',
619-
{ count: $n(visibleResults.value.total) },
620-
visibleResults.value.total,
621-
)
622-
}
593+
const announcePoliteDesktop = debounce((message: string) => {
594+
polite(message)
595+
}, 250)
623596
624-
return $t(
625-
'search.found_packages_sorted',
626-
{ count: $n(effectiveTotal.value) },
627-
effectiveTotal.value,
628-
)
629-
}
597+
const announcePoliteMobile = debounce((message: string) => {
598+
polite(message)
599+
}, 700)
630600
631-
if (status.value === 'success' || status.value === 'error') {
632-
if (displayResults.value.length === 0 && query.value) {
633-
return $t('search.no_results', { query: query.value })
634-
}
601+
function announcePolite(message: string) {
602+
if (isMobile.value) {
603+
announcePoliteDesktop.cancel()
604+
announcePoliteMobile(message)
605+
return
635606
}
636607
637-
return ''
638-
})
639-
640-
const debouncedLiveRegionMessage = ref('')
641-
642-
const updateLiveRegionMobile = debounce((val: string) => {
643-
debouncedLiveRegionMessage.value = val
644-
}, 700)
608+
announcePoliteMobile.cancel()
609+
announcePoliteDesktop(message)
610+
}
645611
646-
const updateLiveRegionDesktop = debounce((val: string) => {
647-
debouncedLiveRegionMessage.value = val
648-
}, 250)
612+
function cancelPendingAnnouncements() {
613+
announcePoliteDesktop.cancel()
614+
announcePoliteMobile.cancel()
615+
}
649616
617+
// Announce search results changes to screen readers
650618
watch(
651-
rawLiveRegionMessage,
652-
newVal => {
653-
if (!newVal) {
654-
updateLiveRegionMobile.cancel()
655-
updateLiveRegionDesktop.cancel()
656-
debouncedLiveRegionMessage.value = ''
619+
() => ({
620+
rateLimited: isRateLimited.value,
621+
searchStatus: status.value,
622+
count: displayResults.value.length,
623+
searchQuery: query.value,
624+
mode: viewMode.value,
625+
pagMode: paginationMode.value,
626+
total: effectiveTotal.value,
627+
}),
628+
({ rateLimited, searchStatus, count, searchQuery, mode, pagMode, total }) => {
629+
if (rateLimited) {
630+
announcePolite($t('search.rate_limited'))
657631
return
658632
}
659633
660-
if (isMobile.value) {
661-
updateLiveRegionDesktop.cancel()
662-
updateLiveRegionMobile(newVal)
663-
} else {
664-
updateLiveRegionMobile.cancel()
665-
updateLiveRegionDesktop(newVal)
634+
// Don't announce while searching
635+
if (searchStatus === 'pending') {
636+
cancelPendingAnnouncements()
637+
return
638+
}
639+
640+
if (count > 0) {
641+
if (mode === 'table' || pagMode === 'paginated') {
642+
const pSize = Math.min(preferredPageSize.value, total)
643+
644+
announcePolite(
645+
$t(
646+
'filters.count.showing_paginated',
647+
{
648+
pageSize: pSize.toString(),
649+
count: $n(total),
650+
},
651+
total,
652+
),
653+
)
654+
} else if (isRelevanceSort.value) {
655+
announcePolite(
656+
$t(
657+
'search.found_packages',
658+
{ count: $n(visibleResults.value?.total ?? 0) },
659+
visibleResults.value?.total ?? 0,
660+
),
661+
)
662+
} else {
663+
announcePolite($t('search.found_packages_sorted', { count: $n(total) }, total))
664+
}
665+
} else if (searchStatus === 'success' || searchStatus === 'error') {
666+
if (searchQuery) {
667+
announcePolite($t('search.no_results', { query: searchQuery }))
668+
} else {
669+
cancelPendingAnnouncements()
670+
}
666671
}
667672
},
668-
{ immediate: true },
669673
)
670-
671-
onBeforeUnmount(() => {
672-
updateLiveRegionMobile.cancel()
673-
updateLiveRegionDesktop.cancel()
674-
})
675674
</script>
676675

677676
<template>
@@ -910,10 +909,6 @@ onBeforeUnmount(() => {
910909
:package-scope="packageScope"
911910
:can-publish-to-scope="canPublishToScope"
912911
/>
913-
914-
<div role="status" class="sr-only">
915-
{{ debouncedLiveRegionMessage }}
916-
</div>
917912
</main>
918913
</template>
919914

0 commit comments

Comments
 (0)