mirror of
https://github.com/linsa-io/linsa.git
synced 2026-04-22 16:28:36 +02:00
fix(key): Allow Esc and Any other input event (#173)
* fix(key): Allow Esc and input handler * chore: set search autoFocus on shortcut component * fix: allow enter, arrow and disable list if keyboard
This commit is contained in:
@@ -131,6 +131,7 @@ export function Shortcut() {
|
|||||||
<form className="relative flex items-center">
|
<form className="relative flex items-center">
|
||||||
<LaIcon name="Search" className="text-muted-foreground absolute left-3 size-4" />
|
<LaIcon name="Search" className="text-muted-foreground absolute left-3 size-4" />
|
||||||
<Input
|
<Input
|
||||||
|
autoFocus
|
||||||
placeholder="Search shortcuts"
|
placeholder="Search shortcuts"
|
||||||
className="border-muted-foreground/50 focus-visible:border-muted-foreground h-10 pl-10 focus-visible:ring-0"
|
className="border-muted-foreground/50 focus-visible:border-muted-foreground h-10 pl-10 focus-visible:ring-0"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import { useConfirm } from "@omit/react-confirm-dialog"
|
|||||||
import { useLinkActions } from "./hooks/use-link-actions"
|
import { useLinkActions } from "./hooks/use-link-actions"
|
||||||
import { isDeleteConfirmShownAtom } from "./LinkRoute"
|
import { isDeleteConfirmShownAtom } from "./LinkRoute"
|
||||||
import { useActiveItemScroll } from "@/hooks/use-active-item-scroll"
|
import { useActiveItemScroll } from "@/hooks/use-active-item-scroll"
|
||||||
|
import { useKeyboardManager } from "@/hooks/use-keyboard-manager"
|
||||||
|
import { useKeydownListener } from "@/hooks/use-keydown-listener"
|
||||||
|
|
||||||
interface LinkListProps {
|
interface LinkListProps {
|
||||||
activeItemIndex: number | null
|
activeItemIndex: number | null
|
||||||
@@ -131,59 +133,52 @@ const LinkList: React.FC<LinkListProps> = ({ activeItemIndex, setActiveItemIndex
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
const { isKeyboardDisabled } = useKeyboardManager("XComponent")
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if (isCommandPalettePpen || !me?.root?.personalLinks || sortedLinks.length === 0 || editId !== null) return
|
|
||||||
|
|
||||||
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
useKeydownListener((e: KeyboardEvent) => {
|
||||||
e.preventDefault()
|
if (
|
||||||
setActiveItemIndex(prevIndex => {
|
isKeyboardDisabled ||
|
||||||
if (prevIndex === null) return 0
|
isCommandPalettePpen ||
|
||||||
const newIndex =
|
!me?.root?.personalLinks ||
|
||||||
e.key === "ArrowUp" ? Math.max(0, prevIndex - 1) : Math.min(sortedLinks.length - 1, prevIndex + 1)
|
sortedLinks.length === 0 ||
|
||||||
|
editId !== null
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if (e.metaKey && sort === "manual") {
|
if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
||||||
const linksArray = [...me.root.personalLinks]
|
e.preventDefault()
|
||||||
const newLinks = arrayMove(linksArray, prevIndex, newIndex)
|
setActiveItemIndex(prevIndex => {
|
||||||
|
if (prevIndex === null) return 0
|
||||||
|
const newIndex =
|
||||||
|
e.key === "ArrowUp" ? Math.max(0, prevIndex - 1) : Math.min(sortedLinks.length - 1, prevIndex + 1)
|
||||||
|
|
||||||
while (me.root.personalLinks.length > 0) {
|
if (e.metaKey && sort === "manual") {
|
||||||
me.root.personalLinks.pop()
|
const linksArray = [...me.root.personalLinks]
|
||||||
}
|
const newLinks = arrayMove(linksArray, prevIndex, newIndex)
|
||||||
|
|
||||||
newLinks.forEach(link => {
|
while (me.root.personalLinks.length > 0) {
|
||||||
if (link) {
|
me.root.personalLinks.pop()
|
||||||
me.root.personalLinks.push(link)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
updateSequences(me.root.personalLinks)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newIndex
|
newLinks.forEach(link => {
|
||||||
})
|
if (link) {
|
||||||
} else if (e.key === "Enter" && !disableEnterKey && activeItemIndex !== null) {
|
me.root.personalLinks.push(link)
|
||||||
e.preventDefault()
|
}
|
||||||
const activeLink = sortedLinks[activeItemIndex]
|
})
|
||||||
if (activeLink) {
|
|
||||||
setEditId(activeLink.id)
|
updateSequences(me.root.personalLinks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newIndex
|
||||||
|
})
|
||||||
|
} else if (e.key === "Enter" && !disableEnterKey && activeItemIndex !== null) {
|
||||||
|
e.preventDefault()
|
||||||
|
const activeLink = sortedLinks[activeItemIndex]
|
||||||
|
if (activeLink) {
|
||||||
|
setEditId(activeLink.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
window.addEventListener("keydown", handleKeyDown)
|
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown)
|
|
||||||
}, [
|
|
||||||
me?.root?.personalLinks,
|
|
||||||
sortedLinks,
|
|
||||||
editId,
|
|
||||||
sort,
|
|
||||||
updateSequences,
|
|
||||||
isCommandPalettePpen,
|
|
||||||
activeItemIndex,
|
|
||||||
setEditId,
|
|
||||||
setActiveItemIndex,
|
|
||||||
disableEnterKey
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleDragStart = useCallback(
|
const handleDragStart = useCallback(
|
||||||
(event: DragStartEvent) => {
|
(event: DragStartEvent) => {
|
||||||
|
|||||||
@@ -2,19 +2,31 @@ import { useAtom } from "jotai"
|
|||||||
import { useEffect, useCallback } from "react"
|
import { useEffect, useCallback } from "react"
|
||||||
import { keyboardDisableSourcesAtom } from "@/store/keydown-manager"
|
import { keyboardDisableSourcesAtom } from "@/store/keydown-manager"
|
||||||
|
|
||||||
|
const allowedKeys = ["Escape", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Enter"]
|
||||||
|
|
||||||
export function useKeyboardManager(sourceId: string) {
|
export function useKeyboardManager(sourceId: string) {
|
||||||
const [disableSources, setDisableSources] = useAtom(keyboardDisableSourcesAtom)
|
const [disableSources, setDisableSources] = useAtom(keyboardDisableSourcesAtom)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
if (disableSources.size > 0) {
|
if (disableSources.has(sourceId)) {
|
||||||
event.preventDefault()
|
if (allowedKeys.includes(event.key)) {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
setDisableSources(prev => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
next.delete(sourceId)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown)
|
window.addEventListener("keydown", handleKeyDown, true)
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown)
|
return () => window.removeEventListener("keydown", handleKeyDown, true)
|
||||||
}, [disableSources])
|
}, [disableSources, sourceId, setDisableSources])
|
||||||
|
|
||||||
const disableKeydown = useCallback(
|
const disableKeydown = useCallback(
|
||||||
(disable: boolean) => {
|
(disable: boolean) => {
|
||||||
@@ -32,7 +44,7 @@ export function useKeyboardManager(sourceId: string) {
|
|||||||
[setDisableSources, sourceId]
|
[setDisableSources, sourceId]
|
||||||
)
|
)
|
||||||
|
|
||||||
const isKeyboardDisabled = disableSources.size > 0
|
const isKeyboardDisabled = disableSources.has(sourceId)
|
||||||
|
|
||||||
return { disableKeydown, isKeyboardDisabled }
|
return { disableKeydown, isKeyboardDisabled }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user