Skip to content

Commit 4cdc941

Browse files
fix(ui): fix focusing bugs while editing files (#4197)
1 parent 0464a57 commit 4cdc941

File tree

3 files changed

+70
-51
lines changed

3 files changed

+70
-51
lines changed

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,8 @@ function TextEditor({
764764
)
765765

766766
const textareaStuckRef = useRef(true)
767+
const renderedContentRef = useRef(renderedContent)
768+
renderedContentRef.current = renderedContent
767769

768770
useEffect(() => {
769771
if (!shouldUseCodeRenderer) return
@@ -772,14 +774,13 @@ function TextEditor({
772774

773775
const updateActiveLineNumber = () => {
774776
const pos = textarea.selectionStart
775-
const textBeforeCursor = renderedContent.substring(0, pos)
777+
const textBeforeCursor = renderedContentRef.current.substring(0, pos)
776778
const nextActiveLineNumber = textBeforeCursor.split('\n').length
777779
setActiveLineNumber((currentLineNumber) =>
778780
currentLineNumber === nextActiveLineNumber ? currentLineNumber : nextActiveLineNumber
779781
)
780782
}
781783

782-
updateActiveLineNumber()
783784
textarea.addEventListener('click', updateActiveLineNumber)
784785
textarea.addEventListener('keyup', updateActiveLineNumber)
785786
textarea.addEventListener('focus', updateActiveLineNumber)
@@ -789,60 +790,64 @@ function TextEditor({
789790
textarea.removeEventListener('keyup', updateActiveLineNumber)
790791
textarea.removeEventListener('focus', updateActiveLineNumber)
791792
}
792-
}, [renderedContent, shouldUseCodeRenderer])
793+
}, [shouldUseCodeRenderer])
794+
795+
const calculateVisualLinesRef = useRef(() => {})
796+
calculateVisualLinesRef.current = () => {
797+
const preElement = codeEditorRef.current?.querySelector('pre')
798+
if (!(preElement instanceof HTMLElement)) return
799+
800+
const lines = renderedContentRef.current.split('\n')
801+
const newVisualLineHeights: number[] = []
802+
803+
const tempContainer = document.createElement('div')
804+
tempContainer.style.cssText = `
805+
position: absolute;
806+
visibility: hidden;
807+
height: auto;
808+
width: ${preElement.clientWidth}px;
809+
font-family: ${window.getComputedStyle(preElement).fontFamily};
810+
font-size: ${window.getComputedStyle(preElement).fontSize};
811+
line-height: ${CODE_EDITOR_LINE_HEIGHT_PX}px;
812+
padding: 8px;
813+
white-space: pre-wrap;
814+
word-break: break-word;
815+
box-sizing: border-box;
816+
`
817+
document.body.appendChild(tempContainer)
818+
819+
lines.forEach((line) => {
820+
const lineDiv = document.createElement('div')
821+
lineDiv.textContent = line || ' '
822+
tempContainer.appendChild(lineDiv)
823+
const actualHeight = lineDiv.getBoundingClientRect().height
824+
const lineUnits = Math.max(1, Math.ceil(actualHeight / CODE_EDITOR_LINE_HEIGHT_PX))
825+
newVisualLineHeights.push(lineUnits)
826+
tempContainer.removeChild(lineDiv)
827+
})
828+
829+
document.body.removeChild(tempContainer)
830+
setVisualLineHeights((currentVisualLineHeights) =>
831+
areNumberArraysEqual(currentVisualLineHeights, newVisualLineHeights)
832+
? currentVisualLineHeights
833+
: newVisualLineHeights
834+
)
835+
}
793836

794837
useEffect(() => {
795838
if (!shouldUseCodeRenderer || !codeEditorRef.current) return
796839

797-
const calculateVisualLines = () => {
798-
const preElement = codeEditorRef.current?.querySelector('pre')
799-
if (!(preElement instanceof HTMLElement)) return
800-
801-
const lines = renderedContent.split('\n')
802-
const newVisualLineHeights: number[] = []
803-
804-
const tempContainer = document.createElement('div')
805-
tempContainer.style.cssText = `
806-
position: absolute;
807-
visibility: hidden;
808-
height: auto;
809-
width: ${preElement.clientWidth}px;
810-
font-family: ${window.getComputedStyle(preElement).fontFamily};
811-
font-size: ${window.getComputedStyle(preElement).fontSize};
812-
line-height: ${CODE_EDITOR_LINE_HEIGHT_PX}px;
813-
padding: 8px;
814-
white-space: pre-wrap;
815-
word-break: break-word;
816-
box-sizing: border-box;
817-
`
818-
document.body.appendChild(tempContainer)
819-
820-
lines.forEach((line) => {
821-
const lineDiv = document.createElement('div')
822-
lineDiv.textContent = line || ' '
823-
tempContainer.appendChild(lineDiv)
824-
const actualHeight = lineDiv.getBoundingClientRect().height
825-
const lineUnits = Math.max(1, Math.ceil(actualHeight / CODE_EDITOR_LINE_HEIGHT_PX))
826-
newVisualLineHeights.push(lineUnits)
827-
tempContainer.removeChild(lineDiv)
828-
})
829-
830-
document.body.removeChild(tempContainer)
831-
setVisualLineHeights((currentVisualLineHeights) =>
832-
areNumberArraysEqual(currentVisualLineHeights, newVisualLineHeights)
833-
? currentVisualLineHeights
834-
: newVisualLineHeights
835-
)
836-
}
837-
838-
const timeoutId = setTimeout(calculateVisualLines, 50)
839-
const resizeObserver = new ResizeObserver(calculateVisualLines)
840+
const resizeObserver = new ResizeObserver(() => calculateVisualLinesRef.current())
840841
resizeObserver.observe(codeEditorRef.current)
841842

842843
return () => {
843-
clearTimeout(timeoutId)
844844
resizeObserver.disconnect()
845845
}
846+
}, [shouldUseCodeRenderer])
847+
848+
useEffect(() => {
849+
if (!shouldUseCodeRenderer) return
850+
calculateVisualLinesRef.current()
846851
}, [renderedContent, shouldUseCodeRenderer])
847852

848853
const renderCodeLineNumbers = useCallback((): ReactElement[] => {
@@ -938,7 +943,7 @@ function TextEditor({
938943
if (streamingContent === undefined) {
939944
if (isLoading) return DOCUMENT_SKELETON
940945

941-
if (error) {
946+
if (error && !isInitialized) {
942947
return (
943948
<div className='flex flex-1 items-center justify-center'>
944949
<p className='text-[13px] text-[var(--text-muted)]'>Failed to load file content</p>

apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/generic-resource-content.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export function GenericResourceContent({ data }: GenericResourceContentProps) {
1313
const bottomRef = useRef<HTMLDivElement>(null)
1414

1515
useEffect(() => {
16-
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
16+
const el = bottomRef.current
17+
const container = el?.parentElement
18+
if (container) {
19+
container.scrollTop = container.scrollHeight
20+
}
1721
}, [data.entries.length])
1822

1923
if (data.entries.length === 0) {

apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,14 +430,24 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
430430

431431
useEffect(() => {
432432
if (wasSendingRef.current && !isSending) {
433-
textareaRef.current?.focus()
433+
const active = document.activeElement
434+
const isEditingElsewhere =
435+
active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement
436+
if (!isEditingElsewhere) {
437+
textareaRef.current?.focus()
438+
}
434439
}
435440
wasSendingRef.current = isSending
436441
}, [isSending, textareaRef])
437442

438443
useEffect(() => {
439444
const raf = window.requestAnimationFrame(() => {
440-
textareaRef.current?.focus()
445+
const active = document.activeElement
446+
const isEditingElsewhere =
447+
active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement
448+
if (!isEditingElsewhere) {
449+
textareaRef.current?.focus()
450+
}
441451
})
442452
return () => window.cancelAnimationFrame(raf)
443453
}, [textareaRef])

0 commit comments

Comments
 (0)