fix(reader): ignore keyboard shortcuts in shadow dom inputs

Keyboard events bubbling up from within a shadow DOM (such as the PDF
viewer's embedded find bar) report the custom element host as the event
target rather than the inner input field. This caused the reader's
global shortcuts to incorrectly trigger while typing.

Resolved by checking e.composedPath() to determine the true origin
of the event.

Closes #291
This commit is contained in:
neon
2026-06-09 18:18:21 +00:00
parent 9efd48c72b
commit c8401f2fa4
5 changed files with 8 additions and 10 deletions
@@ -656,7 +656,8 @@ const isNearBookmark = computed(() => audioBookmarks.bookmarks.value.some((b) =>
// ── Keyboard shortcuts ────────────────────────────────────────────────────────
function handleKey(e: KeyboardEvent) {
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return
const target = (e.composedPath?.()[0] || e.target) as HTMLElement | null
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target?.isContentEditable) return
if (showChapters.value || showSettings.value || showSleepTimer.value || showSpeedPicker.value) return
if (e.key === ' ' || e.key === 'k') {
e.preventDefault()
@@ -434,7 +434,8 @@ function onWheel(e: WheelEvent) {
// ── Keyboard ───────────────────────────────────────────────────────────────────
function onKeyDown(e: KeyboardEvent) {
if ((e.target as HTMLElement).tagName === 'INPUT') return
const target = (e.composedPath?.()[0] || e.target) as HTMLElement | null
if (target?.tagName === 'INPUT') return
const isRtl = direction.value === 'rtl'
switch (e.key) {
@@ -123,9 +123,7 @@ describe('useReaderKeyboardShortcuts', () => {
document.body.appendChild(input)
input.focus()
const event = new KeyboardEvent('keydown', { key: 't', bubbles: true })
Object.defineProperty(event, 'target', { value: input })
document.dispatchEvent(event)
input.dispatchEvent(new KeyboardEvent('keydown', { key: 't', bubbles: true }))
expect(handlers.toggleSidebar).not.toHaveBeenCalled()
document.body.removeChild(input)
@@ -137,9 +135,7 @@ describe('useReaderKeyboardShortcuts', () => {
document.body.appendChild(textarea)
textarea.focus()
const event = new KeyboardEvent('keydown', { key: 's', bubbles: true })
Object.defineProperty(event, 'target', { value: textarea })
document.dispatchEvent(event)
textarea.dispatchEvent(new KeyboardEvent('keydown', { key: 's', bubbles: true }))
expect(handlers.toggleSearch).not.toHaveBeenCalled()
document.body.removeChild(textarea)
@@ -208,7 +208,7 @@ export function useFoliateInput(
}
function handleKeydown(e: KeyboardEvent) {
const target = e.target as HTMLElement
const target = (e.composedPath?.()[0] || e.target) as HTMLElement | null
if (target?.tagName === 'INPUT' || target?.tagName === 'TEXTAREA' || target?.isContentEditable) return
const view = getViewEl()
if (!view) return
@@ -17,7 +17,7 @@ export function useReaderKeyboardShortcuts(handlers: ShortcutHandlers) {
const showHelpModal = ref(false)
function onKeyDown(e: KeyboardEvent) {
const target = e.target as HTMLElement | null
const target = (e.composedPath?.()[0] || e.target) as HTMLElement | null
if (target && (INTERACTIVE_TAGS.has(target.tagName) || target.isContentEditable)) return
switch (e.key) {