fix: disable j/k keyboard shortcut when enabled virtual scroller

TAKAHASHI Shuuji 2024-04-22 13:04:12 +09:00
rodzic 9d327f17aa
commit 06f8bb8388
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: F15C887632129F5E
1 zmienionych plików z 40 dodań i 34 usunięć

Wyświetl plik

@ -7,6 +7,7 @@ export default defineNuxtPlugin(({ $scrollToTop }) => {
const router = useRouter() const router = useRouter()
const i18n = useNuxtApp().$i18n const i18n = useNuxtApp().$i18n
const { y } = useWindowScroll({ behavior: 'instant' }) const { y } = useWindowScroll({ behavior: 'instant' })
const virtualScroller = usePreferences('experimentalVirtualScroller')
// disable shortcuts when focused on inputs (https://vueuse.org/core/usemagickeys/#conditionally-disable) // disable shortcuts when focused on inputs (https://vueuse.org/core/usemagickeys/#conditionally-disable)
const activeElement = useActiveElement() const activeElement = useActiveElement()
@ -78,48 +79,53 @@ export default defineNuxtPlugin(({ $scrollToTop }) => {
} }
whenever(logicAnd(isAuthenticated, notUsingInput, keys['.']), showNewItems) whenever(logicAnd(isAuthenticated, notUsingInput, keys['.']), showNewItems)
const statusSelector = '[aria-roledescription="status-card"]' // TODO: virtual scroller cannot load off-screen post
// that prevents focusing next post properly
// we disabled this shortcut when enabled virtual scroller
if (!virtualScroller.value) {
const statusSelector = '[aria-roledescription="status-card"]'
// find the nearest status element id traversing up from the current active element // find the nearest status element id traversing up from the current active element
// `activeElement` can be some of an element within a status element // `activeElement` can be some of an element within a status element
// otherwise, reach to the root `<html>` // otherwise, reach to the root `<html>`
function getActiveStatueId(element: HTMLElement): string | undefined { function getActiveStatueId(element: HTMLElement): string | undefined {
if (element.nodeName === 'HTML') if (element.nodeName === 'HTML')
return undefined return undefined
if (element.matches(statusSelector)) if (element.matches(statusSelector))
return element.id return element.id
return getActiveStatueId(element.parentNode as HTMLElement) return getActiveStatueId(element.parentNode as HTMLElement)
} }
function focusNextOrPreviousStatus(direction: 'next' | 'previous') { function focusNextOrPreviousStatus(direction: 'next' | 'previous') {
const activeStatusId = activeElement.value ? getActiveStatueId(activeElement.value) : undefined const activeStatusId = activeElement.value ? getActiveStatueId(activeElement.value) : undefined
const nextOrPreviousStatusId = getNextOrPreviousStatusId(activeStatusId, direction) const nextOrPreviousStatusId = getNextOrPreviousStatusId(activeStatusId, direction)
if (nextOrPreviousStatusId) { if (nextOrPreviousStatusId) {
const status = document.getElementById(nextOrPreviousStatusId) const status = document.getElementById(nextOrPreviousStatusId)
if (status) { if (status) {
status.focus({ preventScroll: true }) status.focus({ preventScroll: true })
const topBarHeight = 58 const topBarHeight = 58
y.value += status.getBoundingClientRect().top - topBarHeight y.value += status.getBoundingClientRect().top - topBarHeight
}
} }
} }
}
function getNextOrPreviousStatusId(currentStatusId: string | undefined, direction: 'next' | 'previous'): string | undefined { function getNextOrPreviousStatusId(currentStatusId: string | undefined, direction: 'next' | 'previous'): string | undefined {
const statusIds = [...document.querySelectorAll(statusSelector)].map(s => s.id) const statusIds = [...document.querySelectorAll(statusSelector)].map(s => s.id)
if (currentStatusId === undefined) { if (currentStatusId === undefined) {
// if there is no selection, always focus on the first status // if there is no selection, always focus on the first status
return statusIds[0] return statusIds[0]
}
const currentIndex = statusIds.findIndex(id => id === currentStatusId)
const statusId = direction === 'next'
? statusIds[Math.min(currentIndex + 1, statusIds.length)]
: statusIds[Math.max(0, currentIndex - 1)]
return statusId
} }
const currentIndex = statusIds.findIndex(id => id === currentStatusId) whenever(logicAnd(notUsingInput, keys.j), () => focusNextOrPreviousStatus('next'))
const statusId = direction === 'next' whenever(logicAnd(notUsingInput, keys.k), () => focusNextOrPreviousStatus('previous'))
? statusIds[Math.min(currentIndex + 1, statusIds.length)]
: statusIds[Math.max(0, currentIndex - 1)]
return statusId
} }
whenever(logicAnd(notUsingInput, keys.j), () => focusNextOrPreviousStatus('next'))
whenever(logicAnd(notUsingInput, keys.k), () => focusNextOrPreviousStatus('previous'))
}) })