diff --git a/components/src/stores/base.context.ts b/components/src/stores/base.context.ts index aade5262..50bcaf4a 100644 --- a/components/src/stores/base.context.ts +++ b/components/src/stores/base.context.ts @@ -22,7 +22,6 @@ import { export interface BaseContext { fs: FileSystem; - canUpgradeFs: boolean; upgradeFs: (force?: boolean) => void; closeFs: () => void; upgraded?: string; @@ -59,10 +58,9 @@ export function useBaseContext(): BaseContext { }); }, [upgraded, replaceFs]); - const canUpgradeFs = `showDirectoryPicker` in window; const upgradeFs = useCallback( async (force = false) => { - if (!canUpgradeFs || (upgraded && !force)) return; + if (upgraded && !force) return; const handler = await openNand2TetrisDirectory(); const adapter = await createAndStoreLocalAdapterInIndexedDB(handler); replaceFs(adapter); @@ -84,7 +82,6 @@ export function useBaseContext(): BaseContext { status, setStatus, storage: localStorage, - canUpgradeFs, upgradeFs, closeFs, upgraded, @@ -93,7 +90,6 @@ export function useBaseContext(): BaseContext { export const BaseContext = createContext({ fs: new FileSystem(new LocalStorageFileSystemAdapter()), - canUpgradeFs: false, // eslint-disable-next-line @typescript-eslint/no-empty-function upgradeFs() {}, // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/components/src/stores/base/fs.ts b/components/src/stores/base/fs.ts index d0dd87fb..f3a58552 100644 --- a/components/src/stores/base/fs.ts +++ b/components/src/stores/base/fs.ts @@ -4,13 +4,14 @@ import { SEP, Stats, } from "@davidsouther/jiffies/lib/esm/fs.js"; +import { showDirectoryPicker } from "file-system-access"; function dirname(path: string): string { return path.split(SEP).slice(0, -1).join(SEP); } export function openNand2TetrisDirectory(): Promise { - return window.showDirectoryPicker({ + return showDirectoryPicker({ id: "nand2tetris", mode: "readwrite", startIn: "documents", diff --git a/extension/views/hdl/src/index.tsx b/extension/views/hdl/src/index.tsx index 65901a53..d388563a 100644 --- a/extension/views/hdl/src/index.tsx +++ b/extension/views/hdl/src/index.tsx @@ -13,7 +13,6 @@ const baseContext: BaseContext = { new ObjectFileSystemAdapter({ "projects/01/Not.hdl": Not.hdl }) ), upgraded: "true", - canUpgradeFs: false, upgradeFs() {}, closeFs() {}, storage: {}, diff --git a/package-lock.json b/package-lock.json index df5be8df..12bfc30c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,9 @@ "simulator", "web" ], + "dependencies": { + "file-system-access": "^1.0.4" + }, "engines": { "node": ">=16", "npm": ">=7" @@ -10076,6 +10079,28 @@ "pend": "~1.2.0" } }, + "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" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/figures": { "version": "3.2.0", "dev": true, @@ -10118,6 +10143,27 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-system-access": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/file-system-access/-/file-system-access-1.0.4.tgz", + "integrity": "sha512-JDlhH+gJfZu/oExmtN4/6VX+q1etlrbJbR5uzoBa4BzfTRQbEXGFuGIBRk3ZcPocko3WdEclZSu+d/SByjG6Rg==", + "dependencies": { + "@types/wicg-file-system-access": "^2020.9.2", + "fetch-blob": "^3.0.0", + "node-domexception": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "web-streams-polyfill": "^3.1.0" + } + }, + "node_modules/file-system-access/node_modules/@types/wicg-file-system-access": { + "version": "2020.9.8", + "resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.8.tgz", + "integrity": "sha512-ggMz8nOygG7d/stpH40WVaNvBwuyYLnrg5Mbyf6bmsj/8+gb6Ei4ZZ9/4PNpcPNTT8th9Q8sM8wYmWGjMWLX/A==" + }, "node_modules/filelist": { "version": "1.0.4", "license": "Apache-2.0", @@ -16397,6 +16443,24 @@ "version": "4.3.0", "license": "MIT" }, + "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" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "license": "(BSD-3-Clause OR GPL-2.0)", @@ -23501,6 +23565,14 @@ "defaults": "^1.0.3" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "6.1.0", "license": "BSD-2-Clause", diff --git a/package.json b/package.json index 7cb70ff9..980408d1 100644 --- a/package.json +++ b/package.json @@ -48,5 +48,8 @@ "engines": { "node": ">=16", "npm": ">=7" + }, + "dependencies": { + "file-system-access": "^1.0.4" } } diff --git a/web/src/shell/header.tsx b/web/src/shell/header.tsx index c6d6ef28..92d4b431 100644 --- a/web/src/shell/header.tsx +++ b/web/src/shell/header.tsx @@ -67,12 +67,7 @@ const headerButtons: HeaderButton[] = [ headerButtonFromURL(URLs["cpu"], "developer_board"), headerButtonFromURL(URLs["asm"], "list_alt"), headerButtonFromURL(URLs["vm"], "computer"), - // TODO(https://github.com/nand2tetris/web-ide/issues/349) - // reenable when this is resolved for Firefox and safari - // https://caniuse.com/?search=showDirectoryPicker - ...("showDirectoryPicker" in window - ? [headerButtonFromURL(URLs["compiler"], "code")] - : []), + headerButtonFromURL(URLs["compiler"], "code"), headerButtonFromURL(URLs["bitmap"], "grid_on"), headerButtonFromURL(URLs["util"], "function", "Converter Tool"), { diff --git a/web/src/shell/settings.tsx b/web/src/shell/settings.tsx index ae7a2abf..e48d8775 100644 --- a/web/src/shell/settings.tsx +++ b/web/src/shell/settings.tsx @@ -14,7 +14,7 @@ const showUpgradeFs = false; export const Settings = () => { const { toolStates } = useContext(AppContext); - const { fs, setStatus, canUpgradeFs, upgradeFs, closeFs, upgraded } = + const { fs, setStatus, upgradeFs, closeFs, upgraded } = useContext(BaseContext); const { settings, monaco, theme, setTheme, tracking } = useContext(AppContext); @@ -155,7 +155,7 @@ export const Settings = () => { Files
- {showUpgradeFs && canUpgradeFs ? ( + {showUpgradeFs && ( <>