From 49a6cbd5a6c6174c9745b2a22c75a239836d9412 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 14 Feb 2023 17:31:29 -0500 Subject: [PATCH] Use polyfill for open file and directory dialogs --- .../ControlCatalog/Pages/DialogsPage.xaml.cs | 2 +- src/Browser/Avalonia.Browser/AvaloniaView.cs | 5 - .../Avalonia.Browser/Interop/StorageHelper.cs | 10 +- .../Storage/BrowserStorageProvider.cs | 18 ++- .../Avalonia.Browser/webapp/.eslintrc.json | 2 +- src/Browser/Avalonia.Browser/webapp/build.js | 2 +- .../webapp/modules/avalonia/caniuse.ts | 12 +- .../webapp/modules/avalonia/stream.ts | 3 +- .../webapp/modules/storage/storageItem.ts | 50 +++++--- .../webapp/modules/storage/storageProvider.ts | 25 ++-- .../Avalonia.Browser/webapp/package-lock.json | 117 ++++++++++++++++-- .../Avalonia.Browser/webapp/package.json | 4 +- .../Avalonia.Browser/webapp/tsconfig.json | 6 +- 13 files changed, 178 insertions(+), 78 deletions(-) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index 587b34c9fe..61e10729cc 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -281,7 +281,7 @@ namespace ControlCatalog.Pages { ignoreTextChanged = true; lastSelectedDirectory = folder; - currentFolderBox.Text = folder?.Path.LocalPath; + currentFolderBox.Text = folder?.Path is { IsAbsoluteUri: true } abs ? abs.LocalPath : folder?.Path?.ToString(); ignoreTextChanged = false; } async Task SetPickerResult(IReadOnlyCollection? items) diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs index 775100d76b..3bb7260e55 100644 --- a/src/Browser/Avalonia.Browser/AvaloniaView.cs +++ b/src/Browser/Avalonia.Browser/AvaloniaView.cs @@ -381,12 +381,10 @@ namespace Avalonia.Browser { if (_useGL && (_jsGlInfo == null)) { - Console.WriteLine("nothing to render"); return; } if (_canvasSize.Width <= 0 || _canvasSize.Height <= 0 || _dpi <= 0) { - Console.WriteLine("nothing to render"); return; } @@ -459,7 +457,6 @@ namespace Avalonia.Browser void ITextInputMethodImpl.SetClient(ITextInputMethodClient? client) { - Console.WriteLine("Set Client"); if (_client != null) { _client.SurroundingTextChanged -= SurroundingTextChanged; @@ -482,8 +479,6 @@ namespace Avalonia.Browser var surroundingText = _client.SurroundingText; InputHelper.SetSurroundingText(_inputElement, surroundingText.Text, surroundingText.AnchorOffset, surroundingText.CursorOffset); - - Console.WriteLine("Shown, focused and surrounded."); } else { diff --git a/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs b/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs index 902dd03885..11beba6f2c 100644 --- a/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs +++ b/src/Browser/Avalonia.Browser/Interop/StorageHelper.cs @@ -5,14 +5,8 @@ namespace Avalonia.Browser.Interop; internal static partial class StorageHelper { - [JSImport("Caniuse.canShowOpenFilePicker", AvaloniaModule.MainModuleName)] - public static partial bool CanShowOpenFilePicker(); - - [JSImport("Caniuse.canShowSaveFilePicker", AvaloniaModule.MainModuleName)] - public static partial bool CanShowSaveFilePicker(); - - [JSImport("Caniuse.canShowDirectoryPicker", AvaloniaModule.MainModuleName)] - public static partial bool CanShowDirectoryPicker(); + [JSImport("Caniuse.hasNativeFilePicker", AvaloniaModule.MainModuleName)] + public static partial bool HasNativeFilePicker(); [JSImport("StorageProvider.selectFolderDialog", AvaloniaModule.StorageModuleName)] public static partial Task SelectFolderDialog(JSObject? startIn); diff --git a/src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs b/src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs index 08d7664719..7497e82384 100644 --- a/src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs +++ b/src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs @@ -20,9 +20,9 @@ internal class BrowserStorageProvider : IStorageProvider private readonly Lazy _lazyModule = new(() => AvaloniaModule.ImportStorage()); - public bool CanOpen => StorageHelper.CanShowOpenFilePicker(); - public bool CanSave => StorageHelper.CanShowSaveFilePicker(); - public bool CanPickFolder => StorageHelper.CanShowDirectoryPicker(); + public bool CanOpen => true; + public bool CanSave => StorageHelper.HasNativeFilePicker(); + public bool CanPickFolder => true; public async Task> OpenFilePickerAsync(FilePickerOpenOptions options) { @@ -186,10 +186,15 @@ internal abstract class JSStorageItem : IStorageBookmarkItem dateModified: lastModified > 0 ? DateTimeOffset.FromUnixTimeMilliseconds(lastModified.Value) : null); } - public bool CanBookmark => true; + public bool CanBookmark => StorageHelper.HasNativeFilePicker(); public Task SaveBookmarkAsync() { + if (!CanBookmark) + { + return Task.FromResult(null); + } + return StorageHelper.SaveBookmark(FileHandle); } @@ -200,6 +205,11 @@ internal abstract class JSStorageItem : IStorageBookmarkItem public Task ReleaseBookmarkAsync() { + if (!CanBookmark) + { + return Task.CompletedTask; + } + return StorageHelper.DeleteBookmark(FileHandle); } diff --git a/src/Browser/Avalonia.Browser/webapp/.eslintrc.json b/src/Browser/Avalonia.Browser/webapp/.eslintrc.json index 4b7e24987f..f4fb8e37bf 100644 --- a/src/Browser/Avalonia.Browser/webapp/.eslintrc.json +++ b/src/Browser/Avalonia.Browser/webapp/.eslintrc.json @@ -43,5 +43,5 @@ } ] }, - "ignorePatterns": ["types/*"] + "ignorePatterns": ["types/*","node_modules/*"] } diff --git a/src/Browser/Avalonia.Browser/webapp/build.js b/src/Browser/Avalonia.Browser/webapp/build.js index 81f863cac7..c1cbc84709 100644 --- a/src/Browser/Avalonia.Browser/webapp/build.js +++ b/src/Browser/Avalonia.Browser/webapp/build.js @@ -7,7 +7,7 @@ require("esbuild").build({ bundle: true, minify: true, format: "esm", - target: "es2016", + target: "es2018", platform: "browser", sourcemap: "linked", loader: { ".ts": "ts" } diff --git a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/caniuse.ts b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/caniuse.ts index e019f92113..8fdc3a5c01 100644 --- a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/caniuse.ts +++ b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/caniuse.ts @@ -1,14 +1,6 @@ export class Caniuse { - public static canShowOpenFilePicker(): boolean { - return typeof globalThis.showOpenFilePicker !== "undefined"; - } - - public static canShowSaveFilePicker(): boolean { - return typeof globalThis.showSaveFilePicker !== "undefined"; - } - - public static canShowDirectoryPicker(): boolean { - return typeof globalThis.showDirectoryPicker !== "undefined"; + public static hasNativeFilePicker(): boolean { + return "showSaveFilePicker" in globalThis; } public static isMobile(): boolean { diff --git a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/stream.ts b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/stream.ts index 1f2c181edc..7c7769ea36 100644 --- a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/stream.ts +++ b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/stream.ts @@ -1,3 +1,4 @@ +import FileSystemWritableFileStream from "native-file-system-adapter/types/src/FileSystemWritableFileStream"; import { IMemoryView } from "../../types/dotnet"; export class StreamHelper { @@ -17,7 +18,7 @@ export class StreamHelper { const array = new Uint8Array(span.byteLength); span.copyTo(array); - const data: WriteParams = { + const data = { type: "write", data: array }; diff --git a/src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts b/src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts index c6e5254329..8f47e61100 100644 --- a/src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts +++ b/src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts @@ -1,8 +1,10 @@ import { avaloniaDb, fileBookmarksStore } from "./indexedDb"; +import { FileSystemFileHandle, FileSystemDirectoryHandle, FileSystemWritableFileStream } from "native-file-system-adapter"; +import { Caniuse } from "../avalonia"; export class StorageItem { constructor( - public handle?: FileSystemHandle, + public handle?: FileSystemFileHandle | FileSystemDirectoryHandle, private readonly bookmarkId?: string, public wellKnownType?: WellKnownDirectory ) { @@ -27,39 +29,44 @@ export class StorageItem { } public static async openRead(item: StorageItem): Promise { - if (!(item.handle instanceof FileSystemFileHandle)) { + if (!item.handle || item.kind !== "file") { throw new Error("StorageItem is not a file"); } await item.verityPermissions("read"); - const file = await item.handle.getFile(); + const file = await (item.handle as FileSystemFileHandle).getFile(); return file; } public static async openWrite(item: StorageItem): Promise { - if (!(item.handle instanceof FileSystemFileHandle)) { + if (!item.handle || item.kind !== "file") { throw new Error("StorageItem is not a file"); } await item.verityPermissions("readwrite"); - return await item.handle.createWritable({ keepExistingData: true }); + return await (item.handle as FileSystemFileHandle).createWritable({ keepExistingData: true }); } public static async getProperties(item: StorageItem): Promise<{ Size: number; LastModified: number; Type: string } | null> { - const file = item.handle instanceof FileSystemFileHandle && - await item.handle.getFile(); - - if (!file) { + // getFile can fail with an exception depending if we use polyfill with a save file dialog or not. + try { + const file = item.handle instanceof FileSystemFileHandle && + await item.handle.getFile(); + + if (!file) { + return null; + } + + return { + Size: file.size, + LastModified: file.lastModified, + Type: file.type + }; + } catch { return null; } - - return { - Size: file.size, - LastModified: file.lastModified, - Type: file.type - }; } public static async getItems(item: StorageItem): Promise { @@ -74,11 +81,16 @@ export class StorageItem { return new StorageItems(items); } - private async verityPermissions(mode: FileSystemPermissionMode): Promise { + private async verityPermissions(mode: "read" | "readwrite"): Promise { if (!this.handle) { return; } + // If we are using polyfill, let it decide permissions by itself, we can't request anything in this case. + if (!Caniuse.hasNativeFilePicker()) { + return; + } + if (await this.handle.queryPermission({ mode }) === "granted") { return; } @@ -93,7 +105,9 @@ export class StorageItem { if (item.bookmarkId) { return item.bookmarkId; } - if (!item.handle) { + + // Bookmarks are not supported with polyfill. + if (!item.handle || !Caniuse.hasNativeFilePicker()) { return null; } @@ -107,7 +121,7 @@ export class StorageItem { } public static async deleteBookmark(item: StorageItem): Promise { - if (!item.bookmarkId) { + if (!item.bookmarkId || !Caniuse.hasNativeFilePicker()) { return; } diff --git a/src/Browser/Avalonia.Browser/webapp/modules/storage/storageProvider.ts b/src/Browser/Avalonia.Browser/webapp/modules/storage/storageProvider.ts index 8259510ed2..750c38b8ea 100644 --- a/src/Browser/Avalonia.Browser/webapp/modules/storage/storageProvider.ts +++ b/src/Browser/Avalonia.Browser/webapp/modules/storage/storageProvider.ts @@ -1,14 +1,12 @@ import { avaloniaDb, fileBookmarksStore } from "./indexedDb"; import { StorageItem, StorageItems } from "./storageItem"; +import { showOpenFilePicker, showDirectoryPicker, FileSystemFileHandle } from "native-file-system-adapter"; declare global { type WellKnownDirectory = "desktop" | "documents" | "downloads" | "music" | "pictures" | "videos"; - type StartInDirectory = WellKnownDirectory | FileSystemHandle; - interface OpenFilePickerOptions { - startIn?: StartInDirectory; - } - interface SaveFilePickerOptions { - startIn?: StartInDirectory; + interface FilePickerAcceptType { + description?: string | undefined; + accept: Record; } } @@ -16,39 +14,40 @@ export class StorageProvider { public static async selectFolderDialog( startIn: StorageItem | null): Promise { // 'Picker' API doesn't accept "null" as a parameter, so it should be set to undefined. - const options: DirectoryPickerOptions = { + const options = { startIn: (startIn?.wellKnownType ?? startIn?.handle ?? undefined) }; - const handle = await window.showDirectoryPicker(options); + const handle = await showDirectoryPicker(options as any); return new StorageItem(handle); } public static async openFileDialog( startIn: StorageItem | null, multiple: boolean, types: FilePickerAcceptType[] | null, excludeAcceptAllOption: boolean): Promise { - const options: OpenFilePickerOptions = { + const options = { startIn: (startIn?.wellKnownType ?? startIn?.handle ?? undefined), multiple, excludeAcceptAllOption, types: (types ?? undefined) }; - const handles = await window.showOpenFilePicker(options); - return new StorageItems(handles.map((handle: FileSystemHandle) => new StorageItem(handle))); + const handles = await showOpenFilePicker(options); + return new StorageItems(handles.map((handle: FileSystemFileHandle) => new StorageItem(handle))); } public static async saveFileDialog( startIn: StorageItem | null, suggestedName: string | null, types: FilePickerAcceptType[] | null, excludeAcceptAllOption: boolean): Promise { - const options: SaveFilePickerOptions = { + const options = { startIn: (startIn?.wellKnownType ?? startIn?.handle ?? undefined), suggestedName: (suggestedName ?? undefined), excludeAcceptAllOption, types: (types ?? undefined) }; - const handle = await window.showSaveFilePicker(options); + // Always prefer native save file picker, as polyfill solutions are not reliable. + const handle = await (globalThis as any).showSaveFilePicker(options); return new StorageItem(handle); } diff --git a/src/Browser/Avalonia.Browser/webapp/package-lock.json b/src/Browser/Avalonia.Browser/webapp/package-lock.json index 2d875e84db..12757fd7a0 100644 --- a/src/Browser/Avalonia.Browser/webapp/package-lock.json +++ b/src/Browser/Avalonia.Browser/webapp/package-lock.json @@ -5,9 +5,11 @@ "packages": { "": { "name": "avalonia.browser", + "dependencies": { + "native-file-system-adapter": "github:jimmywarting/native-file-system-adapter#d43ad841581c2cc3ce47bbd1e8f11950ebdff027" + }, "devDependencies": { "@types/emscripten": "^1.39.6", - "@types/wicg-file-system-access": "^2020.9.5", "@typescript-eslint/eslint-plugin": "^5.38.1", "esbuild": "^0.15.7", "eslint": "^8.24.0", @@ -170,12 +172,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/wicg-file-system-access": { - "version": "2020.9.5", - "resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.5.tgz", - "integrity": "sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.38.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.1.tgz", @@ -1573,6 +1569,29 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "optional": true, + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -2289,6 +2308,27 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/native-file-system-adapter": { + "version": "3.0.0", + "resolved": "git+ssh://git@github.com/jimmywarting/native-file-system-adapter.git#d43ad841581c2cc3ce47bbd1e8f11950ebdff027", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.8.0" + }, + "optionalDependencies": { + "fetch-blob": "^3.2.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2301,6 +2341,25 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "optional": true, + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3196,6 +3255,15 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "optional": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3366,12 +3434,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "@types/wicg-file-system-access": { - "version": "2020.9.5", - "resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.5.tgz", - "integrity": "sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA==", - "dev": true - }, "@typescript-eslint/eslint-plugin": { "version": "5.38.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.1.tgz", @@ -4275,6 +4337,16 @@ "reusify": "^1.0.4" } }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "optional": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4796,6 +4868,13 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "native-file-system-adapter": { + "version": "git+ssh://git@github.com/jimmywarting/native-file-system-adapter.git#d43ad841581c2cc3ce47bbd1e8f11950ebdff027", + "from": "native-file-system-adapter@github:jimmywarting/native-file-system-adapter#d43ad841581c2cc3ce47bbd1e8f11950ebdff027", + "requires": { + "fetch-blob": "^3.2.0" + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4808,6 +4887,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "optional": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -5446,6 +5531,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "optional": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/src/Browser/Avalonia.Browser/webapp/package.json b/src/Browser/Avalonia.Browser/webapp/package.json index 05a3976ccc..20dd8d4e6a 100644 --- a/src/Browser/Avalonia.Browser/webapp/package.json +++ b/src/Browser/Avalonia.Browser/webapp/package.json @@ -8,7 +8,6 @@ }, "devDependencies": { "@types/emscripten": "^1.39.6", - "@types/wicg-file-system-access": "^2020.9.5", "@typescript-eslint/eslint-plugin": "^5.38.1", "esbuild": "^0.15.7", "eslint": "^8.24.0", @@ -18,5 +17,8 @@ "eslint-plugin-promise": "^6.0.1", "npm-run-all": "^4.1.5", "typescript": "^4.8.3" + }, + "dependencies": { + "native-file-system-adapter": "github:jimmywarting/native-file-system-adapter#d43ad841581c2cc3ce47bbd1e8f11950ebdff027" } } diff --git a/src/Browser/Avalonia.Browser/webapp/tsconfig.json b/src/Browser/Avalonia.Browser/webapp/tsconfig.json index ad0e727150..1450ce4c57 100644 --- a/src/Browser/Avalonia.Browser/webapp/tsconfig.json +++ b/src/Browser/Avalonia.Browser/webapp/tsconfig.json @@ -1,14 +1,16 @@ { "compilerOptions": { - "target": "es2016", + "target": "es2018", "module": "es2020", "strict": true, "sourceMap": true, "noEmitOnError": true, + "moduleResolution": "node", + "skipLibCheck": true, "isolatedModules": true, // we need it for esbuild "lib": [ "dom", - "es2016", + "es2018", "esnext.asynciterable" ] },