Merge pull request #836 from SuanmoSuanyangTechnology/feature/ui_upgrade_zy

fix(web): editor init
This commit is contained in:
yingzhao
2026-04-09 12:33:33 +08:00
committed by GitHub
3 changed files with 21 additions and 30 deletions

View File

@@ -149,8 +149,8 @@ const Editor: FC<LexicalEditorProps> =({
<HistoryPlugin /> <HistoryPlugin />
<CommandPlugin /> <CommandPlugin />
<AutocompletePlugin options={options} /> <AutocompletePlugin options={options} />
<CharacterCountPlugin setCount={setCount} onChange={onChange} /> <CharacterCountPlugin setCount={setCount} />
<InitialValuePlugin value={value} options={options} /> <InitialValuePlugin value={value} options={options} onChange={onChange} />
<BlurPlugin /> <BlurPlugin />
</div> </div>
</LexicalComposer> </LexicalComposer>

View File

@@ -1,41 +1,22 @@
import { useEffect, useRef } from 'react'; import { useEffect } from 'react';
import { $getRoot, $isParagraphNode } from 'lexical'; import { $getRoot, $isParagraphNode } from 'lexical';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $isVariableNode } from '../nodes/VariableNode'; const CharacterCountPlugin = ({ setCount }: { setCount: (count: number) => void }) => {
const CharacterCountPlugin = ({ setCount, onChange }: { setCount: (count: number) => void; onChange?: (value: string) => void }) => {
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
const onChangeRef = useRef(onChange);
onChangeRef.current = onChange;
useEffect(() => { useEffect(() => {
return editor.registerUpdateListener(({ editorState, tags }) => { return editor.registerUpdateListener(({ editorState, tags }) => {
if (tags.has('programmatic')) return; if (tags.has('programmatic')) return;
editorState.read(() => { editorState.read(() => {
const root = $getRoot(); const root = $getRoot();
let serializedContent = '';
// Traverse all nodes and serialize properly
const paragraphs: string[] = []; const paragraphs: string[] = [];
root.getChildren().forEach(child => { root.getChildren().forEach(child => {
if ($isParagraphNode(child)) { if ($isParagraphNode(child)) {
let paragraphContent = ''; paragraphs.push(child.getChildren().map(n => n.getTextContent()).join(''));
child.getChildren().forEach(node => {
if ($isVariableNode(node)) {
paragraphContent += node.getTextContent();
} else {
paragraphContent += node.getTextContent();
}
});
paragraphs.push(paragraphContent);
} }
}); });
setCount(paragraphs.join('\n').length);
serializedContent = paragraphs.join('\n');
setCount(serializedContent.length);
onChangeRef.current?.(serializedContent);
}); });
}); });
}, [editor, setCount]); }, [editor, setCount]);

View File

@@ -6,7 +6,7 @@
*/ */
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $getRoot, $createParagraphNode, $createTextNode } from 'lexical'; import { $getRoot, $createParagraphNode, $createTextNode, $isParagraphNode } from 'lexical';
import { $createVariableNode } from '../nodes/VariableNode'; import { $createVariableNode } from '../nodes/VariableNode';
import { type Suggestion } from '../plugin/AutocompletePlugin' import { type Suggestion } from '../plugin/AutocompletePlugin'
@@ -14,24 +14,34 @@ import { type Suggestion } from '../plugin/AutocompletePlugin'
interface InitialValuePluginProps { interface InitialValuePluginProps {
value: string; value: string;
options?: Suggestion[]; options?: Suggestion[];
onChange?: (value: string) => void;
} }
const InitialValuePlugin: React.FC<InitialValuePluginProps> = ({ value, options = [] }) => { const InitialValuePlugin: React.FC<InitialValuePluginProps> = ({ value, options = [], onChange }) => {
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
const prevValueRef = useRef<string>(''); const prevValueRef = useRef<string>('');
const isUserInputRef = useRef(false); const isUserInputRef = useRef(false);
const optionsRef = useRef(options); const optionsRef = useRef(options);
optionsRef.current = options; optionsRef.current = options;
const onChangeRef = useRef(onChange);
onChangeRef.current = onChange;
useEffect(() => { useEffect(() => {
return editor.registerUpdateListener(({ editorState, tags }) => { return editor.registerUpdateListener(({ editorState, tags }) => {
if (tags.has('programmatic')) return; if (tags.has('programmatic')) return;
editorState.read(() => { editorState.read(() => {
const root = $getRoot(); const root = $getRoot();
const textContent = root.getTextContent(); const paragraphs: string[] = [];
if (textContent !== prevValueRef.current) { root.getChildren().forEach(child => {
if ($isParagraphNode(child)) {
paragraphs.push(child.getChildren().map(n => n.getTextContent()).join(''));
}
});
const text = paragraphs.join('\n');
if (text !== prevValueRef.current) {
isUserInputRef.current = true; isUserInputRef.current = true;
prevValueRef.current = textContent; prevValueRef.current = text;
onChangeRef.current?.(text);
} }
}); });
}); });