| author | |
| committer | |
| log | f63cda22fa6e9b98de1caec057960dce28248d37 |
| tree | bbff4995b79c62645056785d4dc17c56d6af0d7c |
| parent | b60a34eba46ffb3e97d90a644280ba743870d85d |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Julius Marminge <julius0216@outlook.com>2 files changed, 50 insertions(+), 20 deletions(-)
apps/web/src/components/ChatView.tsx+32-9| ... | @@ -633,23 +633,46 @@ export default function ChatView({ threadId }: ChatViewProps) { | ... | @@ -633,23 +633,46 @@ export default function ChatView({ threadId }: ChatViewProps) { |
| 633 | pendingUserInputs.length > 0 || | 633 | pendingUserInputs.length > 0 || |
| 634 | (showPlanFollowUpPrompt && activeProposedPlan !== null); | 634 | (showPlanFollowUpPrompt && activeProposedPlan !== null); |
| 635 | const composerFooterHasWideActions = showPlanFollowUpPrompt || activePendingProgress !== null; | 635 | const composerFooterHasWideActions = showPlanFollowUpPrompt || activePendingProgress !== null; |
| 636 | const lastSyncedPendingInputRef = useRef<{ | ||
| 637 | requestId: string | null; | ||
| 638 | questionId: string | null; | ||
| 639 | } | null>(null); | ||
| 636 | useEffect(() => { | 640 | useEffect(() => { |
| 637 | if (!activePendingProgress) { | 641 | const nextCustomAnswer = activePendingProgress?.customAnswer; |
| 642 | if (typeof nextCustomAnswer !== "string") { | ||
| 643 | lastSyncedPendingInputRef.current = null; | ||
| 638 | return; | 644 | return; |
| 639 | } | 645 | } |
| 640 | promptRef.current = activePendingProgress.customAnswer; | 646 | const nextRequestId = activePendingUserInput?.requestId ?? null; |
| 641 | setComposerCursor(activePendingProgress.customAnswer.length); | 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 | setComposerTrigger( | 664 | setComposerTrigger( |
| 643 | detectComposerTrigger( | 665 | detectComposerTrigger( |
| 644 | activePendingProgress.customAnswer, | 666 | nextCustomAnswer, |
| 645 | expandCollapsedComposerCursor( | 667 | expandCollapsedComposerCursor(nextCustomAnswer, nextCustomAnswer.length), |
| 646 | activePendingProgress.customAnswer, | ||
| 647 | activePendingProgress.customAnswer.length, | ||
| 648 | ), | ||
| 649 | ), | 668 | ), |
| 650 | ); | 669 | ); |
| 651 | setComposerHighlightedItemId(null); | 670 | setComposerHighlightedItemId(null); |
| 652 | }, [activePendingProgress, activePendingUserInput?.requestId]); | 671 | }, [ |
| 672 | activePendingProgress?.customAnswer, | ||
| 673 | activePendingUserInput?.requestId, | ||
| 674 | activePendingProgress?.activeQuestion?.id, | ||
| 675 | ]); | ||
| 653 | useEffect(() => { | 676 | useEffect(() => { |
| 654 | attachmentPreviewHandoffByMessageIdRef.current = attachmentPreviewHandoffByMessageId; | 677 | attachmentPreviewHandoffByMessageIdRef.current = attachmentPreviewHandoffByMessageId; |
| 655 | }, [attachmentPreviewHandoffByMessageId]); | 678 | }, [attachmentPreviewHandoffByMessageId]); |
apps/web/src/components/ComposerPromptEditor.tsx+18-11| ... | @@ -629,6 +629,7 @@ function ComposerPromptEditorInner({ | ... | @@ -629,6 +629,7 @@ function ComposerPromptEditorInner({ |
| 629 | const [editor] = useLexicalComposerContext(); | 629 | const [editor] = useLexicalComposerContext(); |
| 630 | const onChangeRef = useRef(onChange); | 630 | const onChangeRef = useRef(onChange); |
| 631 | const snapshotRef = useRef({ value, cursor: clampCursor(value, cursor) }); | 631 | const snapshotRef = useRef({ value, cursor: clampCursor(value, cursor) }); |
| 632 | const isApplyingControlledUpdateRef = useRef(false); | ||
| 632 | 633 | ||
| 633 | useEffect(() => { | 634 | useEffect(() => { |
| 634 | onChangeRef.current = onChange; | 635 | onChangeRef.current = onChange; |
| ... | @@ -645,21 +646,26 @@ function ComposerPromptEditorInner({ | ... | @@ -645,21 +646,26 @@ function ComposerPromptEditorInner({ |
| 645 | return; | 646 | return; |
| 646 | } | 647 | } |
| 647 | 648 | ||
| 648 | if (previousSnapshot.value !== value) { | ||
| 649 | editor.update(() => { | ||
| 650 | $setComposerEditorPrompt(value); | ||
| 651 | }); | ||
| 652 | } | ||
| 653 | |||
| 654 | snapshotRef.current = { value, cursor: normalizedCursor }; | 649 | snapshotRef.current = { value, cursor: normalizedCursor }; |
| 655 | 650 | ||
| 656 | const rootElement = editor.getRootElement(); | 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 | return; | 654 | return; |
| 659 | } | 655 | } |
| 660 | 656 | ||
| 657 | isApplyingControlledUpdateRef.current = true; | ||
| 661 | editor.update(() => { | 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 | }, [cursor, editor, value]); | 670 | }, [cursor, editor, value]); |
| 665 | 671 | ||
| ... | @@ -705,9 +711,7 @@ function ComposerPromptEditorInner({ | ... | @@ -705,9 +711,7 @@ function ComposerPromptEditorInner({ |
| 705 | focus: () => { | 711 | focus: () => { |
| 706 | focusAt(snapshotRef.current.cursor); | 712 | focusAt(snapshotRef.current.cursor); |
| 707 | }, | 713 | }, |
| 708 | focusAt: (nextCursor: number) => { | 714 | focusAt, |
| 709 | focusAt(nextCursor); | ||
| 710 | }, | ||
| 711 | focusAtEnd: () => { | 715 | focusAtEnd: () => { |
| 712 | focusAt(snapshotRef.current.value.length); | 716 | focusAt(snapshotRef.current.value.length); |
| 713 | }, | 717 | }, |
| ... | @@ -728,6 +732,9 @@ function ComposerPromptEditorInner({ | ... | @@ -728,6 +732,9 @@ function ComposerPromptEditorInner({ |
| 728 | if (previousSnapshot.value === nextValue && previousSnapshot.cursor === nextCursor) { | 732 | if (previousSnapshot.value === nextValue && previousSnapshot.cursor === nextCursor) { |
| 729 | return; | 733 | return; |
| 730 | } | 734 | } |
| 735 | if (isApplyingControlledUpdateRef.current) { | ||
| 736 | return; | ||
| 737 | } | ||
| 731 | snapshotRef.current = { | 738 | snapshotRef.current = { |
| 732 | value: nextValue, | 739 | value: nextValue, |
| 733 | cursor: nextCursor, | 740 | cursor: nextCursor, |