Fix lost focus on the policy editor
Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
||||||
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
||||||
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
||||||
@@ -38,6 +38,75 @@ import {
|
|||||||
|
|
||||||
import "./PolicyEditor.css";
|
import "./PolicyEditor.css";
|
||||||
|
|
||||||
|
// Custom plugin to preserve scroll position
|
||||||
|
function ScrollPlugin() {
|
||||||
|
const [editor] = useLexicalComposerContext();
|
||||||
|
const scrollRef = useRef<number>(0);
|
||||||
|
const editorRef = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return editor.registerUpdateListener(({ dirtyElements, dirtyLeaves }) => {
|
||||||
|
// Skip if there are no changes
|
||||||
|
if (dirtyElements.size === 0 && dirtyLeaves.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only run after the DOM has been updated
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!editorRef.current) {
|
||||||
|
const rootElement = editor.getRootElement();
|
||||||
|
if (rootElement) {
|
||||||
|
// Find the actual contentEditable element
|
||||||
|
const contentEditables = rootElement.getElementsByClassName(
|
||||||
|
"policy-editor-input"
|
||||||
|
);
|
||||||
|
if (contentEditables.length > 0) {
|
||||||
|
editorRef.current = contentEditables[0] as HTMLElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editorRef.current) {
|
||||||
|
// After updates, restore the scroll position
|
||||||
|
editorRef.current.scrollTop = scrollRef.current;
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editorRef.current) {
|
||||||
|
const rootElement = editor.getRootElement();
|
||||||
|
if (rootElement) {
|
||||||
|
const contentEditables = rootElement.getElementsByClassName(
|
||||||
|
"policy-editor-input"
|
||||||
|
);
|
||||||
|
if (contentEditables.length > 0) {
|
||||||
|
editorRef.current = contentEditables[0] as HTMLElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveScrollPosition = () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
scrollRef.current = editorRef.current.scrollTop;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (editorRef.current) {
|
||||||
|
editorRef.current.addEventListener("scroll", saveScrollPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
editorRef.current.removeEventListener("scroll", saveScrollPosition);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Theme for the editor
|
// Theme for the editor
|
||||||
const theme = {
|
const theme = {
|
||||||
ltr: "ltr",
|
ltr: "ltr",
|
||||||
@@ -247,6 +316,7 @@ function HtmlImportPlugin({
|
|||||||
setEditor: (editor: LexicalEditor) => void;
|
setEditor: (editor: LexicalEditor) => void;
|
||||||
}) {
|
}) {
|
||||||
const [editor] = useLexicalComposerContext();
|
const [editor] = useLexicalComposerContext();
|
||||||
|
const isInitializedRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(
|
console.log(
|
||||||
@@ -258,8 +328,9 @@ function HtmlImportPlugin({
|
|||||||
: "empty"
|
: "empty"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (editor) {
|
if (editor && !isInitializedRef.current) {
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
|
isInitializedRef.current = true;
|
||||||
|
|
||||||
editor.update(() => {
|
editor.update(() => {
|
||||||
try {
|
try {
|
||||||
@@ -307,6 +378,12 @@ export default function PolicyEditor({
|
|||||||
onChange,
|
onChange,
|
||||||
}: PolicyEditorProps) {
|
}: PolicyEditorProps) {
|
||||||
const [editor, setEditor] = useState<LexicalEditor | null>(null);
|
const [editor, setEditor] = useState<LexicalEditor | null>(null);
|
||||||
|
const initialContentRef = useRef(initialContent);
|
||||||
|
|
||||||
|
// Update reference if initialContent changes
|
||||||
|
useEffect(() => {
|
||||||
|
initialContentRef.current = initialContent;
|
||||||
|
}, [initialContent]);
|
||||||
|
|
||||||
console.log("PolicyEditor rendering with initialContent:", initialContent);
|
console.log("PolicyEditor rendering with initialContent:", initialContent);
|
||||||
|
|
||||||
@@ -370,9 +447,10 @@ export default function PolicyEditor({
|
|||||||
<MarkdownShortcutPlugin transformers={TRANSFORMERS} />
|
<MarkdownShortcutPlugin transformers={TRANSFORMERS} />
|
||||||
<OnChangePlugin onChange={handleEditorChange} />
|
<OnChangePlugin onChange={handleEditorChange} />
|
||||||
<HtmlImportPlugin
|
<HtmlImportPlugin
|
||||||
initialHtml={initialContent}
|
initialHtml={initialContentRef.current}
|
||||||
setEditor={setEditor}
|
setEditor={setEditor}
|
||||||
/>
|
/>
|
||||||
|
<ScrollPlugin />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</LexicalComposer>
|
</LexicalComposer>
|
||||||
|
|||||||
Reference in New Issue
Block a user