mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 08:58:58 +01:00
refactor(react/type_widget): separate Trilium-specific implementation
This commit is contained in:
parent
43dcdf8925
commit
f496caa92c
@ -1,15 +1,16 @@
|
|||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import { default as VanillaCodeMirror } from "@triliumnext/codemirror";
|
import { getThemeById, default as VanillaCodeMirror } from "@triliumnext/codemirror";
|
||||||
import { TypeWidgetProps } from "../type_widget";
|
import { TypeWidgetProps } from "../type_widget";
|
||||||
import "./code.css";
|
import "./code.css";
|
||||||
import CodeMirror, { CodeMirrorProps } from "./CodeMirror";
|
import CodeMirror, { CodeMirrorProps } from "./CodeMirror";
|
||||||
import utils from "../../../services/utils";
|
import utils from "../../../services/utils";
|
||||||
import { useEditorSpacedUpdate, useNoteBlob, useSyncedRef, useTriliumOptionBool } from "../../react/hooks";
|
import { useEditorSpacedUpdate, useNoteBlob, useSyncedRef, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
|
||||||
import { t } from "../../../services/i18n";
|
import { t } from "../../../services/i18n";
|
||||||
import appContext from "../../../components/app_context";
|
import appContext from "../../../components/app_context";
|
||||||
import TouchBar, { TouchBarButton } from "../../react/TouchBar";
|
import TouchBar, { TouchBarButton } from "../../react/TouchBar";
|
||||||
import keyboard_actions from "../../../services/keyboard_actions";
|
import keyboard_actions from "../../../services/keyboard_actions";
|
||||||
import { refToJQuerySelector } from "../../react/react_utils";
|
import { refToJQuerySelector } from "../../react/react_utils";
|
||||||
|
import { CODE_THEME_DEFAULT_PREFIX as DEFAULT_PREFIX } from "../constants";
|
||||||
|
|
||||||
export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWidgetProps) {
|
export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWidgetProps) {
|
||||||
const [ content, setContent ] = useState("");
|
const [ content, setContent ] = useState("");
|
||||||
@ -24,12 +25,11 @@ export function ReadOnlyCode({ note, viewScope, ntxId, parentComponent }: TypeWi
|
|||||||
return (
|
return (
|
||||||
<div className="note-detail-readonly-code note-detail-printable">
|
<div className="note-detail-readonly-code note-detail-printable">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
note={note} parentComponent={parentComponent}
|
ntxId={ntxId} note={note} parentComponent={parentComponent}
|
||||||
className="note-detail-readonly-code-content"
|
className="note-detail-readonly-code-content"
|
||||||
content={content}
|
content={content}
|
||||||
mime={note.mime}
|
mime={note.mime}
|
||||||
readOnly
|
readOnly
|
||||||
ntxId={ntxId}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -63,10 +63,9 @@ export function EditableCode({ note, ntxId, debounceUpdate, parentComponent }: T
|
|||||||
return (
|
return (
|
||||||
<div className="note-detail-code note-detail-printable">
|
<div className="note-detail-code note-detail-printable">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
note={note} parentComponent={parentComponent}
|
ntxId={ntxId} note={note} parentComponent={parentComponent}
|
||||||
editorRef={editorRef} containerRef={containerRef}
|
editorRef={editorRef} containerRef={containerRef}
|
||||||
className="note-detail-code-editor"
|
className="note-detail-code-editor"
|
||||||
ntxId={ntxId}
|
|
||||||
placeholder={t("editable_code.placeholder")}
|
placeholder={t("editable_code.placeholder")}
|
||||||
vimKeybindings={vimKeymapEnabled}
|
vimKeybindings={vimKeymapEnabled}
|
||||||
tabIndex={300}
|
tabIndex={300}
|
||||||
@ -87,8 +86,12 @@ export function EditableCode({ note, ntxId, debounceUpdate, parentComponent }: T
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function CodeEditor({ note, parentComponent, containerRef: externalContainerRef, ...editorProps }: Omit<CodeMirrorProps, "onThemeChange"> & Pick<TypeWidgetProps, "note" | "parentComponent">) {
|
function CodeEditor({ note, parentComponent, ntxId, containerRef: externalContainerRef, editorRef: externalEditorRef, ...editorProps }: Omit<CodeMirrorProps, "onThemeChange" | "lineWrapping"> & Pick<TypeWidgetProps, "note" | "parentComponent" | "ntxId">) {
|
||||||
|
const codeEditorRef = useRef<VanillaCodeMirror>(null);
|
||||||
const containerRef = useSyncedRef(externalContainerRef);
|
const containerRef = useSyncedRef(externalContainerRef);
|
||||||
|
const initialized = useRef($.Deferred());
|
||||||
|
const [ codeLineWrapEnabled ] = useTriliumOptionBool("codeLineWrapEnabled");
|
||||||
|
const [ codeNoteTheme ] = useTriliumOption("codeNoteTheme");
|
||||||
|
|
||||||
// React to background color.
|
// React to background color.
|
||||||
const [ backgroundColor, setBackgroundColor ] = useState<string>();
|
const [ backgroundColor, setBackgroundColor ] = useState<string>();
|
||||||
@ -100,14 +103,47 @@ function CodeEditor({ note, parentComponent, containerRef: externalContainerRef,
|
|||||||
};
|
};
|
||||||
}, [ backgroundColor ]);
|
}, [ backgroundColor ]);
|
||||||
|
|
||||||
|
// React to theme changes.
|
||||||
|
useEffect(() => {
|
||||||
|
if (codeEditorRef.current && codeNoteTheme.startsWith(DEFAULT_PREFIX)) {
|
||||||
|
const theme = getThemeById(codeNoteTheme.substring(DEFAULT_PREFIX.length));
|
||||||
|
if (theme) {
|
||||||
|
codeEditorRef.current.setTheme(theme).then(() => {
|
||||||
|
if (note?.mime === "text/x-sqlite;schema=trilium") return;
|
||||||
|
const editor = containerRef.current?.querySelector(".cm-editor");
|
||||||
|
if (!editor) return;
|
||||||
|
const style = window.getComputedStyle(editor);
|
||||||
|
setBackgroundColor(style.backgroundColor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [ codeEditorRef, codeNoteTheme ]);
|
||||||
|
|
||||||
|
useTriliumEvent("executeWithCodeEditor", async ({ resolve, ntxId: eventNtxId }) => {
|
||||||
|
if (eventNtxId !== ntxId) return;
|
||||||
|
await initialized.current.promise();
|
||||||
|
resolve(codeEditorRef.current!);
|
||||||
|
});
|
||||||
|
|
||||||
|
useTriliumEvent("executeWithContentElement", async ({ resolve, ntxId: eventNtxId}) => {
|
||||||
|
if (eventNtxId !== ntxId) return;
|
||||||
|
await initialized.current.promise();
|
||||||
|
resolve(refToJQuerySelector(containerRef));
|
||||||
|
});
|
||||||
|
|
||||||
return <CodeMirror
|
return <CodeMirror
|
||||||
{...editorProps}
|
{...editorProps}
|
||||||
|
editorRef={codeEditorRef}
|
||||||
containerRef={containerRef}
|
containerRef={containerRef}
|
||||||
onThemeChange={note?.mime !== "text/x-sqlite;schema=trilium" ? () => {
|
lineWrapping={codeLineWrapEnabled}
|
||||||
const editor = containerRef.current?.querySelector(".cm-editor");
|
onInitialized={() => {
|
||||||
if (!editor) return;
|
if (externalContainerRef && containerRef.current) {
|
||||||
const style = window.getComputedStyle(editor);
|
externalContainerRef.current = containerRef.current;
|
||||||
setBackgroundColor(style.backgroundColor);
|
}
|
||||||
} : undefined}
|
if (externalEditorRef && codeEditorRef.current) {
|
||||||
|
externalEditorRef.current = codeEditorRef.current;
|
||||||
|
}
|
||||||
|
initialized.current.resolve();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +1,20 @@
|
|||||||
import { useEffect, useRef } from "preact/hooks";
|
import { useEffect, useRef } from "preact/hooks";
|
||||||
import { EditorConfig, getThemeById, default as VanillaCodeMirror } from "@triliumnext/codemirror";
|
import { EditorConfig, default as VanillaCodeMirror } from "@triliumnext/codemirror";
|
||||||
import { useSyncedRef, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
|
import { useSyncedRef } from "../../react/hooks";
|
||||||
import { refToJQuerySelector } from "../../react/react_utils";
|
|
||||||
import { RefObject } from "preact";
|
import { RefObject } from "preact";
|
||||||
import { CODE_THEME_DEFAULT_PREFIX as DEFAULT_PREFIX } from "../constants";
|
|
||||||
|
|
||||||
export interface CodeMirrorProps extends Omit<EditorConfig, "parent"> {
|
export interface CodeMirrorProps extends Omit<EditorConfig, "parent"> {
|
||||||
content: string;
|
content: string;
|
||||||
mime: string;
|
mime: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
ntxId: string | null | undefined;
|
|
||||||
editorRef?: RefObject<VanillaCodeMirror>;
|
editorRef?: RefObject<VanillaCodeMirror>;
|
||||||
containerRef?: RefObject<HTMLPreElement>;
|
containerRef?: RefObject<HTMLPreElement>;
|
||||||
onThemeChange?: () => void;
|
onInitialized?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CodeMirror({ className, content, mime, ntxId, editorRef: externalEditorRef, containerRef: externalContainerRef, onThemeChange, ...extraOpts }: CodeMirrorProps) {
|
export default function CodeMirror({ className, content, mime, editorRef: externalEditorRef, containerRef: externalContainerRef, onInitialized, ...extraOpts }: CodeMirrorProps) {
|
||||||
const parentRef = useSyncedRef(externalContainerRef);
|
const parentRef = useSyncedRef(externalContainerRef);
|
||||||
const codeEditorRef = useRef<VanillaCodeMirror>();
|
const codeEditorRef = useRef<VanillaCodeMirror>();
|
||||||
const [ codeLineWrapEnabled ] = useTriliumOptionBool("codeLineWrapEnabled");
|
|
||||||
const [ codeNoteTheme ] = useTriliumOption("codeNoteTheme");
|
|
||||||
const initialized = $.Deferred();
|
|
||||||
|
|
||||||
// Integration within Trilium's event system.
|
|
||||||
useTriliumEvent("executeWithCodeEditor", async ({ resolve, ntxId: eventNtxId }) => {
|
|
||||||
if (eventNtxId !== ntxId) return;
|
|
||||||
await initialized.promise();
|
|
||||||
resolve(codeEditorRef.current!);
|
|
||||||
});
|
|
||||||
|
|
||||||
useTriliumEvent("executeWithContentElement", async ({ resolve, ntxId: eventNtxId}) => {
|
|
||||||
if (eventNtxId !== ntxId) return;
|
|
||||||
await initialized.promise();
|
|
||||||
resolve(refToJQuerySelector(parentRef));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create CodeMirror instance.
|
// Create CodeMirror instance.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -41,30 +22,17 @@ export default function CodeMirror({ className, content, mime, ntxId, editorRef:
|
|||||||
|
|
||||||
const codeEditor = new VanillaCodeMirror({
|
const codeEditor = new VanillaCodeMirror({
|
||||||
parent: parentRef.current,
|
parent: parentRef.current,
|
||||||
lineWrapping: codeLineWrapEnabled,
|
|
||||||
...extraOpts
|
...extraOpts
|
||||||
});
|
});
|
||||||
codeEditorRef.current = codeEditor;
|
codeEditorRef.current = codeEditor;
|
||||||
if (externalEditorRef) {
|
if (externalEditorRef) {
|
||||||
externalEditorRef.current = codeEditor;
|
externalEditorRef.current = codeEditor;
|
||||||
}
|
}
|
||||||
initialized.resolve();
|
onInitialized?.();
|
||||||
|
|
||||||
return () => codeEditor.destroy();
|
return () => codeEditor.destroy();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// React to theme changes.
|
|
||||||
useEffect(() => {
|
|
||||||
if (codeEditorRef.current && codeNoteTheme.startsWith(DEFAULT_PREFIX)) {
|
|
||||||
const theme = getThemeById(codeNoteTheme.substring(DEFAULT_PREFIX.length));
|
|
||||||
if (theme) {
|
|
||||||
codeEditorRef.current.setTheme(theme).then(() => {
|
|
||||||
onThemeChange?.();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [ codeEditorRef, codeNoteTheme ]);
|
|
||||||
|
|
||||||
// React to text changes.
|
// React to text changes.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const codeEditor = codeEditorRef.current;
|
const codeEditor = codeEditorRef.current;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user