diff --git a/bin/copy-dist.ts b/bin/copy-dist.ts index 39ddd6cdf..6dc16077c 100644 --- a/bin/copy-dist.ts +++ b/bin/copy-dist.ts @@ -73,7 +73,6 @@ const copy = async () => { } const nodeModulesFolder = [ - "node_modules/@excalidraw/excalidraw/dist/", "node_modules/katex/dist/", "node_modules/dayjs/", "node_modules/boxicons/css/", diff --git a/bin/copy-trilium.sh b/bin/copy-trilium.sh index a9961847e..0d6206dea 100755 --- a/bin/copy-trilium.sh +++ b/bin/copy-trilium.sh @@ -49,7 +49,6 @@ cp "$script_dir/../build/electron-main.js" "$DIR" if [[ -d "$DIR"/node_modules ]]; then # cleanup of useless files in dependencies for d in 'image-q/demo' \ - '@excalidraw/excalidraw/dist/excalidraw-assets-dev' '@excalidraw/excalidraw/dist/excalidraw.development.js' '@excalidraw/excalidraw/dist/excalidraw-with-preact.development.js' \ 'mermaid/dist/mermaid.js' \ 'boxicons/svg' 'boxicons/node_modules/react'/* \ '@jimp/plugin-print/fonts' 'jimp/browser' 'jimp/fonts'; do diff --git a/package-lock.json b/package-lock.json index 8cb53fd12..f441eb0d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@mermaid-js/layout-elk": "0.1.7", "@mind-elixir/node-menu": "1.0.3", "@triliumnext/express-partial-content": "1.0.1", + "@types/react-dom": "18.3.1", "archiver": "7.0.1", "async-mutex": "0.5.0", "autocomplete.js": "0.38.1", @@ -133,6 +134,7 @@ "@types/mime-types": "2.1.4", "@types/multer": "1.4.12", "@types/node": "22.10.7", + "@types/react": "18.3.1", "@types/safe-compare": "1.1.2", "@types/sanitize-html": "2.13.0", "@types/sax": "1.2.7", @@ -3912,6 +3914,12 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" + }, "node_modules/@types/qs": { "version": "6.9.17", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", @@ -3926,6 +3934,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", + "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/readdir-glob": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz", @@ -6652,6 +6679,12 @@ "node": ">=18" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, "node_modules/cytoscape": { "version": "3.30.4", "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.4.tgz", diff --git a/package.json b/package.json index 3b6949bb5..044343879 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@mermaid-js/layout-elk": "0.1.7", "@mind-elixir/node-menu": "1.0.3", "@triliumnext/express-partial-content": "1.0.1", + "@types/react-dom": "18.3.1", "archiver": "7.0.1", "async-mutex": "0.5.0", "autocomplete.js": "0.38.1", @@ -175,6 +176,7 @@ "@types/mime-types": "2.1.4", "@types/multer": "1.4.12", "@types/node": "22.10.7", + "@types/react": "18.3.1", "@types/safe-compare": "1.1.2", "@types/sanitize-html": "2.13.0", "@types/sax": "1.2.7", diff --git a/src/public/app/services/library_loader.ts b/src/public/app/services/library_loader.ts index 2fa6b950e..912cb652b 100644 --- a/src/public/app/services/library_loader.ts +++ b/src/public/app/services/library_loader.ts @@ -72,10 +72,6 @@ const MERMAID: Library = { js: ["node_modules/mermaid/dist/mermaid.min.js"] }; -const EXCALIDRAW: Library = { - js: ["node_modules/react/umd/react.production.min.js", "node_modules/react-dom/umd/react-dom.production.min.js", "node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js"] -}; - const MARKJS: Library = { js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"] }; @@ -198,7 +194,6 @@ export default { KATEX, WHEEL_ZOOM, MERMAID, - EXCALIDRAW, MARKJS, I18NEXT, HIGHLIGHT_JS diff --git a/src/public/app/services/link.ts b/src/public/app/services/link.ts index e1a220b34..3e9d4f310 100644 --- a/src/public/app/services/link.ts +++ b/src/public/app/services/link.ts @@ -234,7 +234,7 @@ function goToLink(evt: MouseEvent | JQuery.ClickEvent) { return goToLinkExt(evt, hrefLink, $link); } -function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent, hrefLink: string | undefined, $link: JQuery | null) { +function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | React.PointerEvent, hrefLink: string | undefined, $link: JQuery | null) { if (hrefLink?.startsWith("data:")) { return true; } @@ -249,13 +249,10 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent, hrefLink: string | und const { notePath, viewScope } = parseNavigationStateFromUrl(hrefLink); const ctrlKey = utils.isCtrlKey(evt); - const isLeftClick = evt.which === 1; - const isMiddleClick = evt.which === 2; + const isLeftClick = ("which" in evt && evt.which === 1); + const isMiddleClick = ("which" in evt && evt.which === 2); const openInNewTab = (isLeftClick && ctrlKey) || isMiddleClick; - const leftClick = evt.which === 1; - const middleClick = evt.which === 2; - if (notePath) { if (openInNewTab) { appContext.tabManager.openTabWithNoteWithHoisting(notePath, { viewScope }); @@ -276,7 +273,7 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent, hrefLink: string | und const withinEditLink = $link?.hasClass("ck-link-actions__preview"); const outsideOfCKEditor = !$link || $link.closest("[contenteditable]").length === 0; - if (openInNewTab || (withinEditLink && (leftClick || middleClick)) || (outsideOfCKEditor && (leftClick || middleClick))) { + if (openInNewTab || (withinEditLink && (isLeftClick || isMiddleClick)) || (outsideOfCKEditor && (isLeftClick || isMiddleClick))) { if (hrefLink.toLowerCase().startsWith("http") || hrefLink.startsWith("api/")) { window.open(hrefLink, "_blank"); } else if ((hrefLink.toLowerCase().startsWith("file:") || hrefLink.toLowerCase().startsWith("geo:")) && utils.isElectron()) { diff --git a/src/public/app/services/utils.ts b/src/public/app/services/utils.ts index 9c7cb2d57..ff59d7170 100644 --- a/src/public/app/services/utils.ts +++ b/src/public/app/services/utils.ts @@ -97,7 +97,7 @@ function isMac() { return navigator.platform.indexOf("Mac") > -1; } -function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent) { +function isCtrlKey(evt: KeyboardEvent | MouseEvent | JQuery.ClickEvent | JQuery.ContextMenuEvent | JQuery.TriggeredEvent | React.PointerEvent) { return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey); } diff --git a/src/public/app/types.d.ts b/src/public/app/types.d.ts index 878391322..4c53d181f 100644 --- a/src/public/app/types.d.ts +++ b/src/public/app/types.d.ts @@ -54,72 +54,6 @@ declare global { process?: ElectronProcess; glob?: CustomGlobals; - React: { - createElement(any, any?, any?); - Fragment: any; - useState({ - width: undefined, - height: undefined - }); - useRef(ref: null); - useEffect(cb: () => void, args: unknown[]); - useCallback(cb: (el, ev) => void, args: unknown[]); - }; - ReactDOM: { - unmountComponentAtNode(el: HTMLElement); - createRoot(el: HTMLElement); - } - ExcalidrawLib: { - getSceneVersion(el: unknown[]): number; - exportToSvg(opts: { - elements: ExcalidrawElement[], - appState: ExcalidrawAppState, - exportPadding: number, - metadata: string, - files: ExcalidrawElement[] - }): Promise; - updateScene, - Excalidraw: unknown - } - EXCALIDRAW_ASSET_PATH: string; - } - - interface ExcalidrawApi { - getSceneElements(): ExcalidrawElement[]; - getAppState(): ExcalidrawAppState; - getFiles(): ExcalidrawElement[]; - updateScene(scene: ExcalidrawScene); - updateLibrary(opts: { libraryItems?: ExcalidrawLibrary[], merge: boolean }): Promise; - addFiles(files: ExcalidrawElement[]); - history: { - clear(); - } - } - - interface ExcalidrawElement { - fileId: number; - } - - interface ExcalidrawLibrary { - id: string; - name: string; - } - - interface ExcalidrawScene { - elements: unknown[]; - appState: ExcalidrawAppState; - collaborators: unknown[]; - } - - interface ExcalidrawAppState { - scrollX?: number; - scrollY?: number; - zoom?: number; - theme?: string; - width?: number; - height?: number; - offsetLeft?: number; - offsetTop?: number; } interface AutoCompleteConfig { diff --git a/src/public/app/widgets/type_widgets/canvas.ts b/src/public/app/widgets/type_widgets/canvas.ts index bdee2783e..8a70f5c67 100644 --- a/src/public/app/widgets/type_widgets/canvas.ts +++ b/src/public/app/widgets/type_widgets/canvas.ts @@ -1,9 +1,14 @@ -import libraryLoader from "../../services/library_loader.js"; import TypeWidget from "./type_widget.js"; import utils from "../../services/utils.js"; import linkService from "../../services/link.js"; import server from "../../services/server.js"; import type FNote from "../../entities/fnote.js"; +import type { default as ExcalidrawLib } from "@excalidraw/excalidraw"; +import type { ExcalidrawElement, Theme } from "@excalidraw/excalidraw/types/element/types.js"; +import type { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, LibraryItem, SceneData } from "@excalidraw/excalidraw/types/types.js"; +import type { JSX } from "react"; +import type React from "react"; + const TPL = `