diff --git a/package-lock.json b/package-lock.json index 42db2985..3146b643 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4686,9 +4686,9 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browser-nativefs": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/browser-nativefs/-/browser-nativefs-0.10.3.tgz", - "integrity": "sha512-WGcoR1aR+bxLlilaJ9fIzVOgSC4MaV+6phCTDGXV1sm+RElFuQFnJXR4BebBf2wEnjCsmGmTDNDTBE5KvVm2UQ==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/browser-nativefs/-/browser-nativefs-0.11.0.tgz", + "integrity": "sha512-JsCiw8DeZ5gB59i81e0O0pFSDK124hRoaYR7teNnuvIFVZRXa7vYJStwZxZAJS1tlmVdu5uuC6eIARskyG/IuQ==" }, "browser-process-hrtime": { "version": "1.0.0", diff --git a/package.json b/package.json index cf340f0c..e9640dbb 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@types/react": "16.9.52", "@types/react-dom": "16.9.8", "@types/socket.io-client": "1.4.34", - "browser-nativefs": "0.10.3", + "browser-nativefs": "0.11.0", "firebase": "7.23.0", "i18next-browser-languagedetector": "6.0.1", "lodash.throttle": "4.1.1", diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index ab08f1ae..231b0453 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -59,8 +59,6 @@ export const actionClearCanvas = register({ showAriaLabel={useIsMobile()} onClick={() => { if (window.confirm(t("alerts.clearReset"))) { - // TODO: Make this part of `AppState`. - (window as any).handle = null; updateData(null); } }} diff --git a/src/actions/actionExport.tsx b/src/actions/actionExport.tsx index 6af01e87..21c9d1f8 100644 --- a/src/actions/actionExport.tsx +++ b/src/actions/actionExport.tsx @@ -85,12 +85,16 @@ export const actionChangeShouldAddWatermark = register({ export const actionSaveScene = register({ name: "saveScene", - perform: (elements, appState, value) => { - // TODO: Make this part of `AppState`. - saveAsJSON(elements, appState, (window as any).handle) - .catch(muteFSAbortError) - .catch((error) => console.error(error)); - return { commitToHistory: false }; + perform: async (elements, appState, value) => { + try { + const { fileHandle } = await saveAsJSON(elements, appState); + return { commitToHistory: false, appState: { ...appState, fileHandle } }; + } catch (error) { + if (error?.name !== "AbortError") { + console.error(error); + } + return { commitToHistory: false }; + } }, keyTest: (event) => { return event.key === "s" && event[KEYS.CTRL_OR_CMD] && !event.shiftKey; @@ -109,11 +113,19 @@ export const actionSaveScene = register({ export const actionSaveAsScene = register({ name: "saveAsScene", - perform: (elements, appState, value) => { - saveAsJSON(elements, appState, null) - .catch(muteFSAbortError) - .catch((error) => console.error(error)); - return { commitToHistory: false }; + perform: async (elements, appState, value) => { + try { + const { fileHandle } = await saveAsJSON(elements, { + ...appState, + fileHandle: null, + }); + return { commitToHistory: false, appState: { ...appState, fileHandle } }; + } catch (error) { + if (error?.name !== "AbortError") { + console.error(error); + } + return { commitToHistory: false }; + } }, keyTest: (event) => { return event.key === "s" && event.shiftKey && event[KEYS.CTRL_OR_CMD]; diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx index 32b1eae5..8f6c5322 100644 --- a/src/actions/manager.tsx +++ b/src/actions/manager.tsx @@ -5,6 +5,7 @@ import { UpdaterFn, ActionFilterFn, ActionName, + ActionResult, } from "./types"; import { ExcalidrawElement } from "../element/types"; import { AppState } from "../types"; @@ -13,7 +14,7 @@ import { t } from "../i18n"; export class ActionManager implements ActionsManagerInterface { actions = {} as ActionsManagerInterface["actions"]; - updater: UpdaterFn; + updater: (actionResult: ActionResult | Promise) => void; getAppState: () => Readonly; @@ -24,7 +25,15 @@ export class ActionManager implements ActionsManagerInterface { getAppState: () => AppState, getElementsIncludingDeleted: () => readonly ExcalidrawElement[], ) { - this.updater = updater; + this.updater = (actionResult) => { + if (actionResult && "then" in actionResult) { + actionResult.then((actionResult) => { + return updater(actionResult); + }); + } else { + return updater(actionResult); + } + }; this.getAppState = getAppState; this.getElementsIncludingDeleted = getElementsIncludingDeleted; } diff --git a/src/actions/types.ts b/src/actions/types.ts index aa944eef..44ab6aa5 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -16,9 +16,9 @@ type ActionFn = ( elements: readonly ExcalidrawElement[], appState: Readonly, formData: any, -) => ActionResult; +) => ActionResult | Promise; -export type UpdaterFn = (res: ActionResult, commitToHistory?: boolean) => void; +export type UpdaterFn = (res: ActionResult) => void; export type ActionFilterFn = (action: Action) => void; export type ActionName = diff --git a/src/appState.ts b/src/appState.ts index 54843f17..3c65ba81 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -69,6 +69,7 @@ export const getDefaultAppState = (): Omit< width: window.innerWidth, height: window.innerHeight, isLibraryOpen: false, + fileHandle: null, }; }; @@ -145,6 +146,7 @@ const APP_STATE_STORAGE_CONF = (< zoom: { browser: true, export: false }, offsetTop: { browser: false, export: false }, offsetLeft: { browser: false, export: false }, + fileHandle: { browser: false, export: false }, }); const _clearAppStateForStorage = ( diff --git a/src/clipboard.ts b/src/clipboard.ts index 87522ecf..e9bff75b 100644 --- a/src/clipboard.ts +++ b/src/clipboard.ts @@ -160,7 +160,7 @@ export const parseClipboard = async ( export const copyCanvasToClipboardAsPng = async (canvas: HTMLCanvasElement) => new Promise((resolve, reject) => { try { - canvas.toBlob(async (blob: any) => { + canvas.toBlob(async (blob) => { try { await navigator.clipboard.write([ new window.ClipboardItem({ "image/png": blob }), diff --git a/src/components/App.tsx b/src/components/App.tsx index 024296e9..7eba91f4 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -558,7 +558,7 @@ class App extends React.Component { return; } const fileHandle = launchParams.files[0]; - const blob = await fileHandle.getFile(); + const blob: Blob = await fileHandle.getFile(); blob.handle = fileHandle; loadFromBlob(blob, this.state) .then(({ elements, appState }) => @@ -3845,7 +3845,7 @@ class App extends React.Component { // but can be safely ignored on older releases. const item = event.dataTransfer.items[0]; // TODO: Make this part of `AppState`. - (window as any).handle = await (item as any).getAsFileSystemHandle(); + (file as any).handle = await (item as any).getAsFileSystemHandle(); } catch (error) { console.warn(error.name, error.message); } diff --git a/src/data/blob.ts b/src/data/blob.ts index 5f95deec..8b6305d9 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -4,6 +4,7 @@ import { t } from "../i18n"; import { AppState } from "../types"; import { LibraryData, ImportedDataState } from "./types"; import { calculateScrollCenter } from "../scene"; +import { MIME_TYPES } from "../constants"; export const parseFileContents = async (blob: Blob | File) => { let contents: string; @@ -53,16 +54,22 @@ export const parseFileContents = async (blob: Blob | File) => { return contents; }; +const getMimeType = (blob: Blob): string => { + if (blob.type) { + return blob.type; + } + const name = blob.name || ""; + if (/\.(excalidraw|json)$/.test(name)) { + return "application/json"; + } + return ""; +}; + export const loadFromBlob = async ( - blob: any, + blob: Blob, /** @see restore.localAppState */ localAppState: AppState | null, ) => { - if (blob.handle) { - // TODO: Make this part of `AppState`. - (window as any).handle = blob.handle; - } - const contents = await parseFileContents(blob); try { const data: ImportedDataState = JSON.parse(contents); @@ -74,6 +81,13 @@ export const loadFromBlob = async ( elements: data.elements, appState: { appearance: localAppState?.appearance, + fileHandle: + blob.handle && + ["application/json", MIME_TYPES.excalidraw].includes( + getMimeType(blob), + ) + ? blob.handle + : null, ...cleanAppStateForExport(data.appState || {}), ...(localAppState ? calculateScrollCenter(data.elements || [], localAppState, null) diff --git a/src/data/index.ts b/src/data/index.ts index 35018863..f0e1d8e6 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -66,9 +66,6 @@ export type SocketUpdateDataIncoming = type: "INVALID_RESPONSE"; }; -// TODO: Make this part of `AppState`. -(window as any).handle = null; - const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2); const generateRandomID = async () => { diff --git a/src/data/json.ts b/src/data/json.ts index 39735741..df3cead8 100644 --- a/src/data/json.ts +++ b/src/data/json.ts @@ -27,23 +27,23 @@ export const serializeAsJSON = ( export const saveAsJSON = async ( elements: readonly ExcalidrawElement[], appState: AppState, - fileHandle: any, ) => { const serialized = serializeAsJSON(elements, appState); const blob = new Blob([serialized], { type: "application/json", }); - const name = `${appState.name}.excalidraw`; - // TODO: Make this part of `AppState`. - (window as any).handle = await fileSave( + + const fileHandle = await fileSave( blob, { - fileName: name, + fileName: appState.name, description: "Excalidraw file", extensions: [".excalidraw"], }, - fileHandle || null, + appState.fileHandle, ); + + return { fileHandle }; }; export const loadFromJSON = async (localAppState: AppState) => { diff --git a/src/data/library.ts b/src/data/library.ts index 832e7d76..b813ef7c 100644 --- a/src/data/library.ts +++ b/src/data/library.ts @@ -4,7 +4,7 @@ import { loadLibrary, saveLibrary } from "./localStorage"; export class Library { /** imports library (currently merges, removing duplicates) */ - static async importLibrary(blob: any) { + static async importLibrary(blob: Blob) { const libraryFile = await loadLibraryFromBlob(blob); if (!libraryFile || !libraryFile.library) { return; diff --git a/src/global.d.ts b/src/global.d.ts index 00cc0208..f533e976 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -76,3 +76,10 @@ type CallableType any> = ( type ForwardRef = Parameters< CallableType> >[1]; + +// --------------------------------------------------------------------------— + +interface Blob { + handle?: import("browser-nativefs").FileSystemHandle; + name?: string; +} diff --git a/src/scene/browser-native.d.ts b/src/scene/browser-native.d.ts deleted file mode 100644 index 59630fc0..00000000 --- a/src/scene/browser-native.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "browser-nativefs"; diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index d6c535ca..fc8bb1a6 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -28,6 +28,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -475,6 +476,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -928,6 +930,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": false, @@ -1690,6 +1693,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -1880,6 +1884,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -2324,6 +2329,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -2563,6 +2569,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -2713,6 +2720,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -3176,6 +3184,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -3470,6 +3479,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -3660,6 +3670,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -3890,6 +3901,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -4128,6 +4140,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -4497,6 +4510,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -4778,6 +4792,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -5071,6 +5086,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -5265,6 +5281,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -5415,6 +5432,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -5854,6 +5872,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -6158,6 +6177,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -8124,6 +8144,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -8472,6 +8493,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -8713,6 +8735,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -8952,6 +8975,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -9253,6 +9277,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -9403,6 +9428,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -9553,6 +9579,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -9703,6 +9730,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -9879,6 +9907,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10055,6 +10084,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10231,6 +10261,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10407,6 +10438,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10557,6 +10589,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10707,6 +10740,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -10883,6 +10917,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -11033,6 +11068,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -11209,6 +11245,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -11911,6 +11948,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -12150,6 +12188,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -12238,6 +12277,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -12324,6 +12364,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -13202,6 +13243,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -13639,6 +13681,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -13989,6 +14032,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -14256,6 +14300,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -14444,6 +14489,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -15269,6 +15315,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -15991,6 +16038,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -16614,6 +16662,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -17142,6 +17191,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -17624,6 +17674,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -18017,6 +18068,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -18325,6 +18377,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -18552,6 +18605,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -19430,6 +19484,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -20203,6 +20258,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -20875,6 +20931,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -21450,6 +21507,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -21600,6 +21658,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -21894,6 +21953,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -22188,6 +22248,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -22338,6 +22399,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -22520,6 +22582,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -22755,6 +22818,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -23065,6 +23129,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -23890,6 +23955,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -24184,6 +24250,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -24478,6 +24545,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -24843,6 +24911,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -24996,6 +25065,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -25303,6 +25373,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -25544,6 +25615,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -25857,6 +25929,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -25943,6 +26016,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -26093,6 +26167,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -26900,6 +26975,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -26986,6 +27062,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -27724,6 +27801,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -28115,6 +28193,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -28374,6 +28453,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -28462,6 +28542,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -28940,6 +29021,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, @@ -29026,6 +29108,7 @@ Object { "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, + "fileHandle": null, "gridSize": null, "height": 768, "isBindingEnabled": true, diff --git a/src/types.ts b/src/types.ts index 52dc2c54..2578829d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,6 +96,7 @@ export type AppState = { offsetLeft: number; isLibraryOpen: boolean; + fileHandle: import("browser-nativefs").FileSystemHandle | null; }; export type PointerCoords = Readonly<{