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/*
|
frontend/.vercel_build_output/*
|
||||||
output/*
|
output/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.tools/bin/*
|
.tools/bin/*
|
||||||
|
|
||||||
# Embedded external tool/skill repos (checked out locally, not vendored)
|
|
||||||
.ai-context/ai-context/
|
|
||||||
.ai-context/zero-skills/
|
|
||||||
.tools/mcp-zero/
|
|
||||||
Submodule
+1
Submodule .tools/mcp-zero added at 6e87a88044
@@ -499,6 +499,18 @@ function ensureCaretAnchorAfter(node: Node) {
|
|||||||
return { node: anchor, offset: caretAnchor.length };
|
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) {
|
function placeCaretAfter(node: Node) {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
const caret = isPromptChip(node) ? ensureCaretAnchorAfter(node) : null;
|
const caret = isPromptChip(node) ? ensureCaretAnchorAfter(node) : null;
|
||||||
@@ -642,6 +654,7 @@ export const PromptComposer = forwardRef<
|
|||||||
|
|
||||||
const focus = options.focus ?? true;
|
const focus = options.focus ?? true;
|
||||||
const pending = options.pending ?? false;
|
const pending = options.pending ?? false;
|
||||||
|
removeEmptyEditorFillers(editor);
|
||||||
if (options.replacePending) {
|
if (options.replacePending) {
|
||||||
pendingReferenceChips(editor).forEach((chip) => {
|
pendingReferenceChips(editor).forEach((chip) => {
|
||||||
if (chip.dataset.referenceId === reference.id) return;
|
if (chip.dataset.referenceId === reference.id) return;
|
||||||
@@ -655,6 +668,7 @@ export const PromptComposer = forwardRef<
|
|||||||
const nextPending = existingPending ? pending : false;
|
const nextPending = existingPending ? pending : false;
|
||||||
referencesRef.current.set(reference.id, { ...reference, pending: nextPending });
|
referencesRef.current.set(reference.id, { ...reference, pending: nextPending });
|
||||||
setReferenceChipPending(existingChip, nextPending);
|
setReferenceChipPending(existingChip, nextPending);
|
||||||
|
ensureCaretAnchorAfter(existingChip);
|
||||||
if (focus) {
|
if (focus) {
|
||||||
editor.focus();
|
editor.focus();
|
||||||
placeCaretAfter(existingChip);
|
placeCaretAfter(existingChip);
|
||||||
@@ -674,10 +688,11 @@ export const PromptComposer = forwardRef<
|
|||||||
range.collapse(false);
|
range.collapse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focus) editor.focus();
|
|
||||||
range.deleteContents();
|
range.deleteContents();
|
||||||
range.insertNode(chip);
|
range.insertNode(chip);
|
||||||
|
ensureCaretAnchorAfter(chip);
|
||||||
if (focus) {
|
if (focus) {
|
||||||
|
editor.focus();
|
||||||
placeCaretAfter(chip);
|
placeCaretAfter(chip);
|
||||||
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
||||||
}
|
}
|
||||||
@@ -741,6 +756,7 @@ export const PromptComposer = forwardRef<
|
|||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
if (!editor) return;
|
if (!editor) return;
|
||||||
|
|
||||||
|
removeEmptyEditorFillers(editor);
|
||||||
annotationsRef.current.set(annotation.id, annotation);
|
annotationsRef.current.set(annotation.id, annotation);
|
||||||
const chip = createAnnotationChip(annotation);
|
const chip = createAnnotationChip(annotation);
|
||||||
const storedRange = savedRangeRef.current;
|
const storedRange = savedRangeRef.current;
|
||||||
@@ -750,9 +766,10 @@ export const PromptComposer = forwardRef<
|
|||||||
range.collapse(false);
|
range.collapse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.focus();
|
|
||||||
range.deleteContents();
|
range.deleteContents();
|
||||||
range.insertNode(chip);
|
range.insertNode(chip);
|
||||||
|
ensureCaretAnchorAfter(chip);
|
||||||
|
editor.focus();
|
||||||
placeCaretAfter(chip);
|
placeCaretAfter(chip);
|
||||||
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
savedRangeRef.current = window.getSelection()?.rangeCount ? window.getSelection()?.getRangeAt(0).cloneRange() ?? null : null;
|
||||||
emitChangeFromDom(false);
|
emitChangeFromDom(false);
|
||||||
@@ -842,6 +859,10 @@ export const PromptComposer = forwardRef<
|
|||||||
if (!editor || !selection || selection.rangeCount === 0) return;
|
if (!editor || !selection || selection.rangeCount === 0) return;
|
||||||
const range = selection.getRangeAt(0);
|
const range = selection.getRangeAt(0);
|
||||||
if (!rangeBelongsToEditor(range, editor)) return;
|
if (!rangeBelongsToEditor(range, editor)) return;
|
||||||
|
if (removeEmptyEditorFillers(editor)) {
|
||||||
|
range.selectNodeContents(editor);
|
||||||
|
range.collapse(false);
|
||||||
|
}
|
||||||
|
|
||||||
range.deleteContents();
|
range.deleteContents();
|
||||||
if (hasPromptImageReferences(pastedText)) {
|
if (hasPromptImageReferences(pastedText)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user