From be21db706993c0db95ac09509dfdb023de64daff Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 24 Mar 2026 17:25:52 -0500 Subject: [PATCH] refac --- .../components/common/RichTextInput.svelte | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index af4389f4c6..2e062dad19 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -443,13 +443,32 @@ const { state, view } = editor; const { schema, tr } = state; + // Build a paragraph node from a line of text, reconstructing any + // serialized mention syntax (e.g. <@model>, <$skill|Label>) into + // proper TipTap Mention nodes via DOMParser. + const toParagraph = (line: string) => { + if (!line) return schema.nodes.paragraph.create(); + if (/<[@#$][\w.\-:/]+(?:\|[^>]*)?>/.test(line)) { + const html = line.replace( + /<([@#$])([\w.\-:/]+)(?:\|([^>]*))?>/g, + (_, ch, id, label) => { + const display = label?.length ? label : id; + return `${ch}${display}`; + } + ); + const el = document.createElement('p'); + el.innerHTML = html; + return DOMParser.fromSchema(schema).parse(el, { + topNode: schema.nodes.paragraph + }); + } + return schema.nodes.paragraph.create({}, schema.text(line)); + }; + if (text.includes('\n')) { // Multiple lines: make paragraphs const lines = text.split('\n'); - // Map each line to a paragraph node (empty lines -> empty paragraph) - const nodes = lines.map((line) => - schema.nodes.paragraph.create({}, line ? schema.text(line) : undefined) - ); + const nodes = lines.map(toParagraph); // Create a document fragment containing all parsed paragraphs const fragment = Fragment.fromArray(nodes); // Replace current selection with these paragraphs @@ -460,8 +479,7 @@ editor.commands.clearContent(); } else { // Single line: create paragraph with text - const paragraph = schema.nodes.paragraph.create({}, schema.text(text)); - tr.replaceSelectionWith(paragraph, false); + tr.replaceSelectionWith(toParagraph(text), false); view.dispatch(tr); }