From c8458fce16bc4b5e86582dea756ec1956d04a762 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 1 Jul 2023 16:21:53 +1000 Subject: [PATCH] Update to Svelte 4, and update most other JS deps (#2565) * eslint-plugin-svelte3 -> eslint-plugin-svelte The former is deprecated, and blocks an update to Svelte 4. Also drop unused svelte2tsx and types package. * Drop unused symbols code for now It may be added back in the future, but for now dropping it will save 200k from our editor bundle. * Remove sass and caniuse-lite pins The latter no longer seems to be required. The former was added to suppress deprecation warnings when compiling the old bootstrap version we have pinned. Those are hidden by the build tool now (though we really need to address them at one point: https://github.com/ankitects/anki/issues/1385) Also removed unused files section. * Prevent proto compile from looking in node_modules/@types/sass When deps are updated, tsc aborts because @types/sass is a dummy package without an index.d.ts file. * Filter Svelte warnings out of ./run * Update to latest Bootstrap This fixes the deprecation warnings we were getting during build: bootstrap doesn't accept runtime CSS variables being set in Sass, as it wants to apply transforms to the colors. Closes #1385 * Start port to Svelte 4 - svelte-check tests have a bunch of failures; ./run works - Svelte no longer exposes internals, so we can't use create_in_transition - Also update esbuild and related components like esbuild-svelte * Fix test failures Had to add some more a11y warning ignores - have added https://github.com/ankitects/anki/issues/2564 to address that in the future. * Remove some dependency pins + Remove sass, we don't need it directly * Bump remaining JS deps that have a current semver * Upgrade dprint/license-checker/marked The new helper method avoids marked printing deprecation warnings to the console. Also remove unused lodash/long types, and move lodahs-es to devdeps * Upgrade eslint and fluent packages * Update @floating-ui/dom The only dependencies remaining are currently blocked: - Jest 29 gives some error about require vs import; may not be worth investigating if we switch to Deno for the tests - CodeMirror 6 is a big API change and will need work. * Roll dprint back to an earlier version GitHub dropped support for Ubuntu 18 runners, causing dprint's artifacts to require a glibc version greater than what Anki CI currently has. --- .eslintrc.js | 22 +- build/ninja_gen/src/node.rs | 6 +- package.json | 65 +- qt/aqt/editor.py | 3 - qt/aqt/webview.py | 12 +- sass/base.scss | 8 +- ts/bundle_svelte.mjs | 2 + ts/change-notetype/ChangeNotetypePage.svelte | 6 +- ts/components/Popover.svelte | 4 - ts/components/ScrollArea.svelte | 2 - ts/components/Select.svelte | 8 +- ts/components/Switch.svelte | 1 + ts/components/WithFloating.svelte | 4 +- ts/components/WithOverlay.svelte | 4 +- ts/deck-options/HelpSection.svelte | 8 +- ts/editable/ContentEditable.svelte | 2 + ts/editor/NoteEditor.svelte | 11 - ts/editor/StickyBadge.svelte | 4 +- ts/editor/image-overlay/ImageOverlay.svelte | 5 +- .../mathjax-overlay/MathjaxOverlay.svelte | 3 +- ts/editor/rich-text-input/CustomStyles.svelte | 11 +- ts/editor/rich-text-input/StyleLink.svelte | 6 +- ts/editor/rich-text-input/StyleTag.svelte | 6 +- ts/editor/symbols-overlay/SymbolsEntry.svelte | 58 - .../symbols-overlay/SymbolsOverlay.svelte | 421 -- .../symbols-overlay/character-entities.ts | 33 - ts/editor/symbols-overlay/gemoji.ts | 18 - ts/editor/symbols-overlay/index.ts | 6 - ts/editor/symbols-overlay/symbols-table.ts | 54 - ts/editor/symbols-overlay/symbols-types.d.ts | 27 - ts/editor/tsconfig.json | 1 - ts/graphs/GraphsPage.svelte | 6 +- ts/graphs/index.ts | 10 +- ts/jest.config.js | 2 +- ts/lib/helpers.ts | 6 + ts/lib/nightmode.ts | 1 + ts/licenses.json | 274 +- ts/sveltelib/dynamic-slotting.ts | 7 +- ts/sveltelib/dynamicComponent.ts | 11 +- ts/sveltelib/export-runtime.ts | 4 +- ts/tag-editor/TagInput.svelte | 2 +- .../tag-options-button/TagAddButton.svelte | 2 +- yarn.lock | 4277 +++++++++-------- 43 files changed, 2564 insertions(+), 2859 deletions(-) delete mode 100644 ts/editor/symbols-overlay/SymbolsEntry.svelte delete mode 100644 ts/editor/symbols-overlay/SymbolsOverlay.svelte delete mode 100644 ts/editor/symbols-overlay/character-entities.ts delete mode 100644 ts/editor/symbols-overlay/gemoji.ts delete mode 100644 ts/editor/symbols-overlay/index.ts delete mode 100644 ts/editor/symbols-overlay/symbols-table.ts delete mode 100644 ts/editor/symbols-overlay/symbols-types.d.ts diff --git a/.eslintrc.js b/.eslintrc.js index fb654fa2a..e7dd15563 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,9 +1,11 @@ module.exports = { root: true, - extends: ["eslint:recommended", "plugin:compat/recommended"], + extends: ["eslint:recommended", "plugin:compat/recommended", "plugin:svelte/recommended"], parser: "@typescript-eslint/parser", + parserOptions: { + extraFileExtensions: [".svelte"], + }, plugins: [ - "svelte3", "import", "simple-import-sort", "@typescript-eslint", @@ -36,11 +38,14 @@ module.exports = { }, }, { - files: "**/*.svelte", - processor: "svelte3/svelte3", + files: ["*.svelte"], + parser: "svelte-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + }, rules: { - "no-redeclare": "off", - "no-global-assign": "off", + "svelte/no-at-html-tags": "off", + "svelte/valid-compile": ["error", { "ignoreWarnings": true }], }, }, ], @@ -49,9 +54,6 @@ module.exports = { globals: { globalThis: false, NodeListOf: false, - }, - settings: { - "svelte3/typescript": () => require("typescript"), - "svelte3/ignore-warnings": (warning) => warning.code.startsWith("a11y-"), + $$Generic: "readonly", }, }; diff --git a/build/ninja_gen/src/node.rs b/build/ninja_gen/src/node.rs index 0644cb507..9d0c4fa10 100644 --- a/build/ninja_gen/src/node.rs +++ b/build/ninja_gen/src/node.rs @@ -215,7 +215,7 @@ pub struct SvelteCheck { impl BuildAction for SvelteCheck { fn command(&self) -> &str { "$svelte-check --tsconfig $tsconfig $ - --fail-on-warnings --threshold warning --use-new-transformation $ + --fail-on-warnings --threshold warning $ --compiler-warnings $compiler_warnings" } @@ -229,6 +229,8 @@ impl BuildAction for SvelteCheck { [ "a11y-click-events-have-key-events", "a11y-no-noninteractive-tabindex", + "a11y-no-static-element-interactions", + "a11y-no-noninteractive-element-interactions", ] .iter() .map(|warning| format!("{}$:ignore", warning)) @@ -423,7 +425,7 @@ pub struct CompileTypescript<'a> { impl BuildAction for CompileTypescript<'_> { fn command(&self) -> &str { - "$tsc $in --outDir $out_dir -d --skipLibCheck" + "$tsc $in --outDir $out_dir -d --skipLibCheck --types node" } fn files(&mut self, build: &mut impl build::FilesHandle) { diff --git a/package.json b/package.json index 0151fb9f9..d8690858d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "description": "Anki JS support files", "devDependencies": { "@bufbuild/protoc-gen-es": "^1.2.1", - "@pyoner/svelte-types": "^3.4.4-2", "@sqltools/formatter": "^1.2.2", "@types/bootstrap": "^5.0.12", "@types/codemirror": "^5.60.0", @@ -16,76 +15,64 @@ "@types/jest": "^27.0.2", "@types/jquery": "^3.5.0", "@types/jqueryui": "^1.12.13", - "@types/lodash": "^4.14.162", - "@types/long": "^4.0.1", + "@types/lodash-es": "^4.17.4", + "@types/marked": "^5.0.0", "@types/node": "^16.10.2", - "@typescript-eslint/eslint-plugin": "^4.22.0", - "@typescript-eslint/parser": "^4.22.0", + "@typescript-eslint/eslint-plugin": "^5.60.1", + "@typescript-eslint/parser": "^5.60.1", "caniuse-lite": "^1.0.30001431", "cross-env": "^7.0.2", "diff": "^5.0.0", - "dprint": "^0.32.2", - "esbuild": "^0.15.13", - "esbuild-sass-plugin": "2", - "esbuild-svelte": "^0.7.1", - "eslint": "^7.24.0", - "eslint-plugin-compat": "^3.13.0", + "dprint": "=0.35.3", + "esbuild": "^0.18.10", + "esbuild-sass-plugin": "^2", + "esbuild-svelte": "^0.7.4", + "eslint": "^8.44.0", + "eslint-plugin-compat": "^4.1.4", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-simple-import-sort": "^7.0.0", - "eslint-plugin-svelte3": "^3.4.0", + "eslint-plugin-simple-import-sort": "^10.0.0", + "eslint-plugin-svelte": "^2", "jest-cli": "^28.0.0-alpha.5", "jest-environment-jsdom": "^28.0.0-alpha.5", - "license-checker-rseidelsohn": "^2.1.1", - "prettier": "2.4.1", - "prettier-plugin-svelte": "2.6.0", - "sass": "1.43.5", - "svelte": "^3.25.0", - "svelte-check": "^2.2.6", - "svelte-preprocess": "^5.0.3", + "license-checker-rseidelsohn": "^4.2.6", + "prettier": "^2.4.1", + "prettier-plugin-svelte": "^2.10.1", + "svelte": "^4.0.1", + "svelte-check": "^3.4.4", + "svelte-preprocess": "^5.0.4", "svelte-preprocess-esbuild": "^3.0.1", - "svelte2tsx": "^0.4.6", "tslib": "^2.0.3", "tsx": "^3.12.0", "typescript": "^5.0.4" }, "dependencies": { "@bufbuild/protobuf": "^1.2.1", - "@floating-ui/dom": "^0.3.0", - "@fluent/bundle": "^0.17.0", + "@floating-ui/dom": "^1.4.3", + "@fluent/bundle": "^0.18.0", "@mdi/svg": "^7.0.96", - "@popperjs/core": "^2.9.2", - "@types/lodash-es": "^4.17.4", - "@types/marked": "^4.0.1", - "bootstrap": "=5.0.2", - "bootstrap-icons": "^1.4.0", - "character-entities": "^2.0.2", + "@popperjs/core": "^2.11.8", + "bootstrap": "^5.3.0", + "bootstrap-icons": "^1.10.5", "codemirror": "^5.63.1", "css-browser-selector": "^0.6.5", "d3": "^7.0.0", "fabric": "^5.3.0", - "fuse.js": "^6.6.2", - "gemoji": "^7.1.0", - "intl-pluralrules": "^1.2.2", + "intl-pluralrules": "^2.0.0", "jquery": "^3.5.1", "jquery-ui-dist": "^1.12.1", "lodash-es": "^4.17.21", - "marked": "^4.0.0", + "marked": "^5.1.0", "mathjax": "^3.1.2", "panzoom": "^9.4.3" }, "resolutions": { - "sass": "=1.45.0", - "caniuse-lite": "^1.0.30001431", "canvas": "npm:empty-npm-package" }, - "files": [ - "dist/*" - ], "browserslist": [ "defaults", "not op_mini all", "not < 1%", "Chrome 77", - "iOS 13.4" + "iOS 14.5" ] } diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 3eed03c64..a232a8ced 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -554,9 +554,6 @@ require("anki/ui").loaded.then(() => require("anki/NoteEditor").instances[0].too sticky = [field["sticky"] for field in self.note.note_type()["flds"]] js += " setSticky(%s);" % json.dumps(sticky) - if os.getenv("ANKI_EDITOR_INSERT_SYMBOLS"): - js += " setInsertSymbolsEnabled();" - js = gui_hooks.editor_will_load_note(js, self.note, self) self.web.evalWithCallback( f'require("anki/ui").loaded.then(() => {{ {js} }})', oncallback diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 0a69cda6b..203cc3d2b 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -546,8 +546,10 @@ html {{ {font} }} if theme_manager.night_mode: doc_class = "night-mode" + bs_theme = "dark" else: doc_class = "" + bs_theme = "light" if is_rtl(anki.lang.current_lang): lang_dir = "rtl" @@ -556,7 +558,7 @@ html {{ {font} }} html = f""" - + {self.title} {head} @@ -760,15 +762,17 @@ html {{ {font} }} self.eval( f""" (function() {{ - const doc = document.documentElement.classList; + const doc = document.documentElement; const body = document.body.classList; if ({1 if theme_manager.night_mode else 0}) {{ - doc.add("night-mode"); + doc.dataset.bsTheme = "dark"; + doc.classList.add("night-mode"); body.add("night_mode"); body.add("nightMode"); {"body.add('macos-dark-mode');" if theme_manager.macos_dark_mode() else ""} }} else {{ - doc.remove("night-mode"); + doc.dataset.bsTheme = "light"; + doc.classList.remove("night-mode"); body.remove("night_mode"); body.remove("nightMode"); body.remove("macos-dark-mode"); diff --git a/sass/base.scss b/sass/base.scss index dcdba3219..69600add3 100644 --- a/sass/base.scss +++ b/sass/base.scss @@ -3,10 +3,10 @@ @use "button-mixins" as button; @use "sass/scrollbar"; -$body-color: color(fg); -$body-bg: color(canvas); - -$link-hover-color: color(fg-link); +$body-color: palette(darkgray, 9); +$body-color-dark: palette(lightgray, 0); +$body-bg: palette(lightgray, 2); +$body-bg-dark: palette(darkgray, 5); $link-hover-decoration: none; $utilities: ( diff --git a/ts/bundle_svelte.mjs b/ts/bundle_svelte.mjs index 61f67acf7..ffdc7591f 100644 --- a/ts/bundle_svelte.mjs +++ b/ts/bundle_svelte.mjs @@ -56,6 +56,8 @@ build({ sveltePlugin({ compilerOptions: { css: inlineCss }, preprocess: sveltePlugins, + // let us focus on errors; we can see the warnings with svelte-check + filterWarnings: (_warning) => false, }), ], target, diff --git a/ts/change-notetype/ChangeNotetypePage.svelte b/ts/change-notetype/ChangeNotetypePage.svelte index 7dc70500c..9dda5af96 100644 --- a/ts/change-notetype/ChangeNotetypePage.svelte +++ b/ts/change-notetype/ChangeNotetypePage.svelte @@ -4,12 +4,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html --> { const { reason, originalEvent } = detail; @@ -264,7 +263,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } }} > - + - + { if (shrinkingDisabled) { diff --git a/ts/editor/mathjax-overlay/MathjaxOverlay.svelte b/ts/editor/mathjax-overlay/MathjaxOverlay.svelte index ec5fd5121..546196936 100644 --- a/ts/editor/mathjax-overlay/MathjaxOverlay.svelte +++ b/ts/editor/mathjax-overlay/MathjaxOverlay.svelte @@ -211,10 +211,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html offset={20} keepOnKeyup portalTarget={document.body} - let:position={positionFloating} on:close={resetHandle} > - + void; + deregister: (id: string) => void; + } + + export function getCustomStylesContext(): CustomStylesContext { + return getContext(customStylesKey); + } + export const customStylesKey = Symbol("customStyles"); - -
-
- {#if containsHTML} - {@html symbol} - {:else} - {symbol} - {/if} -
- -
- {#each names as name} - - - - {/each} -
-
- - diff --git a/ts/editor/symbols-overlay/SymbolsOverlay.svelte b/ts/editor/symbols-overlay/SymbolsOverlay.svelte deleted file mode 100644 index f224c854c..000000000 --- a/ts/editor/symbols-overlay/SymbolsOverlay.svelte +++ /dev/null @@ -1,421 +0,0 @@ - - - -
- {#if referenceRange} - - -
- {#each foundSymbols as found, index (found.symbol)} - replaceTextOnDemand(found)} - > - - {symbolsDelimiter}{symbolName}{symbolsDelimiter} - - - {/each} -
-
-
- {/if} -
- - diff --git a/ts/editor/symbols-overlay/character-entities.ts b/ts/editor/symbols-overlay/character-entities.ts deleted file mode 100644 index 51c3f3b75..000000000 --- a/ts/editor/symbols-overlay/character-entities.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -import { characterEntities } from "character-entities"; - -import type { SymbolsTable } from "./symbols-types"; - -// Not all characters work well in the editor field -delete characterEntities["Tab"]; - -// A single character entity can be present under different names -// So we change the mapping to symbol => name[] -const characterTable: Record = {}; - -for (const [name, character] of Object.entries(characterEntities)) { - if (character in characterTable) { - characterTable[character].push(name); - } else { - characterTable[character] = [name]; - } -} - -const characterSymbolsTable: SymbolsTable = []; - -for (const [character, names] of Object.entries(characterTable)) { - characterSymbolsTable.push({ - symbol: character, - names, - tags: [], - }); -} - -export default characterSymbolsTable; diff --git a/ts/editor/symbols-overlay/gemoji.ts b/ts/editor/symbols-overlay/gemoji.ts deleted file mode 100644 index de7db4b11..000000000 --- a/ts/editor/symbols-overlay/gemoji.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -import { gemoji } from "gemoji"; - -import type { SymbolsTable } from "./symbols-types"; - -const gemojiSymbolsTable: SymbolsTable = []; - -for (const { emoji, names, tags } of gemoji) { - gemojiSymbolsTable.push({ - symbol: emoji, - names, - tags, - }); -} - -export default gemojiSymbolsTable; diff --git a/ts/editor/symbols-overlay/index.ts b/ts/editor/symbols-overlay/index.ts deleted file mode 100644 index 069458e6f..000000000 --- a/ts/editor/symbols-overlay/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -import SymbolsOverlay from "./SymbolsOverlay.svelte"; - -export default SymbolsOverlay; diff --git a/ts/editor/symbols-overlay/symbols-table.ts b/ts/editor/symbols-overlay/symbols-table.ts deleted file mode 100644 index 51f185c53..000000000 --- a/ts/editor/symbols-overlay/symbols-table.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -import Fuse from "fuse.js"; - -import characterEntities from "./character-entities"; -import gemoji from "./gemoji"; -import type { SymbolsEntry, SymbolsTable } from "./symbols-types"; - -const symbolsTable: SymbolsTable = [...characterEntities, ...gemoji]; - -const symbolsFuse = new Fuse(symbolsTable, { - threshold: 0.2, - minMatchCharLength: 2, - useExtendedSearch: true, - isCaseSensitive: true, - keys: [ - { - name: "names", - weight: 7, - }, - { - name: "tags", - weight: 3, - }, - { - name: "autoInsert", - weight: 0.1, - }, - { - name: "containsHTML", - weight: 0.1, - }, - ], -}); - -export function findSymbols(query: string): SymbolsTable { - return symbolsFuse.search(query).map(({ item }) => item); -} - -export function getExactSymbol(query: string): SymbolsEntry | null { - const [found] = symbolsFuse.search({ names: `="${query}"` }, { limit: 1 }); - - return found ? found.item : null; -} - -export function getAutoInsertSymbol(query: string): SymbolsEntry | null { - const [found] = symbolsFuse.search({ - names: `="${query}"`, - autoInsert: "=autoInsert", - }); - - return found ? found.item : null; -} diff --git a/ts/editor/symbols-overlay/symbols-types.d.ts b/ts/editor/symbols-overlay/symbols-types.d.ts deleted file mode 100644 index 9004f14c7..000000000 --- a/ts/editor/symbols-overlay/symbols-types.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright: Ankitects Pty Ltd and contributors -// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html - -export interface SymbolsEntry { - symbol: string; - /** - * Used for searching and direct insertion - */ - names: string[]; - /** - * Used for searching - */ - tags: string[]; - /** - * If symbols contain HTML, they need to be treated specially. - */ - containsHTML?: "containsHTML"; - /** - * Symbols can be automak inserted, when you enter a full name within delimiters. - * If you enable auto insertion, you can use direction insertion without - * using the delimiter and triggering the search dropdown. - * To falicitate interacting with fuse.js this is a string value rather than a boolean. - */ - autoInsert?: "autoInsert"; -} - -export type SymbolsTable = SymbolsEntry[]; diff --git a/ts/editor/tsconfig.json b/ts/editor/tsconfig.json index e021013df..b5d2538b8 100644 --- a/ts/editor/tsconfig.json +++ b/ts/editor/tsconfig.json @@ -4,7 +4,6 @@ "*", "image-overlay/*", "mathjax-overlay/*", - "symbols-overlay/*", "plain-text-input/*", "rich-text-input/*", "editor-toolbar/*" diff --git a/ts/graphs/GraphsPage.svelte b/ts/graphs/GraphsPage.svelte index 434c834e4..969b4e585 100644 --- a/ts/graphs/GraphsPage.svelte +++ b/ts/graphs/GraphsPage.svelte @@ -4,7 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->