mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	refactor(deps): use webpack import for canvas
This commit is contained in:
		| @@ -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/", | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										33
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										33
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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<HTMLElement> | null) { | ||||
| function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | React.PointerEvent<HTMLCanvasElement>, hrefLink: string | undefined, $link: JQuery<HTMLElement> | 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()) { | ||||
|   | ||||
| @@ -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<HTMLCanvasElement>) { | ||||
|     return (!isMac() && evt.ctrlKey) || (isMac() && evt.metaKey); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										66
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -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<HTMLElement>; | ||||
|             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<ExcalidrawLibrary[]>; | ||||
|         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 { | ||||
|   | ||||
| @@ -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 = ` | ||||
|     <div class="canvas-widget note-detail-canvas note-detail-printable note-detail"> | ||||
|         <style> | ||||
| @@ -54,8 +59,8 @@ const TPL = ` | ||||
|  | ||||
| interface CanvasContent { | ||||
|     elements: ExcalidrawElement[], | ||||
|     files: ExcalidrawElement[], | ||||
|     appState: ExcalidrawAppState | ||||
|     files: BinaryFileData[], | ||||
|     appState: Partial<AppState> | ||||
| } | ||||
|  | ||||
| interface AttachmentMetadata { | ||||
| @@ -114,13 +119,12 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|     private currentNoteId: string; | ||||
|     private currentSceneVersion: number; | ||||
|     private libraryChanged: boolean; | ||||
|     private librarycache: ExcalidrawLibrary[]; | ||||
|     private librarycache: LibraryItem[]; | ||||
|     private attachmentMetadata: AttachmentMetadata[]; | ||||
|     private themeStyle!: string; | ||||
|     private excalidrawApi!: ExcalidrawApi; | ||||
|     private excalidrawWrapperRef!: { | ||||
|         current: HTMLElement | ||||
|     }; | ||||
|     private themeStyle!: Theme; | ||||
|     private excalidrawLib!: typeof ExcalidrawLib; | ||||
|     private excalidrawApi!: ExcalidrawImperativeAPI; | ||||
|     private excalidrawWrapperRef!: React.RefObject<HTMLElement | null>; | ||||
|  | ||||
|     private $render!: JQuery<HTMLElement>; | ||||
|     private reactHandlers!: JQuery<HTMLElement>; | ||||
| @@ -133,7 +137,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         this.SCENE_VERSION_ERROR = -2; // -2 indicates error | ||||
|  | ||||
|         // ensure that assets are loaded from trilium | ||||
|         window.EXCALIDRAW_ASSET_PATH = `${window.location.origin}/node_modules/@excalidraw/excalidraw/dist/`; | ||||
|         // TODO: | ||||
|         (window as any).EXCALIDRAW_ASSET_PATH = `${window.location.origin}/node_modules/@excalidraw/excalidraw/dist/`; | ||||
|  | ||||
|         // temporary vars | ||||
|         this.currentNoteId = ""; | ||||
| @@ -169,22 +174,37 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         this.$widget.toggleClass("full-height", true); | ||||
|         this.$render = this.$widget.find(".canvas-render"); | ||||
|         const documentStyle = window.getComputedStyle(document.documentElement); | ||||
|         this.themeStyle = documentStyle.getPropertyValue("--theme-style")?.trim(); | ||||
|         this.themeStyle = documentStyle.getPropertyValue("--theme-style")?.trim() as Theme; | ||||
|  | ||||
|         libraryLoader.requireLibrary(libraryLoader.EXCALIDRAW).then(() => { | ||||
|             const React = window.React; | ||||
|             const ReactDOM = window.ReactDOM; | ||||
|         this.#init(); | ||||
|  | ||||
|         return this.$widget; | ||||
|     } | ||||
|  | ||||
|     async #init() { | ||||
|         const renderElement = this.$render.get(0); | ||||
|         if (!renderElement) { | ||||
|             throw new Error("Unable to find element to render."); | ||||
|         } | ||||
|  | ||||
|             ReactDOM.unmountComponentAtNode(renderElement); | ||||
|             const root = ReactDOM.createRoot(renderElement); | ||||
|             root.render(React.createElement(() => this.createExcalidrawReactApp())); | ||||
|         }); | ||||
|         // See https://github.com/excalidraw/excalidraw/issues/7899. | ||||
|         if (!window.process) { | ||||
|             (window.process as any) = {}; | ||||
|         } | ||||
|         if (!window.process.env) { | ||||
|             window.process.env = {}; | ||||
|         } | ||||
|         (window.process.env as any).PREACT = false; | ||||
|  | ||||
|         return this.$widget; | ||||
|         const excalidraw = (await import("@excalidraw/excalidraw")); | ||||
|         this.excalidrawLib = excalidraw; | ||||
|  | ||||
|         const { unmountComponentAtNode } = await import("react-dom"); | ||||
|         const { createRoot } = await import("react-dom/client"); | ||||
|         const React = (await import("react")).default; | ||||
|         unmountComponentAtNode(renderElement); | ||||
|         const root = createRoot(renderElement); | ||||
|         root.render(React.createElement(() => this.createExcalidrawReactApp(React, excalidraw.Excalidraw))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -215,15 +235,15 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|          * newly instantiated? | ||||
|          */ | ||||
|         if (!blob?.content?.trim()) { | ||||
|             const sceneData = { | ||||
|             const sceneData: SceneData = { | ||||
|                 elements: [], | ||||
|                 appState: { | ||||
|                     theme: this.themeStyle | ||||
|                 }, | ||||
|                 collaborators: [] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             this.excalidrawApi.updateScene(sceneData); | ||||
|             // TODO: Props mismatch. | ||||
|             this.excalidrawApi.updateScene(sceneData as any); | ||||
|         } else if (blob.content) { | ||||
|             let content: CanvasContent; | ||||
|  | ||||
| @@ -240,26 +260,28 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 }; | ||||
|             } | ||||
|  | ||||
|             const { elements, files, appState = {} } = content; | ||||
|             const { elements, files } = content; | ||||
|             const appState: Partial<AppState> = content.appState ?? {}; | ||||
|  | ||||
|             appState.theme = this.themeStyle; | ||||
|  | ||||
|             if (this.excalidrawWrapperRef.current) { | ||||
|                 const boundingClientRect = this.excalidrawWrapperRef.current.getBoundingClientRect(); | ||||
|                 appState.width = boundingClientRect.width; | ||||
|                 appState.height = boundingClientRect.height; | ||||
|                 appState.offsetLeft = boundingClientRect.left; | ||||
|                 appState.offsetTop = boundingClientRect.top; | ||||
|             } | ||||
|  | ||||
|             const sceneData: ExcalidrawScene = { | ||||
|             const sceneData: SceneData = { | ||||
|                 elements, | ||||
|                 appState, | ||||
|                 collaborators: [] | ||||
|                 appState | ||||
|             }; | ||||
|  | ||||
|             // files are expected in an array when loading. they are stored as a key-index object | ||||
|             // see example for loading here: | ||||
|             // https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68 | ||||
|             const fileArray = []; | ||||
|             const fileArray: BinaryFileData[] = []; | ||||
|             for (const fileId in files) { | ||||
|                 const file = files[fileId]; | ||||
|                 // TODO: dataURL is replaceable with a trilium image url | ||||
| @@ -288,7 +310,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                 } | ||||
|  | ||||
|                 // Extract libraryItems from the blobs | ||||
|                 const libraryItems = results.map((result) => result?.blob?.getJsonContentSafely()).filter((item) => !!item) as ExcalidrawLibrary[]; | ||||
|                 const libraryItems = results.map((result) => result?.blob?.getJsonContentSafely()).filter((item) => !!item) as LibraryItem[]; | ||||
|  | ||||
|                 // Extract metadata for each attachment | ||||
|                 const metadata = results.map((result) => result.metadata); | ||||
| @@ -302,7 +324,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             }); | ||||
|  | ||||
|             // Update the scene | ||||
|             this.excalidrawApi.updateScene(sceneData); | ||||
|             // TODO: Fix type of sceneData | ||||
|             this.excalidrawApi.updateScene(sceneData as any); | ||||
|             this.excalidrawApi.addFiles(fileArray); | ||||
|             this.excalidrawApi.history.clear(); | ||||
|         } | ||||
| @@ -328,18 +351,17 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         const files = this.excalidrawApi.getFiles(); | ||||
|  | ||||
|         // parallel svg export to combat bitrot and enable rendering image for note inclusion, preview, and share | ||||
|         const svg = await window.ExcalidrawLib.exportToSvg({ | ||||
|         const svg = await this.excalidrawLib.exportToSvg({ | ||||
|             elements, | ||||
|             appState, | ||||
|             exportPadding: 5, // 5 px padding | ||||
|             metadata: "trilium-export", | ||||
|             files | ||||
|         }); | ||||
|         const svgString = svg.outerHTML; | ||||
|  | ||||
|         const activeFiles: Record<string, ExcalidrawElement> = {}; | ||||
|         const activeFiles: Record<string, BinaryFileData> = {}; | ||||
|         elements.forEach((element) => { | ||||
|             if (element.fileId) { | ||||
|             if ("fileId" in element && element.fileId) { | ||||
|                 activeFiles[element.fileId] = files[element.fileId]; | ||||
|             } | ||||
|         }); | ||||
| @@ -362,7 +384,12 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             // this.libraryChanged is unset in dataSaved() | ||||
|  | ||||
|             // there's no separate method to get library items, so have to abuse this one | ||||
|             const libraryItems = await this.excalidrawApi.updateLibrary({ merge: true }); | ||||
|             const libraryItems = await this.excalidrawApi.updateLibrary({ | ||||
|                 libraryItems(currentLibraryItems) { | ||||
|                     return []; | ||||
|                 }, | ||||
|                 merge: true | ||||
|             }); | ||||
|  | ||||
|             // excalidraw saves the library as a own state. the items are saved to libraryItems. then we compare the library right now with a libraryitemcache. The cache is filled when we first load the Library into the note. | ||||
|             //We need the cache to delete old attachments later in the server. | ||||
| @@ -445,33 +472,35 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     createExcalidrawReactApp() { | ||||
|         const React = window.React; | ||||
|         const { Excalidraw } = window.ExcalidrawLib; | ||||
|         const excalidrawWrapperRef = React.useRef(null); | ||||
|     createExcalidrawReactApp(react: typeof React, excalidrawComponent: React.MemoExoticComponent<(props: ExcalidrawProps) => JSX.Element>) { | ||||
|         const excalidrawWrapperRef = react.useRef<HTMLElement>(null); | ||||
|         this.excalidrawWrapperRef = excalidrawWrapperRef; | ||||
|         const [dimensions, setDimensions] = React.useState({ | ||||
|         const [dimensions, setDimensions] = react.useState<{ width?: number, height?: number}>({ | ||||
|             width: undefined, | ||||
|             height: undefined | ||||
|         }); | ||||
|  | ||||
|         React.useEffect(() => { | ||||
|         react.useEffect(() => { | ||||
|             if (excalidrawWrapperRef.current) { | ||||
|                 const dimensions = { | ||||
|                     width: excalidrawWrapperRef.current.getBoundingClientRect().width, | ||||
|                     height: excalidrawWrapperRef.current.getBoundingClientRect().height | ||||
|                 }; | ||||
|                 setDimensions(dimensions); | ||||
|             } | ||||
|  | ||||
|             const onResize = () => { | ||||
|                 if (this.note?.type !== "canvas") { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 if (excalidrawWrapperRef.current) { | ||||
|                     const dimensions = { | ||||
|                         width: excalidrawWrapperRef.current.getBoundingClientRect().width, | ||||
|                         height: excalidrawWrapperRef.current.getBoundingClientRect().height | ||||
|                     }; | ||||
|                     setDimensions(dimensions); | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             window.addEventListener("resize", onResize); | ||||
| @@ -479,8 +508,11 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             return () => window.removeEventListener("resize", onResize); | ||||
|         }, [excalidrawWrapperRef]); | ||||
|  | ||||
|         const onLinkOpen = React.useCallback((element, event) => { | ||||
|         const onLinkOpen = react.useCallback<NonNullable<ExcalidrawProps["onLinkOpen"]>>((element, event) => { | ||||
|             let link = element.link; | ||||
|             if (!link) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (link.startsWith("root/")) { | ||||
|                 link = "#" + link; | ||||
| @@ -493,25 +525,24 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|             return linkService.goToLinkExt(nativeEvent, link, null); | ||||
|         }, []); | ||||
|  | ||||
|         return React.createElement( | ||||
|             React.Fragment, | ||||
|         return react.createElement( | ||||
|             react.Fragment, | ||||
|             null, | ||||
|             React.createElement( | ||||
|             react.createElement( | ||||
|                 "div", | ||||
|                 { | ||||
|                     className: "excalidraw-wrapper", | ||||
|                     ref: excalidrawWrapperRef | ||||
|                 }, | ||||
|                 React.createElement(Excalidraw, { | ||||
|                 react.createElement(excalidrawComponent, { | ||||
|                     // this makes sure that 1) manual theme switch button is hidden 2) theme stays as it should after opening menu | ||||
|                     theme: this.themeStyle, | ||||
|                     excalidrawAPI: (api: ExcalidrawApi) => { | ||||
|                     excalidrawAPI: (api: ExcalidrawImperativeAPI) => { | ||||
|                         this.excalidrawApi = api; | ||||
|                     }, | ||||
|                     width: dimensions.width, | ||||
|                     height: dimensions.height, | ||||
|                     onPaste: (data: unknown, event: unknown) => { | ||||
|                         console.log("Verbose: excalidraw internal paste. No trilium action implemented.", data, event); | ||||
|                         return false; | ||||
|                     }, | ||||
|                     onLibraryChange: () => { | ||||
|                         this.libraryChanged = true; | ||||
| @@ -528,9 +559,11 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                     autoFocus: false, | ||||
|                     onLinkOpen, | ||||
|                     UIOptions: { | ||||
|                         canvasActions: { | ||||
|                             saveToActiveFile: false, | ||||
|                             saveAsImage: false | ||||
|                         } | ||||
|                     } | ||||
|                 }) | ||||
|             ) | ||||
|         ); | ||||
| @@ -555,7 +588,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|     getSceneVersion() { | ||||
|         if (this.excalidrawApi) { | ||||
|             const elements = this.excalidrawApi.getSceneElements(); | ||||
|             return window.ExcalidrawLib.getSceneVersion(elements); | ||||
|             return this.excalidrawLib.getSceneVersion(elements); | ||||
|         } else { | ||||
|             return this.SCENE_VERSION_ERROR; | ||||
|         } | ||||
|   | ||||
| @@ -44,13 +44,6 @@ async function register(app: express.Application) { | ||||
|     app.use(`/assets/vX/stylesheets`, express.static(path.join(srcRoot, "public/stylesheets"))); | ||||
|     app.use(`/${assetPath}/libraries`, persistentCacheStatic(path.join(srcRoot, "..", "libraries"))); | ||||
|     app.use(`/assets/vX/libraries`, express.static(path.join(srcRoot, "..", "libraries"))); | ||||
|  | ||||
|     // excalidraw-view mode in shared notes | ||||
|     app.use(`/${assetPath}/node_modules/react/umd/react.production.min.js`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/react/umd/react.production.min.js"))); | ||||
|     app.use(`/${assetPath}/node_modules/react/umd/react.development.js`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/react/umd/react.development.js"))); | ||||
|     app.use(`/${assetPath}/node_modules/react-dom/umd/react-dom.production.min.js`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/react-dom/umd/react-dom.production.min.js"))); | ||||
|     app.use(`/${assetPath}/node_modules/react-dom/umd/react-dom.development.js`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/react-dom/umd/react-dom.development.js"))); | ||||
|     // expose the whole dist folder since complete assets are needed in edit and share | ||||
|     app.use(`/node_modules/@excalidraw/excalidraw/dist/`, express.static(path.join(srcRoot, "..", "node_modules/@excalidraw/excalidraw/dist/"))); | ||||
|     app.use(`/${assetPath}/node_modules/@excalidraw/excalidraw/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/@excalidraw/excalidraw/dist/"))); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user