fix(PromptComposer): clear empty editor fillers before chip insertion
Insert a helper that strips filler-only editor content (stray <br> and caret-anchor text nodes) before inserting reference/annotation chips and on paste, so chips no longer land after an empty line. Also anchor the caret after each inserted/updated chip and reorder focus/insert so the caret reliably follows the new chip.
This commit is contained in:
Submodule
+1
Submodule .ai-context/ai-context added at bc525eedc9
Submodule
+1
Submodule .ai-context/zero-skills added at 943a13c5d8
+1
-6
@@ -8,9 +8,4 @@ frontend/.vercel/*
|
||||
frontend/.vercel_build_output/*
|
||||
output/*
|
||||
.DS_Store
|
||||
.tools/bin/*
|
||||
|
||||
# Embedded external tool/skill repos (checked out locally, not vendored)
|
||||
.ai-context/ai-context/
|
||||
.ai-context/zero-skills/
|
||||
.tools/mcp-zero/
|
||||
.tools/bin/*
|
||||
Submodule
+1
Submodule .tools/mcp-zero added at 6e87a88044
@@ -499,6 +499,18 @@ function ensureCaretAnchorAfter(node: Node) {
|
||||
return { node: anchor, offset: caretAnchor.length };
|
||||
}
|
||||
|
||||
function removeEmptyEditorFillers(editor: HTMLElement) {
|
||||
const childNodes = Array.from(editor.childNodes);
|
||||
if (childNodes.length === 0) return false;
|
||||
const onlyFillers = childNodes.every((node) => {
|
||||
if (node instanceof HTMLBRElement) return true;
|
||||
return node.nodeType === Node.TEXT_NODE && stripCaretAnchors(node.textContent ?? "").length === 0;
|
||||
});
|
||||
if (!onlyFillers) return false;
|
||||
editor.replaceChildren();
|
||||
return true;
|
||||
}
|
||||
|
||||
function placeCaretAfter(node: Node) {
|
||||
const range = document.createRange();
|
||||
const caret = isPromptChip(node) ? ensureCaretAnchorAfter(node) : null;
|
||||
@@ -642,6 +654,7 @@ export const PromptComposer = forwardRef<
|
||||
|
||||
const focus = options.focus ?? true;
|
||||
const pending = options.pending ?? false;
|
||||
removeEmptyEditorFillers(editor);
|
||||
if (options.replacePending) {
|
||||
pendingReferenceChips(editor).forEach((chip) => {
|
||||
if (chip.dataset.referenceId === reference.id) return;
|
||||
@@ -655,6 +668,7 @@ export const PromptComposer = forwardRef<
|
||||
const nextPending = existingPending ? pending : false;
|
||||
referencesRef.current.set(reference.id, { ...reference, pending: nextPending });
|
||||
setReferenceChipPending(existingChip, nextPending);
|
||||
ensureCaretAnchorAfter(existingChip);
|
||||
if (focus) {
|
||||
editor.focus();
|
||||
placeCaretAfter(existingChip);
|
||||
@@ -674,10 +688,11 @@ export const PromptComposer = forwardRef<
|
||||
range.collapse(false);
|
||||
}
|
||||
|
||||
if (focus) editor.focus();
|
||||
range.deleteContents();
|
||||
range.insertNode(chip);
|
||||
ensureCaretAnchorAfter(chip);
|
||||
if (focus) {
|
||||
editor.focus();
|
||||
placeCaretAfter(chip);
|
||||
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
||||
}
|
||||
@@ -741,6 +756,7 @@ export const PromptComposer = forwardRef<
|
||||
const editor = editorRef.current;
|
||||
if (!editor) return;
|
||||
|
||||
removeEmptyEditorFillers(editor);
|
||||
annotationsRef.current.set(annotation.id, annotation);
|
||||
const chip = createAnnotationChip(annotation);
|
||||
const storedRange = savedRangeRef.current;
|
||||
@@ -750,9 +766,10 @@ export const PromptComposer = forwardRef<
|
||||
range.collapse(false);
|
||||
}
|
||||
|
||||
editor.focus();
|
||||
range.deleteContents();
|
||||
range.insertNode(chip);
|
||||
ensureCaretAnchorAfter(chip);
|
||||
editor.focus();
|
||||
placeCaretAfter(chip);
|
||||
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
||||
emitChangeFromDom(false);
|
||||
@@ -842,6 +859,10 @@ export const PromptComposer = forwardRef<
|
||||
if (!editor || !selection || selection.rangeCount === 0) return;
|
||||
const range = selection.getRangeAt(0);
|
||||
if (!rangeBelongsToEditor(range, editor)) return;
|
||||
if (removeEmptyEditorFillers(editor)) {
|
||||
range.selectNodeContents(editor);
|
||||
range.collapse(false);
|
||||
}
|
||||
|
||||
range.deleteContents();
|
||||
if (hasPromptImageReferences(pastedText)) {
|
||||
|
||||
Reference in New Issue
Block a user