2025-08-23 19:54:02 +03:00

76 lines
2.5 KiB
TypeScript

import { CKTextEditor, type AttributeEditor, type EditorConfig, type ModelPosition } from "@triliumnext/ckeditor5";
import { useEffect, useRef } from "preact/compat";
interface CKEditorOpts {
currentValue?: string;
className: string;
tabIndex?: number;
config: EditorConfig;
editor: typeof AttributeEditor;
disableNewlines?: boolean;
disableSpellcheck?: boolean;
onChange?: (newValue?: string) => void;
onClick?: (e: MouseEvent, pos?: ModelPosition | null) => void;
onKeyDown?: (e: KeyboardEvent) => void;
onBlur?: () => void;
}
export default function CKEditor({ currentValue, editor, config, disableNewlines, disableSpellcheck, onChange, onClick, ...restProps }: CKEditorOpts) {
const editorContainerRef = useRef<HTMLDivElement>(null);
const textEditorRef = useRef<CKTextEditor>(null);
useEffect(() => {
if (!editorContainerRef.current) return;
editor.create(editorContainerRef.current, config).then((textEditor) => {
textEditorRef.current = textEditor;
if (disableNewlines) {
textEditor.editing.view.document.on(
"enter",
(event, data) => {
// disable entering new line - see https://github.com/ckeditor/ckeditor5/issues/9422
data.preventDefault();
event.stop();
},
{ priority: "high" }
);
}
if (disableSpellcheck) {
const documentRoot = textEditor.editing.view.document.getRoot();
if (documentRoot) {
textEditor.editing.view.change((writer) => writer.setAttribute("spellcheck", "false", documentRoot));
}
}
if (onChange) {
textEditor.model.document.on("change:data", () => {
onChange(textEditor.getData())
});
}
if (currentValue) {
textEditor.setData(currentValue);
}
});
}, []);
useEffect(() => {
if (!textEditorRef.current) return;
textEditorRef.current.setData(currentValue ?? "");
}, [ currentValue ]);
return (
<div
ref={editorContainerRef}
onClick={(e) => {
if (onClick) {
const pos = textEditorRef.current?.model.document.selection.getFirstPosition();
onClick(e, pos);
}
}}
{...restProps}
/>
)
}