mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
Focus editor header rename input from ref (#3328)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import type { RefCallback } from 'react'
|
||||
import type { OpenFile } from '@/store/slices/editor'
|
||||
import { useWorktreeById } from '@/store/selectors'
|
||||
import { basename } from '@/lib/path'
|
||||
@@ -9,7 +10,7 @@ type EditorHeaderFileRenameState = {
|
||||
canRename: boolean
|
||||
currentFileName: string
|
||||
isRenaming: boolean
|
||||
renameInputRef: React.RefObject<HTMLInputElement | null>
|
||||
renameInputRef: RefCallback<HTMLInputElement>
|
||||
openRenameInput: () => void
|
||||
commitRename: () => void
|
||||
cancelRename: () => void
|
||||
@@ -18,8 +19,9 @@ type EditorHeaderFileRenameState = {
|
||||
export function useEditorHeaderFileRename(activeFile: OpenFile): EditorHeaderFileRenameState {
|
||||
const worktree = useWorktreeById(activeFile.worktreeId)
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
const renameInputRef = useRef<HTMLInputElement>(null)
|
||||
const renameInputElementRef = useRef<HTMLInputElement | null>(null)
|
||||
const renameCancelledRef = useRef(false)
|
||||
const renameFocusFrameRef = useRef<number | null>(null)
|
||||
const currentFileName = basename(activeFile.filePath)
|
||||
const canRename =
|
||||
activeFile.mode === 'edit' && !activeFile.diffSource && !activeFile.conflict && !isRenaming
|
||||
@@ -38,7 +40,7 @@ export function useEditorHeaderFileRename(activeFile: OpenFile): EditorHeaderFil
|
||||
setIsRenaming(false)
|
||||
return
|
||||
}
|
||||
const input = renameInputRef.current
|
||||
const input = renameInputElementRef.current
|
||||
if (!input) {
|
||||
setIsRenaming(false)
|
||||
return
|
||||
@@ -62,25 +64,40 @@ export function useEditorHeaderFileRename(activeFile: OpenFile): EditorHeaderFil
|
||||
setIsRenaming(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRenaming) {
|
||||
const clearRenameFocusFrame = useCallback((): void => {
|
||||
if (renameFocusFrameRef.current === null) {
|
||||
return
|
||||
}
|
||||
const raf = requestAnimationFrame(() => {
|
||||
const el = renameInputRef.current
|
||||
if (!el) {
|
||||
cancelAnimationFrame(renameFocusFrameRef.current)
|
||||
renameFocusFrameRef.current = null
|
||||
}, [])
|
||||
|
||||
const renameInputRef = useCallback<RefCallback<HTMLInputElement>>(
|
||||
(el) => {
|
||||
renameInputElementRef.current = el
|
||||
clearRenameFocusFrame()
|
||||
if (!el || !isRenaming) {
|
||||
return
|
||||
}
|
||||
el.focus()
|
||||
const dotIndex = currentFileName.lastIndexOf('.')
|
||||
if (dotIndex > 0) {
|
||||
el.setSelectionRange(0, dotIndex)
|
||||
} else {
|
||||
el.select()
|
||||
}
|
||||
})
|
||||
return () => cancelAnimationFrame(raf)
|
||||
}, [currentFileName, isRenaming])
|
||||
|
||||
// Why: focus belongs to the rename input mount; the frame preserves the
|
||||
// previous timing so header layout settles before selecting text.
|
||||
renameFocusFrameRef.current = requestAnimationFrame(() => {
|
||||
renameFocusFrameRef.current = null
|
||||
if (renameInputElementRef.current !== el) {
|
||||
return
|
||||
}
|
||||
el.focus()
|
||||
const dotIndex = currentFileName.lastIndexOf('.')
|
||||
if (dotIndex > 0) {
|
||||
el.setSelectionRange(0, dotIndex)
|
||||
} else {
|
||||
el.select()
|
||||
}
|
||||
})
|
||||
},
|
||||
[clearRenameFocusFrame, currentFileName, isRenaming]
|
||||
)
|
||||
|
||||
return {
|
||||
canRename,
|
||||
|
||||
Reference in New Issue
Block a user