fix: cancel inline input refocus frames (#3488)

This commit is contained in:
Neil 2026-05-29 22:54:36 -07:00 committed by GitHub
parent e6b04820ea
commit e7be9c50f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 21 additions and 3 deletions

View File

@ -97,10 +97,27 @@ export function InlineInputRow({
// of auto-submitting, which would dismiss the empty input.
const focusSettled = useRef(false)
const settleTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
const refocusFrame = useRef<number | null>(null)
const cancelRefocusFrame = useCallback((): void => {
if (refocusFrame.current !== null) {
cancelAnimationFrame(refocusFrame.current)
refocusFrame.current = null
}
}, [])
const scheduleInputRefocus = useCallback((): void => {
cancelRefocusFrame()
refocusFrame.current = requestAnimationFrame(() => {
refocusFrame.current = null
inputRef.current?.focus()
})
}, [cancelRefocusFrame])
useEffect(() => {
submitted.current = false
focusSettled.current = false
cancelRefocusFrame()
// Schedule focus after any pending focus-restore from menu close
const raf = requestAnimationFrame(() => {
@ -126,6 +143,7 @@ export function InlineInputRow({
})
return () => {
cancelAnimationFrame(raf)
cancelRefocusFrame()
if (blurTimeout.current) {
clearTimeout(blurTimeout.current)
}
@ -133,7 +151,7 @@ export function InlineInputRow({
clearTimeout(settleTimer.current)
}
}
}, [inlineInput])
}, [cancelRefocusFrame, inlineInput])
const clearBlurTimeout = useCallback(() => {
if (blurTimeout.current) {
@ -190,14 +208,14 @@ export function InlineInputRow({
(e.relatedTarget.closest('[data-slot="context-menu-trigger"]') ||
e.relatedTarget.closest('[data-slot="dropdown-menu-trigger"]'))
) {
requestAnimationFrame(() => inputRef.current?.focus())
scheduleInputRefocus()
return
}
// During the grace period after mount, menu close focus management
// may shift focus away (often relatedTarget is null). Re-focus
// instead of dismissing the still-empty input.
if (!focusSettled.current) {
requestAnimationFrame(() => inputRef.current?.focus())
scheduleInputRefocus()
return
}
const value = e.currentTarget.value