refac/fix: rich text input in ff

This commit is contained in:
Timothy Jaeryang Baek
2025-07-06 17:32:03 +04:00
parent be7166d6fc
commit e84c521177
3 changed files with 91 additions and 84 deletions
+62 -67
View File
@@ -176,35 +176,34 @@
if (!editor) return;
text = text.replaceAll('\n\n', '\n');
const { state, view } = editor;
const { schema, tr } = state;
if (text.includes('\n')) {
// Multiple lines: make paragraphs
const { schema, tr } = state;
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)
);
// Create a document fragment containing all parsed paragraphs
const fragment = Fragment.fromArray(nodes);
// Replace current selection with these paragraphs
tr.replaceSelectionWith(fragment, false /* don't select new */);
// You probably want to move the cursor after the inserted content
// tr.setSelection(Selection.near(tr.doc.resolve(tr.selection.to)));
view.dispatch(tr);
} else if (text === '') {
// Empty: delete selection or paragraph
editor.commands.clearContent();
// Empty: replace with empty paragraph using tr
const emptyParagraph = schema.nodes.paragraph.create();
tr.replaceSelectionWith(emptyParagraph, false);
view.dispatch(tr);
} else {
editor.commands.setContent(editor.state.schema.text(text));
// Single line: create paragraph with text
const paragraph = schema.nodes.paragraph.create({}, schema.text(text));
tr.replaceSelectionWith(paragraph, false);
view.dispatch(tr);
}
selectNextTemplate(editor.view.state, editor.view.dispatch);
focus();
};
export const replaceVariables = (variables) => {
@@ -253,7 +252,7 @@
export const focus = () => {
if (editor) {
editor.view.focus();
// Scroll to the top of the editor
// Scroll to the current selection
editor.view.dispatch(editor.view.state.tr.scrollIntoView());
}
};
@@ -326,11 +325,7 @@
setTimeout(() => {
const templateFound = selectNextTemplate(editor.view.state, editor.view.dispatch);
if (!templateFound) {
// If no template found, set cursor at the end
const endPos = editor.view.state.doc.content.size;
editor.view.dispatch(
editor.view.state.tr.setSelection(TextSelection.create(editor.view.state.doc, endPos))
);
editor.commands.focus('end');
}
}, 0);
}
@@ -339,7 +334,11 @@
onMount(async () => {
let content = value;
if (!json) {
if (json) {
if (!content) {
content = html ? html : null;
}
} else {
if (preserveBreaks) {
turndownService.addRule('preserveBreaks', {
filter: 'br', // Target <br> elements
@@ -370,10 +369,6 @@
// Usage example
content = await tryParse(value);
}
} else {
if (html && !content) {
content = html;
}
}
console.log('content', content);
@@ -417,40 +412,34 @@
// force re-render so `editor.isActive` works as expected
editor = editor;
html = editor.getHTML();
const htmlValue = editor.getHTML();
const jsonValue = editor.getJSON();
let mdValue = turndownService
.turndown(
htmlValue
.replace(/<p><\/p>/g, '<br/>')
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
)
.replace(/\u00a0/g, ' ');
onChange({
html: editor.getHTML(),
json: editor.getJSON(),
md: turndownService
.turndown(
editor
.getHTML()
.replace(/<p><\/p>/g, '<br/>')
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
)
.replace(/\u00a0/g, ' ')
html: htmlValue,
json: jsonValue,
md: mdValue
});
if (json) {
value = editor.getJSON();
value = jsonValue;
} else {
if (!raw) {
let newValue = turndownService
.turndown(
editor
.getHTML()
.replace(/<p><\/p>/g, '<br/>')
.replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
)
.replace(/\u00a0/g, ' ');
if (raw) {
value = htmlValue;
} else {
if (!preserveBreaks) {
newValue = newValue.replace(/<br\/>/g, '');
mdValue = mdValue.replace(/<br\/>/g, '');
}
if (value !== newValue) {
value = newValue;
if (value !== mdValue) {
value = mdValue;
// check if the node is paragraph as well
if (editor.isActive('paragraph')) {
@@ -459,8 +448,6 @@
}
}
}
} else {
value = editor.getHTML();
}
}
},
@@ -609,36 +596,44 @@
const onValueChange = () => {
if (!editor) return;
const jsonValue = editor.getJSON();
const htmlValue = editor.getHTML();
let mdValue = turndownService
.turndown(
(preserveBreaks ? htmlValue.replace(/<p><\/p>/g, '<br/>') : htmlValue).replace(
/ {2,}/g,
(m) => m.replace(/ /g, '\u00a0')
)
)
.replace(/\u00a0/g, ' ');
if (value === '') {
editor.commands.clearContent(); // Clear content if value is empty
selectTemplate();
return;
}
if (json) {
if (JSON.stringify(value) !== JSON.stringify(editor.getJSON())) {
if (JSON.stringify(value) !== JSON.stringify(jsonValue)) {
editor.commands.setContent(value);
selectTemplate();
}
} else {
if (raw) {
if (value !== editor.getHTML()) {
if (value !== htmlValue) {
editor.commands.setContent(value);
selectTemplate();
}
} else {
if (
value !==
turndownService
.turndown(
(preserveBreaks
? editor.getHTML().replace(/<p><\/p>/g, '<br/>')
: editor.getHTML()
).replace(/ {2,}/g, (m) => m.replace(/ /g, '\u00a0'))
)
.replace(/\u00a0/g, ' ')
) {
preserveBreaks
? editor.commands.setContent(value)
: editor.commands.setContent(
marked.parse(value.replaceAll(`\n<br/>`, `<br/>`), {
if (value !== mdValue) {
editor.commands.setContent(
preserveBreaks
? value
: marked.parse(value.replaceAll(`\n<br/>`, `<br/>`), {
breaks: false
})
); // Update editor content
);
selectTemplate();
}