Skip to content

Commit dc195d3

Browse files
authored
fix(loading): cursor positioning, render-phase defaultValue sync, remove unnecessary useMemo (#4396)
* fix(loading): fix spans and draft chat state * fix(user-input): document auto-focus RAF ordering relative to draft restore * chore(user-input): remove extraneous comments
1 parent af859cd commit dc195d3

2 files changed

Lines changed: 22 additions & 20 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useLayoutEffect, useMemo, useRef } from 'react'
3+
import { useLayoutEffect, useRef } from 'react'
44
import { cn } from '@/lib/core/utils/cn'
55
import { MessageActions } from '@/app/workspace/[workspaceId]/components'
66
import { ChatMessageAttachments } from '@/app/workspace/[workspaceId]/home/components/chat-message-attachments'
@@ -111,17 +111,14 @@ export function MothershipChat({
111111
const { staged: stagedMessages, isStaging } = useProgressiveList(messages, stagingKey)
112112
const stagedMessageCount = stagedMessages.length
113113
const stagedOffset = messages.length - stagedMessages.length
114-
const precedingUserContentByIndex = useMemo(() => {
115-
const contentByIndex: Array<string | undefined> = []
116-
let lastUserContent: string | undefined
117-
for (const [index, message] of messages.entries()) {
118-
contentByIndex[index] = lastUserContent
119-
if (message.role === 'user') {
120-
lastUserContent = message.content
121-
}
114+
const precedingUserContentByIndex: Array<string | undefined> = []
115+
let lastUserContent: string | undefined
116+
for (const [index, message] of messages.entries()) {
117+
precedingUserContentByIndex[index] = lastUserContent
118+
if (message.role === 'user') {
119+
lastUserContent = message.content
122120
}
123-
return contentByIndex
124-
}, [messages])
121+
}
125122
const initialScrollDoneRef = useRef(false)
126123
const userInputRef = useRef<UserInputHandle>(null)
127124

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,13 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
153153
const overlayRef = useRef<HTMLDivElement>(null)
154154
const plusMenuRef = useRef<PlusMenuHandle>(null)
155155

156-
const prevDefaultValueRef = useRef(defaultValue)
157-
useEffect(() => {
158-
if (defaultValue === prevDefaultValueRef.current) return
159-
prevDefaultValueRef.current = defaultValue
160-
if (defaultValue) setValue(defaultValue)
161-
}, [defaultValue])
156+
const [prevDefaultValue, setPrevDefaultValue] = useState(defaultValue)
157+
if (defaultValue && defaultValue !== prevDefaultValue) {
158+
setPrevDefaultValue(defaultValue)
159+
setValue(defaultValue)
160+
} else if (!defaultValue && prevDefaultValue) {
161+
setPrevDefaultValue(defaultValue)
162+
}
162163

163164
const files = useFileAttachments({
164165
userId: userId || session?.user?.id,
@@ -206,10 +207,15 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
206207
}))
207208
)
208209
}
210+
if (draft.text) {
211+
const textarea = textareaRef.current
212+
if (textarea) {
213+
textarea.focus()
214+
textarea.setSelectionRange(draft.text.length, draft.text.length)
215+
}
216+
}
209217
}, []) // eslint-disable-line react-hooks/exhaustive-deps -- intentional mount-only restore
210218

211-
// Skip the initial save — restore's setState calls haven't propagated yet, so
212-
// files/contexts are still empty and would transiently wipe a file-only draft.
213219
const isFirstSaveRef = useRef(true)
214220
useEffect(() => {
215221
if (isFirstSaveRef.current) {
@@ -418,7 +424,6 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
418424

419425
const newValue = `${before}${insertText}${after}`
420426
pendingCursorRef.current = newPos
421-
// Eagerly sync refs so successive drop-handler iterations see the updated position
422427
valueRef.current = newValue
423428
atInsertPosRef.current = newPos
424429
mentionRangeRef.current = null

0 commit comments

Comments
 (0)