Unified · Split
| @@ -633,23 +633,46 @@ export default function ChatView({ threadId }: ChatViewProps) { · 632 unmodified lines | ||
| 633 | 633 | pendingUserInputs.length > 0 || |
| 634 | 634 | (showPlanFollowUpPrompt && activeProposedPlan !== null); |
| 635 | 635 | const composerFooterHasWideActions = showPlanFollowUpPrompt || activePendingProgress !== null; |
| 636 | + const lastSyncedPendingInputRef = useRef<{ | |
| 637 | + requestId: string | null; | |
| 638 | + questionId: string | null; | |
| 639 | + } | null>(null); | |
| 636 | 640 | useEffect(() => { |
| 637 | − if (!activePendingProgress) { | |
| 641 | + const nextCustomAnswer = activePendingProgress?.customAnswer; | |
| 642 | + if (typeof nextCustomAnswer !== "string") { | |
| 643 | + lastSyncedPendingInputRef.current = null; | |
| 638 | 644 | return; |
| 639 | 645 | } |
| 640 | − promptRef.current = activePendingProgress.customAnswer; | |
| 641 | − setComposerCursor(activePendingProgress.customAnswer.length); | |
| 646 | + const nextRequestId = activePendingUserInput?.requestId ?? null; | |
| 647 | + const nextQuestionId = activePendingProgress?.activeQuestion?.id ?? null; | |
| 648 | + const questionChanged = | |
| 649 | + lastSyncedPendingInputRef.current?.requestId !== nextRequestId || | |
| 650 | + lastSyncedPendingInputRef.current?.questionId !== nextQuestionId; | |
| 651 | + const textChangedExternally = promptRef.current !== nextCustomAnswer; | |
| 652 | + | |
| 653 | + lastSyncedPendingInputRef.current = { | |
| 654 | + requestId: nextRequestId, | |
| 655 | + questionId: nextQuestionId, | |
| 656 | + }; | |
| 657 | + | |
| 658 | + if (!questionChanged && !textChangedExternally) { | |
| 659 | + return; | |
| 660 | + } | |
| 661 | + | |
| 662 | + promptRef.current = nextCustomAnswer; | |
| 663 | + setComposerCursor(nextCustomAnswer.length); | |
| 642 | 664 | setComposerTrigger( |
| 643 | 665 | detectComposerTrigger( |
| 644 | − activePendingProgress.customAnswer, | |
| 645 | − expandCollapsedComposerCursor( | |
| 646 | − activePendingProgress.customAnswer, | |
| 647 | − activePendingProgress.customAnswer.length, | |
| 648 | − ), | |
| 666 | + nextCustomAnswer, | |
| 667 | + expandCollapsedComposerCursor(nextCustomAnswer, nextCustomAnswer.length), | |
| 649 | 668 | ), |
| 650 | 669 | ); |
| 651 | 670 | setComposerHighlightedItemId(null); |
| 652 | − }, [activePendingProgress, activePendingUserInput?.requestId]); | |
| 671 | + }, [ | |
| 672 | + activePendingProgress?.customAnswer, | |
| 673 | + activePendingUserInput?.requestId, | |
| 674 | + activePendingProgress?.activeQuestion?.id, | |
| 675 | + ]); | |
| 653 | 676 | useEffect(() => { |
| 654 | 677 | attachmentPreviewHandoffByMessageIdRef.current = attachmentPreviewHandoffByMessageId; |
| 655 | 678 | }, [attachmentPreviewHandoffByMessageId]); |
| @@ -629,6 +629,7 @@ function ComposerPromptEditorInner({ · 628 unmodified lines | ||
| 629 | 629 | const [editor] = useLexicalComposerContext(); |
| 630 | 630 | const onChangeRef = useRef(onChange); |
| 631 | 631 | const snapshotRef = useRef({ value, cursor: clampCursor(value, cursor) }); |
| 632 | + const isApplyingControlledUpdateRef = useRef(false); | |
| 632 | 633 | |
| 633 | 634 | useEffect(() => { |
| 634 | 635 | onChangeRef.current = onChange; |
| @@ -645,21 +646,26 @@ function ComposerPromptEditorInner({ · 10 unmodified lines | ||
| 645 | 646 | return; |
| 646 | 647 | } |
| 647 | 648 | |
| 648 | − if (previousSnapshot.value !== value) { | |
| 649 | − editor.update(() => { | |
| 650 | − $setComposerEditorPrompt(value); | |
| 651 | − }); | |
| 652 | − } | |
| 653 | − | |
| 654 | 649 | snapshotRef.current = { value, cursor: normalizedCursor }; |
| 655 | 650 | |
| 656 | 651 | const rootElement = editor.getRootElement(); |
| 657 | − if (!rootElement || document.activeElement !== rootElement) { | |
| 652 | + const isFocused = Boolean(rootElement && document.activeElement === rootElement); | |
| 653 | + if (previousSnapshot.value === value && !isFocused) { | |
| 658 | 654 | return; |
| 659 | 655 | } |
| 660 | 656 | |
| 657 | + isApplyingControlledUpdateRef.current = true; | |
| 661 | 658 | editor.update(() => { |
| 662 | − $setSelectionAtComposerOffset(normalizedCursor); | |
| 659 | + const valueChanged = previousSnapshot.value !== value; | |
| 660 | + if (previousSnapshot.value !== value) { | |
| 661 | + $setComposerEditorPrompt(value); | |
| 662 | + } | |
| 663 | + if (valueChanged || isFocused) { | |
| 664 | + $setSelectionAtComposerOffset(normalizedCursor); | |
| 665 | + } | |
| 666 | + }); | |
| 667 | + queueMicrotask(() => { | |
| 668 | + isApplyingControlledUpdateRef.current = false; | |
| 663 | 669 | }); |
| 664 | 670 | }, [cursor, editor, value]); |
| 665 | 671 | |
| @@ -705,9 +711,7 @@ function ComposerPromptEditorInner({ · 39 unmodified lines | ||
| 705 | 711 | focus: () => { |
| 706 | 712 | focusAt(snapshotRef.current.cursor); |
| 707 | 713 | }, |
| 708 | − focusAt: (nextCursor: number) => { | |
| 709 | − focusAt(nextCursor); | |
| 710 | − }, | |
| 714 | + focusAt, | |
| 711 | 715 | focusAtEnd: () => { |
| 712 | 716 | focusAt(snapshotRef.current.value.length); |
| 713 | 717 | }, |
| @@ -728,6 +732,9 @@ function ComposerPromptEditorInner({ · 14 unmodified lines | ||
| 728 | 732 | if (previousSnapshot.value === nextValue && previousSnapshot.cursor === nextCursor) { |
| 729 | 733 | return; |
| 730 | 734 | } |
| 735 | + if (isApplyingControlledUpdateRef.current) { | |
| 736 | + return; | |
| 737 | + } | |
| 731 | 738 | snapshotRef.current = { |
| 732 | 739 | value: nextValue, |
| 733 | 740 | cursor: nextCursor, |