Skip to content

Commit 89c5825

Browse files
committed
refactor: extract duplicated isEditableElement util
1 parent ab28b00 commit 89c5825

4 files changed

Lines changed: 19 additions & 29 deletions

File tree

app/app.vue

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import type { Directions } from '@nuxtjs/i18n'
33
import { useEventListener } from '@vueuse/core'
4+
import { isEditableElement } from '~/utils/input'
45
56
const route = useRoute()
67
const router = useRouter()
@@ -39,12 +40,7 @@ if (import.meta.server) {
3940
// "/" focuses search or navigates to search page
4041
// "?" highlights all keyboard shortcut elements
4142
function handleGlobalKeydown(e: KeyboardEvent) {
42-
const target = e.target as HTMLElement
43-
44-
const isEditableTarget =
45-
target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable
46-
47-
if (isEditableTarget) return
43+
if (isEditableElement(e.target)) return
4844
4945
if (e.key === '/') {
5046
e.preventDefault()

app/components/AppHeader.vue

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script setup lang="ts">
2+
import { isEditableElement } from '~/utils/input'
3+
24
withDefaults(
35
defineProps<{
46
showLogo?: boolean
@@ -62,11 +64,7 @@ function handleSearchFocus() {
6264
onKeyStroke(
6365
',',
6466
e => {
65-
// Don't trigger if user is typing in an input
66-
const target = e.target as HTMLElement
67-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
68-
return
69-
}
67+
if (isEditableElement(e.target)) return
7068
7169
e.preventDefault()
7270
navigateTo('/settings')
@@ -79,12 +77,7 @@ onKeyStroke(
7977
e => {
8078
// Allow more specific handlers to take precedence
8179
if (e.defaultPrevented) return
82-
83-
// Don't trigger if user is typing in an input
84-
const target = e.target as HTMLElement
85-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
86-
return
87-
}
80+
if (isEditableElement(e.target)) return
8881
8982
e.preventDefault()
9083
navigateTo('/compare')

app/pages/[...package].vue

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { JsrPackageInfo } from '#shared/types/jsr'
44
import { assertValidPackageName } from '#shared/utils/npm'
55
import { joinURL } from 'ufo'
66
import { areUrlsEquivalent } from '#shared/utils/url'
7+
import { isEditableElement } from '~/utils/input'
78
89
definePageMeta({
910
name: 'package',
@@ -319,10 +320,7 @@ useSeoMeta({
319320
onKeyStroke(
320321
'.',
321322
e => {
322-
const target = e.target as HTMLElement
323-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
324-
return
325-
}
323+
if (isEditableElement(e.target)) return
326324
if (pkg.value && displayVersion.value) {
327325
e.preventDefault()
328326
navigateTo({
@@ -339,10 +337,7 @@ onKeyStroke(
339337
onKeyStroke(
340338
'd',
341339
e => {
342-
const target = e.target as HTMLElement
343-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
344-
return
345-
}
340+
if (isEditableElement(e.target)) return
346341
if (docsLink.value) {
347342
e.preventDefault()
348343
navigateTo(docsLink.value)
@@ -352,10 +347,7 @@ onKeyStroke(
352347
)
353348
354349
onKeyStroke('c', e => {
355-
const target = e.target as HTMLElement
356-
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
357-
return
358-
}
350+
if (isEditableElement(e.target)) return
359351
if (pkg.value) {
360352
e.preventDefault()
361353
router.push({ path: '/compare', query: { packages: pkg.value.name } })

app/utils/input.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,12 @@ export const noCorrect = {
44
autocorrect: 'off',
55
spellcheck: 'false',
66
} as const
7+
8+
/**
9+
* Check if an event target is an editable element (input, textarea, or contenteditable).
10+
* Useful for keyboard shortcut handlers that should not trigger when the user is typing.
11+
*/
12+
export function isEditableElement(target: EventTarget | null): boolean {
13+
if (!target || !(target instanceof HTMLElement)) return false
14+
return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable
15+
}

0 commit comments

Comments
 (0)