fix(chat): fix ghost text overlay positioning for caret sync

Move ghost text into a separate absolutely-positioned overlay div that
mirrors the textarea's scroll position, replacing the previous inline
span approach. Add a hidden span to offset the visible ghost text to
the correct position after the current input, ensuring the ghost text
stays aligned with the caret regardless of scroll state.
This commit is contained in:
Igor Šćekić
2026-02-26 19:32:51 +01:00
parent 67760f533f
commit d13a2a7cf6
2 changed files with 31 additions and 3 deletions
@@ -39,6 +39,7 @@ export const PromptInput: Component = () => {
let textareaRef: HTMLTextAreaElement | undefined
let highlightRef: HTMLDivElement | undefined
let ghostRef: HTMLDivElement | undefined
let dropdownRef: HTMLDivElement | undefined
let debounceTimer: ReturnType<typeof setTimeout> | undefined
let requestCounter = 0
@@ -158,6 +159,9 @@ export const PromptInput: Component = () => {
if (highlightRef && textareaRef) {
highlightRef.scrollTop = textareaRef.scrollTop
}
if (ghostRef && textareaRef) {
ghostRef.scrollTop = textareaRef.scrollTop
}
}
const adjustHeight = () => {
@@ -316,10 +320,13 @@ export const PromptInput: Component = () => {
</Show>
)}
</Index>
<Show when={ghostText()}>
<span class="prompt-input-ghost-text">{ghostText()}</span>
</Show>
</div>
<Show when={ghostText()}>
<div class="prompt-input-ghost-overlay" ref={ghostRef} aria-hidden="true">
<span class="prompt-input-ghost-hidden">{text()}</span>
<span class="prompt-input-ghost-text">{ghostText()}</span>
</div>
</Show>
<textarea
ref={textareaRef}
class="prompt-input"
@@ -339,6 +339,27 @@
color: var(--vscode-textLink-foreground, #3794ff);
}
.prompt-input-ghost-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
padding: 8px;
font-family: var(--vscode-font-family);
font-size: 13px;
line-height: 1.4;
white-space: pre-wrap;
word-wrap: break-word;
overflow: hidden;
z-index: 0;
}
.prompt-input-ghost-hidden {
visibility: hidden;
}
.prompt-input-ghost-text {
color: var(--vscode-editorGhostText-foreground, rgba(255, 255, 255, 0.35));
}