mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-12 23:33:47 +08:00
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
This commit is contained in:
+8
-11
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useLayoutEffect, useMemo, useRef } from 'react'
|
||||
import { useLayoutEffect, useRef } from 'react'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { MessageActions } from '@/app/workspace/[workspaceId]/components'
|
||||
import { ChatMessageAttachments } from '@/app/workspace/[workspaceId]/home/components/chat-message-attachments'
|
||||
@@ -111,17 +111,14 @@ export function MothershipChat({
|
||||
const { staged: stagedMessages, isStaging } = useProgressiveList(messages, stagingKey)
|
||||
const stagedMessageCount = stagedMessages.length
|
||||
const stagedOffset = messages.length - stagedMessages.length
|
||||
const precedingUserContentByIndex = useMemo(() => {
|
||||
const contentByIndex: Array<string | undefined> = []
|
||||
let lastUserContent: string | undefined
|
||||
for (const [index, message] of messages.entries()) {
|
||||
contentByIndex[index] = lastUserContent
|
||||
if (message.role === 'user') {
|
||||
lastUserContent = message.content
|
||||
}
|
||||
const precedingUserContentByIndex: Array<string | undefined> = []
|
||||
let lastUserContent: string | undefined
|
||||
for (const [index, message] of messages.entries()) {
|
||||
precedingUserContentByIndex[index] = lastUserContent
|
||||
if (message.role === 'user') {
|
||||
lastUserContent = message.content
|
||||
}
|
||||
return contentByIndex
|
||||
}, [messages])
|
||||
}
|
||||
const initialScrollDoneRef = useRef(false)
|
||||
const userInputRef = useRef<UserInputHandle>(null)
|
||||
|
||||
|
||||
@@ -153,12 +153,13 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
|
||||
const overlayRef = useRef<HTMLDivElement>(null)
|
||||
const plusMenuRef = useRef<PlusMenuHandle>(null)
|
||||
|
||||
const prevDefaultValueRef = useRef(defaultValue)
|
||||
useEffect(() => {
|
||||
if (defaultValue === prevDefaultValueRef.current) return
|
||||
prevDefaultValueRef.current = defaultValue
|
||||
if (defaultValue) setValue(defaultValue)
|
||||
}, [defaultValue])
|
||||
const [prevDefaultValue, setPrevDefaultValue] = useState(defaultValue)
|
||||
if (defaultValue && defaultValue !== prevDefaultValue) {
|
||||
setPrevDefaultValue(defaultValue)
|
||||
setValue(defaultValue)
|
||||
} else if (!defaultValue && prevDefaultValue) {
|
||||
setPrevDefaultValue(defaultValue)
|
||||
}
|
||||
|
||||
const files = useFileAttachments({
|
||||
userId: userId || session?.user?.id,
|
||||
@@ -206,10 +207,15 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
|
||||
}))
|
||||
)
|
||||
}
|
||||
if (draft.text) {
|
||||
const textarea = textareaRef.current
|
||||
if (textarea) {
|
||||
textarea.focus()
|
||||
textarea.setSelectionRange(draft.text.length, draft.text.length)
|
||||
}
|
||||
}
|
||||
}, []) // eslint-disable-line react-hooks/exhaustive-deps -- intentional mount-only restore
|
||||
|
||||
// Skip the initial save — restore's setState calls haven't propagated yet, so
|
||||
// files/contexts are still empty and would transiently wipe a file-only draft.
|
||||
const isFirstSaveRef = useRef(true)
|
||||
useEffect(() => {
|
||||
if (isFirstSaveRef.current) {
|
||||
@@ -418,7 +424,6 @@ export const UserInput = forwardRef<UserInputHandle, UserInputProps>(function Us
|
||||
|
||||
const newValue = `${before}${insertText}${after}`
|
||||
pendingCursorRef.current = newPos
|
||||
// Eagerly sync refs so successive drop-handler iterations see the updated position
|
||||
valueRef.current = newValue
|
||||
atInsertPosRef.current = newPos
|
||||
mentionRangeRef.current = null
|
||||
|
||||
Reference in New Issue
Block a user