️(frontend) close side panel with Escape key

useEscapeToClose: close panel on Escape, restore focus, let chat input bubble
This commit is contained in:
Cyril
2026-07-13 13:59:36 +02:00
committed by aleb_the_flash
parent 2c5dd151f1
commit 4fa044fa3e
4 changed files with 34 additions and 1 deletions
+4
View File
@@ -8,6 +8,10 @@ and this project adheres to
## [Unreleased] ## [Unreleased]
### Changed
- ♿️(frontend) close side panel with Escape key #1507
### Added ### Added
- ✨(agent) support Voxtral realtime as inference engine - ✨(agent) support Voxtral realtime as inference engine
@@ -51,7 +51,7 @@ export const ChatTextArea = () => {
const isDisabled = !textAreaValue.trim() || isSending const isDisabled = !textAreaValue.trim() || isSending
const onKeyDown = async (e: React.KeyboardEvent<HTMLTextAreaElement>) => { const onKeyDown = async (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
e.stopPropagation() if (e.key !== 'Escape') e.stopPropagation()
if (e.key !== 'Enter' || (e.key === 'Enter' && e.shiftKey) || isDisabled) if (e.key !== 'Enter' || (e.key === 'Enter' && e.shiftKey) || isDisabled)
return return
e.preventDefault() e.preventDefault()
@@ -16,6 +16,7 @@ import { Info } from './Info'
import { HStack } from '@/styled-system/jsx' import { HStack } from '@/styled-system/jsx'
import { useReactionsToolbar } from '@/features/reactions/hooks/useReactionsToolbar' import { useReactionsToolbar } from '@/features/reactions/hooks/useReactionsToolbar'
import { useRestoreFocus } from '@/hooks/useRestoreFocus' import { useRestoreFocus } from '@/hooks/useRestoreFocus'
import { useEscapeToClose } from '@/hooks/useEscapeToClose'
type StyledSidePanelProps = { type StyledSidePanelProps = {
title: string title: string
@@ -194,6 +195,8 @@ export const SidePanel = () => {
activeKey: activePanelId, activeKey: activePanelId,
}) })
useEscapeToClose(isSidePanelOpen, asideRef, closeSidePanel)
return ( return (
<StyledSidePanel <StyledSidePanel
ref={asideRef} ref={asideRef}
@@ -0,0 +1,26 @@
import { useEffect, useRef, type RefObject } from 'react'
export const useEscapeToClose = (
isActive: boolean,
containerRef: RefObject<HTMLElement | null>,
onClose: () => void
) => {
const onCloseRef = useRef(onClose)
useEffect(() => {
onCloseRef.current = onClose
})
useEffect(() => {
if (!isActive) return
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Escape') return
if (!containerRef.current?.contains(document.activeElement)) return
e.stopPropagation()
onCloseRef.current()
}
document.addEventListener('keydown', handleKeyDown)
return () => document.removeEventListener('keydown', handleKeyDown)
}, [isActive, containerRef])
}