mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-10-30 18:34:22 +01:00 
			
		
		
		
	Move file system operations to separate module (#510)
This commit is contained in:
		
							
								
								
									
										87
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										87
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -2721,6 +2721,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", | ||||||
|       "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" |       "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" | ||||||
|     }, |     }, | ||||||
|  |     "browser-nativefs": { | ||||||
|  |       "version": "0.0.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/browser-nativefs/-/browser-nativefs-0.0.5.tgz", | ||||||
|  |       "integrity": "sha512-0yS+D32qmIgg7YAUpaSfLEMfG6Co5ajPhbCT7agHsF6PuF6p7VVFNT5x8yAEWLAfPJHyNW/1nxNL54JZLzn6jg==" | ||||||
|  |     }, | ||||||
|     "browser-process-hrtime": { |     "browser-process-hrtime": { | ||||||
|       "version": "0.1.3", |       "version": "0.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", |       "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", | ||||||
| @@ -3054,7 +3059,8 @@ | |||||||
|             }, |             }, | ||||||
|             "ansi-regex": { |             "ansi-regex": { | ||||||
|               "version": "2.1.1", |               "version": "2.1.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "aproba": { |             "aproba": { | ||||||
|               "version": "1.2.0", |               "version": "1.2.0", | ||||||
| @@ -3072,11 +3078,13 @@ | |||||||
|             }, |             }, | ||||||
|             "balanced-match": { |             "balanced-match": { | ||||||
|               "version": "1.0.0", |               "version": "1.0.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "brace-expansion": { |             "brace-expansion": { | ||||||
|               "version": "1.1.11", |               "version": "1.1.11", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "balanced-match": "^1.0.0", |                 "balanced-match": "^1.0.0", | ||||||
|                 "concat-map": "0.0.1" |                 "concat-map": "0.0.1" | ||||||
| @@ -3089,15 +3097,18 @@ | |||||||
|             }, |             }, | ||||||
|             "code-point-at": { |             "code-point-at": { | ||||||
|               "version": "1.1.0", |               "version": "1.1.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "concat-map": { |             "concat-map": { | ||||||
|               "version": "0.0.1", |               "version": "0.0.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "console-control-strings": { |             "console-control-strings": { | ||||||
|               "version": "1.1.0", |               "version": "1.1.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "core-util-is": { |             "core-util-is": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
| @@ -3200,7 +3211,8 @@ | |||||||
|             }, |             }, | ||||||
|             "inherits": { |             "inherits": { | ||||||
|               "version": "2.0.4", |               "version": "2.0.4", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "ini": { |             "ini": { | ||||||
|               "version": "1.3.5", |               "version": "1.3.5", | ||||||
| @@ -3210,6 +3222,7 @@ | |||||||
|             "is-fullwidth-code-point": { |             "is-fullwidth-code-point": { | ||||||
|               "version": "1.0.0", |               "version": "1.0.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "number-is-nan": "^1.0.0" |                 "number-is-nan": "^1.0.0" | ||||||
|               } |               } | ||||||
| @@ -3222,17 +3235,20 @@ | |||||||
|             "minimatch": { |             "minimatch": { | ||||||
|               "version": "3.0.4", |               "version": "3.0.4", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "brace-expansion": "^1.1.7" |                 "brace-expansion": "^1.1.7" | ||||||
|               } |               } | ||||||
|             }, |             }, | ||||||
|             "minimist": { |             "minimist": { | ||||||
|               "version": "0.0.8", |               "version": "0.0.8", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "minipass": { |             "minipass": { | ||||||
|               "version": "2.9.0", |               "version": "2.9.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "safe-buffer": "^5.1.2", |                 "safe-buffer": "^5.1.2", | ||||||
|                 "yallist": "^3.0.0" |                 "yallist": "^3.0.0" | ||||||
| @@ -3249,6 +3265,7 @@ | |||||||
|             "mkdirp": { |             "mkdirp": { | ||||||
|               "version": "0.5.1", |               "version": "0.5.1", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "minimist": "0.0.8" |                 "minimist": "0.0.8" | ||||||
|               } |               } | ||||||
| @@ -3329,7 +3346,8 @@ | |||||||
|             }, |             }, | ||||||
|             "number-is-nan": { |             "number-is-nan": { | ||||||
|               "version": "1.0.1", |               "version": "1.0.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "object-assign": { |             "object-assign": { | ||||||
|               "version": "4.1.1", |               "version": "4.1.1", | ||||||
| @@ -3339,6 +3357,7 @@ | |||||||
|             "once": { |             "once": { | ||||||
|               "version": "1.4.0", |               "version": "1.4.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "wrappy": "1" |                 "wrappy": "1" | ||||||
|               } |               } | ||||||
| @@ -3414,7 +3433,8 @@ | |||||||
|             }, |             }, | ||||||
|             "safe-buffer": { |             "safe-buffer": { | ||||||
|               "version": "5.1.2", |               "version": "5.1.2", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "safer-buffer": { |             "safer-buffer": { | ||||||
|               "version": "2.1.2", |               "version": "2.1.2", | ||||||
| @@ -3444,6 +3464,7 @@ | |||||||
|             "string-width": { |             "string-width": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "code-point-at": "^1.0.0", |                 "code-point-at": "^1.0.0", | ||||||
|                 "is-fullwidth-code-point": "^1.0.0", |                 "is-fullwidth-code-point": "^1.0.0", | ||||||
| @@ -3461,6 +3482,7 @@ | |||||||
|             "strip-ansi": { |             "strip-ansi": { | ||||||
|               "version": "3.0.1", |               "version": "3.0.1", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "ansi-regex": "^2.0.0" |                 "ansi-regex": "^2.0.0" | ||||||
|               } |               } | ||||||
| @@ -3499,11 +3521,13 @@ | |||||||
|             }, |             }, | ||||||
|             "wrappy": { |             "wrappy": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "yallist": { |             "yallist": { | ||||||
|               "version": "3.1.1", |               "version": "3.1.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
| @@ -7687,7 +7711,8 @@ | |||||||
|             }, |             }, | ||||||
|             "ansi-regex": { |             "ansi-regex": { | ||||||
|               "version": "2.1.1", |               "version": "2.1.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "aproba": { |             "aproba": { | ||||||
|               "version": "1.2.0", |               "version": "1.2.0", | ||||||
| @@ -7705,11 +7730,13 @@ | |||||||
|             }, |             }, | ||||||
|             "balanced-match": { |             "balanced-match": { | ||||||
|               "version": "1.0.0", |               "version": "1.0.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "brace-expansion": { |             "brace-expansion": { | ||||||
|               "version": "1.1.11", |               "version": "1.1.11", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "balanced-match": "^1.0.0", |                 "balanced-match": "^1.0.0", | ||||||
|                 "concat-map": "0.0.1" |                 "concat-map": "0.0.1" | ||||||
| @@ -7722,15 +7749,18 @@ | |||||||
|             }, |             }, | ||||||
|             "code-point-at": { |             "code-point-at": { | ||||||
|               "version": "1.1.0", |               "version": "1.1.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "concat-map": { |             "concat-map": { | ||||||
|               "version": "0.0.1", |               "version": "0.0.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "console-control-strings": { |             "console-control-strings": { | ||||||
|               "version": "1.1.0", |               "version": "1.1.0", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "core-util-is": { |             "core-util-is": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
| @@ -7833,7 +7863,8 @@ | |||||||
|             }, |             }, | ||||||
|             "inherits": { |             "inherits": { | ||||||
|               "version": "2.0.4", |               "version": "2.0.4", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "ini": { |             "ini": { | ||||||
|               "version": "1.3.5", |               "version": "1.3.5", | ||||||
| @@ -7843,6 +7874,7 @@ | |||||||
|             "is-fullwidth-code-point": { |             "is-fullwidth-code-point": { | ||||||
|               "version": "1.0.0", |               "version": "1.0.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "number-is-nan": "^1.0.0" |                 "number-is-nan": "^1.0.0" | ||||||
|               } |               } | ||||||
| @@ -7855,17 +7887,20 @@ | |||||||
|             "minimatch": { |             "minimatch": { | ||||||
|               "version": "3.0.4", |               "version": "3.0.4", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "brace-expansion": "^1.1.7" |                 "brace-expansion": "^1.1.7" | ||||||
|               } |               } | ||||||
|             }, |             }, | ||||||
|             "minimist": { |             "minimist": { | ||||||
|               "version": "0.0.8", |               "version": "0.0.8", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "minipass": { |             "minipass": { | ||||||
|               "version": "2.9.0", |               "version": "2.9.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "safe-buffer": "^5.1.2", |                 "safe-buffer": "^5.1.2", | ||||||
|                 "yallist": "^3.0.0" |                 "yallist": "^3.0.0" | ||||||
| @@ -7882,6 +7917,7 @@ | |||||||
|             "mkdirp": { |             "mkdirp": { | ||||||
|               "version": "0.5.1", |               "version": "0.5.1", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "minimist": "0.0.8" |                 "minimist": "0.0.8" | ||||||
|               } |               } | ||||||
| @@ -7962,7 +7998,8 @@ | |||||||
|             }, |             }, | ||||||
|             "number-is-nan": { |             "number-is-nan": { | ||||||
|               "version": "1.0.1", |               "version": "1.0.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "object-assign": { |             "object-assign": { | ||||||
|               "version": "4.1.1", |               "version": "4.1.1", | ||||||
| @@ -7972,6 +8009,7 @@ | |||||||
|             "once": { |             "once": { | ||||||
|               "version": "1.4.0", |               "version": "1.4.0", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "wrappy": "1" |                 "wrappy": "1" | ||||||
|               } |               } | ||||||
| @@ -8047,7 +8085,8 @@ | |||||||
|             }, |             }, | ||||||
|             "safe-buffer": { |             "safe-buffer": { | ||||||
|               "version": "5.1.2", |               "version": "5.1.2", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "safer-buffer": { |             "safer-buffer": { | ||||||
|               "version": "2.1.2", |               "version": "2.1.2", | ||||||
| @@ -8077,6 +8116,7 @@ | |||||||
|             "string-width": { |             "string-width": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "code-point-at": "^1.0.0", |                 "code-point-at": "^1.0.0", | ||||||
|                 "is-fullwidth-code-point": "^1.0.0", |                 "is-fullwidth-code-point": "^1.0.0", | ||||||
| @@ -8094,6 +8134,7 @@ | |||||||
|             "strip-ansi": { |             "strip-ansi": { | ||||||
|               "version": "3.0.1", |               "version": "3.0.1", | ||||||
|               "bundled": true, |               "bundled": true, | ||||||
|  |               "optional": true, | ||||||
|               "requires": { |               "requires": { | ||||||
|                 "ansi-regex": "^2.0.0" |                 "ansi-regex": "^2.0.0" | ||||||
|               } |               } | ||||||
| @@ -8132,11 +8173,13 @@ | |||||||
|             }, |             }, | ||||||
|             "wrappy": { |             "wrappy": { | ||||||
|               "version": "1.0.2", |               "version": "1.0.2", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             }, |             }, | ||||||
|             "yallist": { |             "yallist": { | ||||||
|               "version": "3.1.1", |               "version": "3.1.1", | ||||||
|               "bundled": true |               "bundled": true, | ||||||
|  |               "optional": true | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|     "not op_mini all" |     "not op_mini all" | ||||||
|   ], |   ], | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|  |     "browser-nativefs": "0.0.5", | ||||||
|     "i18next": "19.0.3", |     "i18next": "19.0.3", | ||||||
|     "i18next-browser-languagedetector": "4.0.1", |     "i18next-browser-languagedetector": "4.0.1", | ||||||
|     "i18next-xhr-backend": "3.2.2", |     "i18next-xhr-backend": "3.2.2", | ||||||
| @@ -61,5 +62,10 @@ | |||||||
|     "test:app": "react-scripts test --env=jsdom --passWithNoTests", |     "test:app": "react-scripts test --env=jsdom --passWithNoTests", | ||||||
|     "test:code": "npm run prettier -- --list-different" |     "test:code": "npm run prettier -- --list-different" | ||||||
|   }, |   }, | ||||||
|   "version": "1.0.0" |   "version": "1.0.0", | ||||||
|  |   "license": "MIT", | ||||||
|  |   "repository": { | ||||||
|  |     "type": "git", | ||||||
|  |     "url": "https://github.com/excalidraw/excalidraw.git" | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								src/scene/browser-native.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/scene/browser-native.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | declare module "browser-nativefs"; | ||||||
| @@ -6,70 +6,26 @@ import { AppState } from "../types"; | |||||||
| import { ExportType } from "./types"; | import { ExportType } from "./types"; | ||||||
| import { getExportCanvasPreview } from "./getExportCanvasPreview"; | import { getExportCanvasPreview } from "./getExportCanvasPreview"; | ||||||
| import nanoid from "nanoid"; | import nanoid from "nanoid"; | ||||||
|  | import { fileOpenPromise, fileSavePromise } from "browser-nativefs"; | ||||||
|  |  | ||||||
| const LOCAL_STORAGE_KEY = "excalidraw"; | const LOCAL_STORAGE_KEY = "excalidraw"; | ||||||
| const LOCAL_STORAGE_KEY_STATE = "excalidraw-state"; | const LOCAL_STORAGE_KEY_STATE = "excalidraw-state"; | ||||||
| const BACKEND_POST = "https://json.excalidraw.com/api/v1/post/"; | const BACKEND_POST = "https://json.excalidraw.com/api/v1/post/"; | ||||||
| const BACKEND_GET = "https://json.excalidraw.com/api/v1/"; | const BACKEND_GET = "https://json.excalidraw.com/api/v1/"; | ||||||
|  |  | ||||||
|  | let fileOpen: Function; | ||||||
|  | let fileSave: Function; | ||||||
|  |  | ||||||
|  | (async () => { | ||||||
|  |   fileOpen = (await fileOpenPromise).default; | ||||||
|  |   fileSave = (await fileSavePromise).default; | ||||||
|  | })(); | ||||||
|  |  | ||||||
| // TODO: Defined globally, since file handles aren't yet serializable. | // TODO: Defined globally, since file handles aren't yet serializable. | ||||||
| // Once `FileSystemFileHandle` can be serialized, make this | // Once `FileSystemFileHandle` can be serialized, make this | ||||||
| // part of `AppState`. | // part of `AppState`. | ||||||
| (window as any).handle = null; | (window as any).handle = null; | ||||||
|  |  | ||||||
| function saveFile(name: string, data: string) { |  | ||||||
|   // create a temporary <a> elem which we'll use to download the image |  | ||||||
|   const link = document.createElement("a"); |  | ||||||
|   link.setAttribute("download", name); |  | ||||||
|   link.setAttribute("href", data); |  | ||||||
|   link.click(); |  | ||||||
|  |  | ||||||
|   // clean up |  | ||||||
|   link.remove(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function saveFileNative(name: string, data: Blob) { |  | ||||||
|   const options = { |  | ||||||
|     type: "saveFile", |  | ||||||
|     accepts: [ |  | ||||||
|       { |  | ||||||
|         description: `Excalidraw ${ |  | ||||||
|           data.type === "image/png" ? "image" : "file" |  | ||||||
|         }`, |  | ||||||
|         extensions: [data.type.split("/")[1]], |  | ||||||
|         mimeTypes: [data.type] |  | ||||||
|       } |  | ||||||
|     ] |  | ||||||
|   }; |  | ||||||
|   try { |  | ||||||
|     let handle; |  | ||||||
|     if (data.type === "application/json") { |  | ||||||
|       // For Excalidraw files (i.e., `application/json` files): |  | ||||||
|       // If it exists, write back to a previously opened file. |  | ||||||
|       // Else, create a new file. |  | ||||||
|       if ((window as any).handle) { |  | ||||||
|         handle = (window as any).handle; |  | ||||||
|       } else { |  | ||||||
|         handle = await (window as any).chooseFileSystemEntries(options); |  | ||||||
|         (window as any).handle = handle; |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       // For image export files (i.e., `image/png` files): |  | ||||||
|       // Always create a new file. |  | ||||||
|       handle = await (window as any).chooseFileSystemEntries(options); |  | ||||||
|     } |  | ||||||
|     const writer = await handle.createWriter(); |  | ||||||
|     await writer.truncate(0); |  | ||||||
|     await writer.write(0, data, data.type); |  | ||||||
|     await writer.close(); |  | ||||||
|   } catch (err) { |  | ||||||
|     if (err.name !== "AbortError") { |  | ||||||
|       console.error(err.name, err.message); |  | ||||||
|     } |  | ||||||
|     throw err; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface DataState { | interface DataState { | ||||||
|   elements: readonly ExcalidrawElement[]; |   elements: readonly ExcalidrawElement[]; | ||||||
|   appState: AppState; |   appState: AppState; | ||||||
| @@ -94,17 +50,14 @@ export async function saveAsJSON( | |||||||
|   const serialized = serializeAsJSON(elements, appState); |   const serialized = serializeAsJSON(elements, appState); | ||||||
|  |  | ||||||
|   const name = `${appState.name}.json`; |   const name = `${appState.name}.json`; | ||||||
|   if ("chooseFileSystemEntries" in window) { |   await fileSave( | ||||||
|     await saveFileNative( |     new Blob([serialized], { type: "application/json" }), | ||||||
|       name, |     { | ||||||
|       new Blob([serialized], { type: "application/json" }) |       fileName: name, | ||||||
|     ); |       description: "Excalidraw file" | ||||||
|   } else { |     }, | ||||||
|     saveFile( |     (window as any).handle | ||||||
|       name, |   ); | ||||||
|       "data:application/json;charset=utf-8," + encodeURIComponent(serialized) |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| export async function loadFromJSON() { | export async function loadFromJSON() { | ||||||
| @@ -122,57 +75,34 @@ export async function loadFromJSON() { | |||||||
|     return { elements, appState }; |     return { elements, appState }; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   if ("chooseFileSystemEntries" in window) { |   const blob = await fileOpen({ | ||||||
|     try { |     description: "Excalidraw files", | ||||||
|       (window as any).handle = await (window as any).chooseFileSystemEntries({ |     extensions: ["json"], | ||||||
|         accepts: [ |     mimeTypes: ["application/json"] | ||||||
|           { |   }); | ||||||
|             description: "Excalidraw files", |   if (blob.handle) { | ||||||
|             extensions: ["json"], |     (window as any).handle = blob.handle; | ||||||
|             mimeTypes: ["application/json"] |  | ||||||
|           } |  | ||||||
|         ] |  | ||||||
|       }); |  | ||||||
|       const file = await (window as any).handle.getFile(); |  | ||||||
|       const contents = await file.text(); |  | ||||||
|       const { elements, appState } = updateAppState(contents); |  | ||||||
|       return new Promise<DataState>(resolve => { |  | ||||||
|         resolve(restore(elements, appState)); |  | ||||||
|       }); |  | ||||||
|     } catch (err) { |  | ||||||
|       if (err.name !== "AbortError") { |  | ||||||
|         console.error(err.name, err.message); |  | ||||||
|       } |  | ||||||
|       throw err; |  | ||||||
|     } |  | ||||||
|   } else { |  | ||||||
|     const input = document.createElement("input"); |  | ||||||
|     const reader = new FileReader(); |  | ||||||
|     input.type = "file"; |  | ||||||
|     input.accept = ".json"; |  | ||||||
|  |  | ||||||
|     input.onchange = () => { |  | ||||||
|       if (!input.files!.length) { |  | ||||||
|         alert("A file was not selected."); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       reader.readAsText(input.files![0], "utf8"); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     input.click(); |  | ||||||
|  |  | ||||||
|     return new Promise<DataState>(resolve => { |  | ||||||
|       reader.onloadend = () => { |  | ||||||
|         if (reader.readyState === FileReader.DONE) { |  | ||||||
|           const { elements, appState } = updateAppState( |  | ||||||
|             reader.result as string |  | ||||||
|           ); |  | ||||||
|           resolve(restore(elements, appState)); |  | ||||||
|         } |  | ||||||
|       }; |  | ||||||
|     }); |  | ||||||
|   } |   } | ||||||
|  |   let contents; | ||||||
|  |   if ("text" in Blob) { | ||||||
|  |     contents = await blob.text(); | ||||||
|  |   } else { | ||||||
|  |     contents = await (async () => { | ||||||
|  |       return new Promise(resolve => { | ||||||
|  |         const reader = new FileReader(); | ||||||
|  |         reader.readAsText(blob, "utf8"); | ||||||
|  |         reader.onloadend = () => { | ||||||
|  |           if (reader.readyState === FileReader.DONE) { | ||||||
|  |             resolve(reader.result as string); | ||||||
|  |           } | ||||||
|  |         }; | ||||||
|  |       }); | ||||||
|  |     })(); | ||||||
|  |   } | ||||||
|  |   const { elements, appState } = updateAppState(contents); | ||||||
|  |   return new Promise<DataState>(resolve => { | ||||||
|  |     resolve(restore(elements, appState)); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
| export async function exportToBackend( | export async function exportToBackend( | ||||||
| @@ -246,15 +176,14 @@ export async function exportCanvas( | |||||||
|  |  | ||||||
|   if (type === "png") { |   if (type === "png") { | ||||||
|     const fileName = `${name}.png`; |     const fileName = `${name}.png`; | ||||||
|     if ("chooseFileSystemEntries" in window) { |     tempCanvas.toBlob(async (blob: any) => { | ||||||
|       tempCanvas.toBlob(async (blob: any) => { |       if (blob) { | ||||||
|         if (blob) { |         await fileSave(blob, { | ||||||
|           await saveFileNative(fileName, blob); |           fileName: fileName, | ||||||
|         } |           description: "Excalidraw image" | ||||||
|       }); |         }); | ||||||
|     } else { |       } | ||||||
|       saveFile(fileName, tempCanvas.toDataURL("image/png")); |     }); | ||||||
|     } |  | ||||||
|   } else if (type === "clipboard") { |   } else if (type === "clipboard") { | ||||||
|     try { |     try { | ||||||
|       tempCanvas.toBlob(async function(blob: any) { |       tempCanvas.toBlob(async function(blob: any) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Thomas Steiner
					Thomas Steiner