fix: prevent scroll jump when editing large messages (#21402)

Save and restore scroll positions around textarea auto-resize to avoid
layout shifts. Use preventScroll on focus.
This commit is contained in:
Algorithm5838
2026-02-16 01:33:51 -06:00
committed by GitHub
parent ca0983f76b
commit 15b5f97f89
2 changed files with 24 additions and 2 deletions
@@ -365,8 +365,13 @@
await tick(); await tick();
const messagesContainer = document.getElementById('messages-container');
const savedScrollTop = messagesContainer?.scrollTop;
editTextAreaElement.style.height = ''; editTextAreaElement.style.height = '';
editTextAreaElement.style.height = `${editTextAreaElement.scrollHeight}px`; editTextAreaElement.style.height = `${editTextAreaElement.scrollHeight}px`;
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
}; };
const editMessageConfirmHandler = async () => { const editMessageConfirmHandler = async () => {
@@ -697,8 +702,13 @@
class=" bg-transparent outline-hidden w-full resize-none" class=" bg-transparent outline-hidden w-full resize-none"
bind:value={editedContent} bind:value={editedContent}
on:input={(e) => { on:input={(e) => {
const messagesContainer = document.getElementById('messages-container');
const savedScrollTop = messagesContainer?.scrollTop;
e.target.style.height = ''; e.target.style.height = '';
e.target.style.height = `${e.target.scrollHeight}px`; e.target.style.height = `${e.target.scrollHeight}px`;
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
}} }}
on:keydown={(e) => { on:keydown={(e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
@@ -50,6 +50,7 @@
let editedFiles = []; let editedFiles = [];
let messageEditTextAreaElement: HTMLTextAreaElement; let messageEditTextAreaElement: HTMLTextAreaElement;
let editScrollContainer: HTMLDivElement;
let message = JSON.parse(JSON.stringify(history.messages[messageId])); let message = JSON.parse(JSON.stringify(history.messages[messageId]));
$: if (history.messages) { $: if (history.messages) {
@@ -73,10 +74,14 @@
await tick(); await tick();
if (messageEditTextAreaElement) { if (messageEditTextAreaElement) {
const messagesContainer = document.getElementById('messages-container');
const savedScrollTop = messagesContainer?.scrollTop;
messageEditTextAreaElement.style.height = ''; messageEditTextAreaElement.style.height = '';
messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`; messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`;
messageEditTextAreaElement?.focus(); if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
messageEditTextAreaElement?.focus({ preventScroll: true });
} }
}; };
@@ -283,15 +288,22 @@
</div> </div>
{/if} {/if}
<div class="max-h-96 overflow-auto"> <div class="max-h-96 overflow-auto" bind:this={editScrollContainer}>
<textarea <textarea
id="message-edit-{message.id}" id="message-edit-{message.id}"
bind:this={messageEditTextAreaElement} bind:this={messageEditTextAreaElement}
class=" bg-transparent outline-hidden w-full resize-none" class=" bg-transparent outline-hidden w-full resize-none"
bind:value={editedContent} bind:value={editedContent}
on:input={(e) => { on:input={(e) => {
const messagesContainer = document.getElementById('messages-container');
const savedScrollTop = messagesContainer?.scrollTop;
const savedInnerScroll = editScrollContainer?.scrollTop;
e.target.style.height = ''; e.target.style.height = '';
e.target.style.height = `${e.target.scrollHeight}px`; e.target.style.height = `${e.target.scrollHeight}px`;
if (messagesContainer) messagesContainer.scrollTop = savedScrollTop;
if (editScrollContainer) editScrollContainer.scrollTop = savedInnerScroll;
}} }}
on:keydown={(e) => { on:keydown={(e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {