From 177192630989828e84af0567f8029b9d9cdd01cf Mon Sep 17 00:00:00 2001 From: softyoda Date: Fri, 13 Feb 2026 16:52:57 +0100 Subject: [PATCH 1/2] feat: add editor formatting toolbar with keyboard shortcuts Add a comprehensive markdown formatting toolbar (EditorToolbar.svelte) and a complete formatting API to the Editor component. Features include: - Inline formatting: bold, italic, strikethrough, underline, inline code - Headings: H1-H6 with cycle support - Lists: unordered, ordered, and task lists with toggle behavior - Block elements: blockquote, code block, horizontal rule - Insert operations: links, images, tables - Smart toggle: format/unformat based on current state - Multi-line support for inline and list formatting - Keyboard shortcuts for all formatting actions Co-Authored-By: Claude Opus 4.6 --- package-lock.json | 1226 +---------------------- src/lib/MarkdownViewer.svelte | 90 +- src/lib/components/Editor.svelte | 742 ++++++++++++-- src/lib/components/EditorToolbar.svelte | 210 ++++ 4 files changed, 948 insertions(+), 1320 deletions(-) create mode 100644 src/lib/components/EditorToolbar.svelte diff --git a/package-lock.json b/package-lock.json index f0b0078..424b3bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,24 +1,20 @@ { "name": "markpad", - "version": "2.4.2", + "version": "2.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "markpad", - "version": "2.4.2", + "version": "2.4.0", "license": "MIT", "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-dialog": "^2.5.0", "@tauri-apps/plugin-opener": "^2", - "@types/dompurify": "^3.0.5", - "dompurify": "^3.3.1", "highlight.js": "^11.11.1", "katex": "^0.16.27", - "mermaid": "^11.12.2", - "monaco-editor": "^0.55.1", - "monaco-vim": "^0.4.4" + "monaco-editor": "^0.55.1" }, "devDependencies": { "@sveltejs/adapter-static": "^3.0.6", @@ -31,76 +27,6 @@ "vite": "^6.0.3" } }, - "node_modules/@antfu/install-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", - "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", - "license": "MIT", - "dependencies": { - "package-manager-detector": "^1.3.0", - "tinyexec": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@braintree/sanitize-url": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", - "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", - "license": "MIT" - }, - "node_modules/@chevrotain/cst-dts-gen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/gast": "11.0.3", - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/@chevrotain/gast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/types": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/@chevrotain/gast/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, - "node_modules/@chevrotain/regexp-to-ast": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/types": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", - "license": "Apache-2.0" - }, - "node_modules/@chevrotain/utils": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", - "license": "Apache-2.0" - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -543,23 +469,6 @@ "node": ">=18" } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "license": "MIT" - }, - "node_modules/@iconify/utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", - "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", - "license": "MIT", - "dependencies": { - "@antfu/install-pkg": "^1.1.0", - "@iconify/types": "^2.0.0", - "mlly": "^1.8.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -610,15 +519,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mermaid-js/parser": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", - "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", - "license": "MIT", - "dependencies": { - "langium": "3.3.1" - } - }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -1009,6 +909,7 @@ "integrity": "sha512-JFtOqDoU0DI/+QSG8qnq5bKcehVb3tCHhOG4amsSYth5/KgO4EkJvi42xSAiyKmXAAULW1/Zdb6lkgGEgSxdZg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -1052,6 +953,7 @@ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -1338,237 +1240,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", - "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==" - }, - "node_modules/@types/d3-axis": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-brush": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-chord": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" - }, - "node_modules/@types/d3-contour": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", - "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==" - }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" - }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", - "dependencies": { - "@types/d3-dsv": "*" - } - }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==" - }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==" - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" - }, - "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==" - }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==" - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==" - }, - "node_modules/@types/d3-time-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", - "dependencies": { - "@types/d3-selection": "*" - } - }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "license": "MIT", - "dependencies": { - "@types/trusted-types": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1576,23 +1247,20 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1620,38 +1288,6 @@ "node": ">= 0.4" } }, - "node_modules/chevrotain": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", - "license": "Apache-2.0", - "dependencies": { - "@chevrotain/cst-dts-gen": "11.0.3", - "@chevrotain/gast": "11.0.3", - "@chevrotain/regexp-to-ast": "11.0.3", - "@chevrotain/types": "11.0.3", - "@chevrotain/utils": "11.0.3", - "lodash-es": "4.17.21" - } - }, - "node_modules/chevrotain-allstar": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21" - }, - "peerDependencies": { - "chevrotain": "^11.0.0" - } - }, - "node_modules/chevrotain/node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1687,12 +1323,6 @@ "node": ">= 12" } }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "license": "MIT" - }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -1703,529 +1333,6 @@ "node": ">= 0.6" } }, - "node_modules/cose-base": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", - "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", - "license": "MIT", - "dependencies": { - "layout-base": "^1.0.0" - } - }, - "node_modules/cytoscape": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", - "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cytoscape-cose-bilkent": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", - "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", - "license": "MIT", - "dependencies": { - "cose-base": "^1.0.0" - }, - "peerDependencies": { - "cytoscape": "^3.2.0" - } - }, - "node_modules/cytoscape-fcose": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", - "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", - "license": "MIT", - "dependencies": { - "cose-base": "^2.2.0" - }, - "peerDependencies": { - "cytoscape": "^3.2.0" - } - }, - "node_modules/cytoscape-fcose/node_modules/cose-base": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", - "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", - "license": "MIT", - "dependencies": { - "layout-base": "^2.0.0" - } - }, - "node_modules/cytoscape-fcose/node_modules/layout-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", - "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", - "license": "MIT" - }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "license": "ISC", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "license": "ISC", - "dependencies": { - "d3-path": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "license": "ISC", - "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "license": "ISC", - "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "license": "ISC", - "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-dsv/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "license": "ISC", - "dependencies": { - "d3-dsv": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-geo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", - "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-sankey": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", - "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "1 - 2", - "d3-shape": "^1.2.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-array": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", - "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", - "license": "BSD-3-Clause", - "dependencies": { - "internmap": "^1.0.0" - } - }, - "node_modules/d3-sankey/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-sankey/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/d3-sankey/node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", - "license": "ISC" - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dagre-d3-es": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", - "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", - "license": "MIT", - "dependencies": { - "d3": "^7.9.0", - "lodash-es": "^4.17.21" - } - }, - "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2254,15 +1361,6 @@ "node": ">=0.10.0" } }, - "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "license": "ISC", - "dependencies": { - "robust-predicates": "^3.0.2" - } - }, "node_modules/devalue": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz", @@ -2271,9 +1369,9 @@ "license": "MIT" }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -2371,12 +1469,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/hachure-fill": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", - "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", - "license": "MIT" - }, "node_modules/highlight.js": { "version": "11.11.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", @@ -2386,27 +1478,6 @@ "node": ">=12.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -2433,11 +1504,6 @@ "katex": "cli.js" } }, - "node_modules/khroma": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" - }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -2448,28 +1514,6 @@ "node": ">=6" } }, - "node_modules/langium": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", - "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", - "license": "MIT", - "dependencies": { - "chevrotain": "~11.0.3", - "chevrotain-allstar": "~0.3.0", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.11", - "vscode-uri": "~3.0.8" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/layout-base": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", - "license": "MIT" - }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -2477,12 +1521,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", - "license": "MIT" - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2505,58 +1543,6 @@ "node": ">= 18" } }, - "node_modules/mermaid": { - "version": "11.12.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.2.tgz", - "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==", - "license": "MIT", - "dependencies": { - "@braintree/sanitize-url": "^7.1.1", - "@iconify/utils": "^3.0.1", - "@mermaid-js/parser": "^0.6.3", - "@types/d3": "^7.4.3", - "cytoscape": "^3.29.3", - "cytoscape-cose-bilkent": "^4.1.0", - "cytoscape-fcose": "^2.2.0", - "d3": "^7.9.0", - "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.13", - "dayjs": "^1.11.18", - "dompurify": "^3.2.5", - "katex": "^0.16.22", - "khroma": "^2.1.0", - "lodash-es": "^4.17.21", - "marked": "^16.2.1", - "roughjs": "^4.6.6", - "stylis": "^4.3.6", - "ts-dedent": "^2.2.0", - "uuid": "^11.1.0" - } - }, - "node_modules/mermaid/node_modules/marked": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", - "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "license": "MIT", - "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" - } - }, "node_modules/monaco-editor": { "version": "0.55.1", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", @@ -2567,23 +1553,6 @@ "marked": "14.0.0" } }, - "node_modules/monaco-editor/node_modules/dompurify": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, - "node_modules/monaco-vim": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/monaco-vim/-/monaco-vim-0.4.4.tgz", - "integrity": "sha512-LNChAb//WEm/W+eyeHG/0+pdVEHotk2hLTN+M3sQZx5E8cAlSWSgqcxpcRuQnxDybSln7pfHF9i63HmbIQvrWw==", - "peerDependencies": { - "monaco-editor": "*" - } - }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -2630,24 +1599,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/package-manager-detector": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", - "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", - "license": "MIT" - }, - "node_modules/path-data-parser": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", - "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", - "license": "MIT" - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2661,6 +1612,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2668,33 +1620,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/points-on-curve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", - "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", - "license": "MIT" - }, - "node_modules/points-on-path": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", - "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", - "license": "MIT", - "dependencies": { - "path-data-parser": "0.1.0", - "points-on-curve": "0.2.0" - } - }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -2738,12 +1663,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "license": "Unlicense" - }, "node_modules/rollup": { "version": "4.55.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", @@ -2789,24 +1708,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/roughjs": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", - "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", - "license": "MIT", - "dependencies": { - "hachure-fill": "^0.5.2", - "path-data-parser": "^0.1.0", - "points-on-curve": "^0.2.0", - "points-on-path": "^0.2.1" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -2820,12 +1721,6 @@ "node": ">=6" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -2858,18 +1753,13 @@ "node": ">=0.10.0" } }, - "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", - "license": "MIT" - }, "node_modules/svelte": { "version": "5.46.3", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.3.tgz", "integrity": "sha512-Y5juST3x+/ySty5tYJCVWa6Corkxpt25bUZQHqOceg9xfMUtDsFx6rCsG6cYf1cA6vzDi66HIvaki0byZZX95A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -2915,15 +1805,6 @@ "typescript": ">=5.0.0" } }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2951,21 +1832,13 @@ "node": ">=6" } }, - "node_modules/ts-dedent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", - "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", - "license": "MIT", - "engines": { - "node": ">=6.10" - } - }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2974,31 +1847,13 @@ "node": ">=14.17" } }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "license": "MIT" - }, - "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -3088,55 +1943,6 @@ } } }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.17.5" - }, - "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "license": "MIT", - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "license": "MIT" - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "license": "MIT" - }, - "node_modules/vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", - "license": "MIT" - }, "node_modules/zimmerframe": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", diff --git a/src/lib/MarkdownViewer.svelte b/src/lib/MarkdownViewer.svelte index bc65cb2..770c33d 100644 --- a/src/lib/MarkdownViewer.svelte +++ b/src/lib/MarkdownViewer.svelte @@ -9,6 +9,7 @@ import Uninstaller from './Uninstaller.svelte'; import TitleBar from './components/TitleBar.svelte'; import Editor from './components/Editor.svelte'; + import EditorToolbar from './components/EditorToolbar.svelte'; import Modal from './components/Modal.svelte'; import DOMPurify from 'dompurify'; @@ -38,6 +39,7 @@ let isEditing = $derived(activeTab?.isEditing ?? false); let rawContent = $derived(activeTab?.rawContent ?? ''); let isSplit = $derived(activeTab?.isSplit ?? false); + let editorRef = $state>(); // derived from tab manager let currentFile = $derived(tabManager.activeTab?.path ?? ''); @@ -486,6 +488,10 @@ } } + function handleFormat(action: string) { + editorRef?.format(action); + } + function handleScroll(e: Event) { const target = e.target as HTMLElement; @@ -497,10 +503,6 @@ return; } - if (tabManager.activeTab?.isScrollSynced) { - tabManager.toggleScrollSync(tabManager.activeTab.id); - } - if (tabManager.activeTabId) { // Update raw scroll pos tabManager.updateTabScroll(tabManager.activeTabId, target.scrollTop); @@ -1278,29 +1280,36 @@
{#if isEditing || isSplit} - toggleEdit()} - ontoggleLive={toggleLiveMode} - onhome={() => (showHome = true)} - onnextTab={() => tabManager.cycleTab('next')} - onprevTab={() => tabManager.cycleTab('prev')} - onundoClose={handleUndoCloseTab} - onscrollsync={handleEditorScrollSync} /> +
+ +
+ toggleEdit()} + ontoggleLive={toggleLiveMode} + onhome={() => (showHome = true)} + onnextTab={() => tabManager.cycleTab('next')} + onprevTab={() => tabManager.cycleTab('prev')} + onundoClose={handleUndoCloseTab} + onscrollsync={handleEditorScrollSync} /> +
+
{/if}
{#if isSplit} +
startDrag(e, tabManager.activeTabId)} role="separator" aria-orientation="vertical" tabindex="0">
{/if} @@ -1392,24 +1401,6 @@ max-width: 100%; } - .caret-indicator { - position: absolute; - height: 2px; - background-color: #0078d4; - width: 100%; - left: 0; - right: 0; - pointer-events: none; - z-index: 100; - opacity: 0.8; - transform: translateY(2px); /* visual adjustment */ - } - - /* Disable animation in split view to prevent jumpiness */ - .split-view .markdown-body { - animation: none; - } - @keyframes slideIn { from { opacity: 0; @@ -1483,14 +1474,16 @@ border-top: 6px solid var(--color-canvas-default); } - .editor-wrapper { - width: 100%; + .editor-stack { + display: flex; + flex-direction: column; height: 100%; - position: absolute; - top: 0; - left: 0; - padding-top: 36px; - box-sizing: border-box; + min-height: 0; + } + + .editor-host { + flex: 1; + min-height: 0; } .drag-overlay { @@ -1657,9 +1650,4 @@ background: var(--color-accent-fg); } - .editor-wrapper { - /* Legacy mapping */ - width: 100%; - height: 100%; - } diff --git a/src/lib/components/Editor.svelte b/src/lib/components/Editor.svelte index bf1a97d..e3fc33f 100644 --- a/src/lib/components/Editor.svelte +++ b/src/lib/components/Editor.svelte @@ -58,6 +58,594 @@ let currentLanguage = $state('markdown'); const currentTabId = tabManager.activeTabId; + const escapeRegex = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + const getEditorContext = () => { + if (!editor) return null; + const model = editor.getModel(); + const selection = editor.getSelection(); + if (!model || !selection) return null; + return { model, selection }; + }; + + const isEscaped = (line: string, index: number) => index > 0 && line[index - 1] === '\\'; + + const findInlineFormatRange = (model: monaco.editor.ITextModel, position: monaco.Position, marker: string): monaco.Range | null => { + const line = model.getLineContent(position.lineNumber); + const markerLen = marker.length; + const cursorIndex = position.column - 1; + + let start = -1; + for (let i = Math.min(cursorIndex - markerLen, line.length - markerLen); i >= 0; i--) { + if (line.slice(i, i + markerLen) === marker && !isEscaped(line, i)) { + start = i; + break; + } + } + + let end = -1; + for (let i = Math.max(cursorIndex, 0); i <= line.length - markerLen; i++) { + if (line.slice(i, i + markerLen) === marker && !isEscaped(line, i)) { + end = i + markerLen; + break; + } + } + + if (start !== -1 && end !== -1 && start < end) { + return new monaco.Range(position.lineNumber, start + 1, position.lineNumber, end + 1); + } + return null; + }; + + const tryExpandToFormatBoundary = ( + model: monaco.editor.ITextModel, + selection: monaco.Selection, + marker: string, + ): monaco.Range | null => { + if (selection.startLineNumber !== selection.endLineNumber) return null; + + const line = model.getLineContent(selection.startLineNumber); + const markerLen = marker.length; + const startIndex = selection.startColumn - 1; + const endIndex = selection.endColumn - 1; + + let start = -1; + for (let i = Math.min(startIndex - markerLen, line.length - markerLen); i >= 0; i--) { + if (line.slice(i, i + markerLen) === marker && !isEscaped(line, i)) { + start = i; + break; + } + } + + let end = -1; + for (let i = Math.max(endIndex, 0); i <= line.length - markerLen; i++) { + if (line.slice(i, i + markerLen) === marker && !isEscaped(line, i)) { + end = i + markerLen; + break; + } + } + + if (start !== -1 && end !== -1 && start < end) { + return new monaco.Range(selection.startLineNumber, start + 1, selection.startLineNumber, end + 1); + } + return null; + }; + + const findTagRange = (model: monaco.editor.ITextModel, position: monaco.Position, startTag: string, endTag: string): monaco.Range | null => { + const line = model.getLineContent(position.lineNumber); + const cursorIndex = position.column - 1; + const startIndex = line.lastIndexOf(startTag, cursorIndex); + const endIndex = line.indexOf(endTag, cursorIndex); + if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) { + return new monaco.Range(position.lineNumber, startIndex + 1, position.lineNumber, endIndex + endTag.length + 1); + } + return null; + }; + + const tryExpandToTagBoundary = ( + model: monaco.editor.ITextModel, + selection: monaco.Selection, + startTag: string, + endTag: string, + ): monaco.Range | null => { + if (selection.startLineNumber !== selection.endLineNumber) return null; + const line = model.getLineContent(selection.startLineNumber); + const startIndex = line.lastIndexOf(startTag, selection.startColumn - 1); + const endIndex = line.indexOf(endTag, selection.endColumn - 1); + if (startIndex !== -1 && endIndex !== -1 && startIndex < endIndex) { + return new monaco.Range(selection.startLineNumber, startIndex + 1, selection.startLineNumber, endIndex + endTag.length + 1); + } + return null; + }; + + const handleInlineFormat = (model: monaco.editor.ITextModel, selection: monaco.Selection, marker: string) => { + const text = model.getValueInRange(selection); + const markerLen = marker.length; + + if (!selection.isEmpty()) { + if (selection.startLineNumber !== selection.endLineNumber) { + const edits: monaco.editor.IIdentifiedSingleEditOperation[] = []; + for (let line = selection.startLineNumber; line <= selection.endLineNumber; line++) { + const lineContent = model.getLineContent(line); + const startColumn = line === selection.startLineNumber ? selection.startColumn : 1; + const endColumn = line === selection.endLineNumber ? selection.endColumn : lineContent.length + 1; + const range = new monaco.Range(line, startColumn, line, endColumn); + const segment = model.getValueInRange(range); + if (segment === '') continue; + + if (segment.startsWith(marker) && segment.endsWith(marker) && segment.length >= markerLen * 2) { + const unwrapped = segment.slice(markerLen, -markerLen); + edits.push({ range, text: unwrapped, forceMoveMarkers: true }); + } else { + edits.push({ range, text: `${marker}${segment}${marker}`, forceMoveMarkers: true }); + } + } + + if (edits.length > 0) editor.executeEdits('format-inline', edits); + return; + } + + if (text.startsWith(marker) && text.endsWith(marker) && text.length >= markerLen * 2) { + const unwrapped = text.slice(markerLen, -markerLen); + editor.executeEdits('format-inline', [{ range: selection, text: unwrapped, forceMoveMarkers: true }]); + return; + } + + const expandedRange = tryExpandToFormatBoundary(model, selection, marker); + if (expandedRange) { + const fullText = model.getValueInRange(expandedRange); + if (fullText.startsWith(marker) && fullText.endsWith(marker)) { + const inner = fullText.slice(markerLen, -markerLen); + editor.executeEdits('format-inline', [{ range: expandedRange, text: inner, forceMoveMarkers: true }]); + return; + } + } + + editor.executeEdits('format-inline', [ + { + range: selection, + text: `${marker}${text}${marker}`, + forceMoveMarkers: true, + }, + ]); + return; + } + + const cursorPos = selection.getPosition(); + const formatRange = findInlineFormatRange(model, cursorPos, marker); + if (formatRange) { + const formattedText = model.getValueInRange(formatRange); + const inner = formattedText.slice(markerLen, -markerLen); + editor.executeEdits('format-inline', [{ range: formatRange, text: inner, forceMoveMarkers: true }]); + return; + } + + editor.executeEdits('format-inline', [ + { + range: selection, + text: `${marker}${marker}`, + forceMoveMarkers: true, + }, + ]); + + const newPos = new monaco.Position(cursorPos.lineNumber, cursorPos.column + markerLen); + editor.setPosition(newPos); + }; + + const handleTagFormat = (model: monaco.editor.ITextModel, selection: monaco.Selection, startTag: string, endTag: string) => { + const text = model.getValueInRange(selection); + + if (!selection.isEmpty()) { + if (text.startsWith(startTag) && text.endsWith(endTag)) { + const unwrapped = text.slice(startTag.length, -endTag.length); + editor.executeEdits('format-tag', [{ range: selection, text: unwrapped, forceMoveMarkers: true }]); + return; + } + + const expandedRange = tryExpandToTagBoundary(model, selection, startTag, endTag); + if (expandedRange) { + const fullText = model.getValueInRange(expandedRange); + if (fullText.startsWith(startTag) && fullText.endsWith(endTag)) { + const inner = fullText.slice(startTag.length, -endTag.length); + editor.executeEdits('format-tag', [{ range: expandedRange, text: inner, forceMoveMarkers: true }]); + return; + } + } + + editor.executeEdits('format-tag', [ + { + range: selection, + text: `${startTag}${text}${endTag}`, + forceMoveMarkers: true, + }, + ]); + return; + } + + const cursorPos = selection.getPosition(); + const tagRange = findTagRange(model, cursorPos, startTag, endTag); + if (tagRange) { + const formattedText = model.getValueInRange(tagRange); + const inner = formattedText.slice(startTag.length, -endTag.length); + editor.executeEdits('format-tag', [{ range: tagRange, text: inner, forceMoveMarkers: true }]); + return; + } + + editor.executeEdits('format-tag', [ + { + range: selection, + text: `${startTag}${endTag}`, + forceMoveMarkers: true, + }, + ]); + + const newPos = new monaco.Position(cursorPos.lineNumber, cursorPos.column + startTag.length); + editor.setPosition(newPos); + }; + + const handleLineFormat = (model: monaco.editor.ITextModel, selection: monaco.Selection, prefix: string) => { + const startLine = selection.startLineNumber; + const endLine = selection.endLineNumber; + + let allHavePrefix = true; + const prefixTrimmed = prefix.trim(); + + for (let i = startLine; i <= endLine; i++) { + const line = model.getLineContent(i); + if (!line.trimStart().startsWith(prefixTrimmed)) { + allHavePrefix = false; + break; + } + } + + const edits: monaco.editor.IIdentifiedSingleEditOperation[] = []; + const prefixRegex = new RegExp(`^(\\s*)${escapeRegex(prefixTrimmed)}\\s?`); + + for (let i = startLine; i <= endLine; i++) { + const line = model.getLineContent(i); + const lineRange = new monaco.Range(i, 1, i, line.length + 1); + + if (allHavePrefix) { + const prefixMatch = line.match(prefixRegex); + if (prefixMatch) { + const newLine = line.slice(prefixMatch[0].length); + edits.push({ range: lineRange, text: newLine }); + } + } else { + const leadingWs = line.match(/^(\s*)/)?.[1] || ''; + const content = line.slice(leadingWs.length); + const cleanContent = prefixTrimmed.startsWith('#') ? content.replace(/^#{1,6}\s*/, '') : content; + edits.push({ range: lineRange, text: `${leadingWs}${prefix}${cleanContent}` }); + } + } + + if (edits.length > 0) { + editor.executeEdits('line-format', edits); + } + }; + + const cycleHeading = (direction: 'up' | 'down' = 'down') => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + + const line = model.getLineContent(selection.startLineNumber); + const headingMatch = line.match(/^(#{1,6})\s/); + const currentLevel = headingMatch ? headingMatch[1].length : 0; + let newLevel = currentLevel; + + if (direction === 'down') { + newLevel = currentLevel >= 6 ? 0 : currentLevel + 1; + } else { + newLevel = currentLevel <= 0 ? 6 : currentLevel - 1; + } + + const lineRange = new monaco.Range(selection.startLineNumber, 1, selection.startLineNumber, line.length + 1); + const cleanLine = line.replace(/^#{1,6}\s*/, ''); + const newLine = newLevel > 0 ? `${'#'.repeat(newLevel)} ${cleanLine}` : cleanLine; + editor.executeEdits('heading-cycle', [{ range: lineRange, text: newLine }]); + editor.focus(); + }; + + const toggleUnorderedList = () => { + const context = getEditorContext(); + if (!context) return; + handleLineFormat(context.model, context.selection, '- '); + editor.focus(); + }; + + const toggleOrderedList = () => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + + const startLine = selection.startLineNumber; + const endLine = selection.endLineNumber; + + let isOrderedList = true; + for (let i = startLine; i <= endLine; i++) { + const line = model.getLineContent(i); + if (!line.match(/^\s*\d+\.\s/)) { + isOrderedList = false; + break; + } + } + + const edits: monaco.editor.IIdentifiedSingleEditOperation[] = []; + for (let i = startLine; i <= endLine; i++) { + const line = model.getLineContent(i); + const lineRange = new monaco.Range(i, 1, i, line.length + 1); + + if (isOrderedList) { + const newLine = line.replace(/^\s*\d+\.\s/, ''); + edits.push({ range: lineRange, text: newLine }); + } else { + const leadingWs = line.match(/^(\s*)/)?.[1] || ''; + const content = line.slice(leadingWs.length).replace(/^[-*]\s/, ''); + const num = i - startLine + 1; + edits.push({ range: lineRange, text: `${leadingWs}${num}. ${content}` }); + } + } + + if (edits.length > 0) editor.executeEdits('list-toggle', edits); + editor.focus(); + }; + + const toggleTaskList = () => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + + const startLine = selection.startLineNumber; + const endLine = selection.endLineNumber; + const edits: monaco.editor.IIdentifiedSingleEditOperation[] = []; + + for (let i = startLine; i <= endLine; i++) { + const line = model.getLineContent(i); + const lineRange = new monaco.Range(i, 1, i, line.length + 1); + + if (line.match(/^\s*-\s\[x\]\s/i)) { + const newLine = line.replace(/^\s*-\s\[x\]\s/i, ''); + edits.push({ range: lineRange, text: newLine }); + } else if (line.match(/^\s*-\s\[\s?\]\s/)) { + const newLine = line.replace(/^\s*-\s\[\s?\]\s/, (match) => match.replace(/\[\s?\]/, '[x]')); + edits.push({ range: lineRange, text: newLine }); + } else { + const leadingWs = line.match(/^(\s*)/)?.[1] || ''; + const content = line.slice(leadingWs.length).replace(/^[-*]\s/, ''); + edits.push({ range: lineRange, text: `${leadingWs}- [ ] ${content}` }); + } + } + + if (edits.length > 0) editor.executeEdits('task-toggle', edits); + editor.focus(); + }; + + const insertLink = (url?: string, text?: string) => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + const selectedText = model.getValueInRange(selection); + let linkText = text || selectedText || 'link text'; + let linkUrl = url || ''; + + if (!url) { + if (!selectedText && !text) { + const promptText = window.prompt('Link text:', linkText); + if (promptText === null) return; + linkText = promptText || 'link text'; + } + const promptUrl = window.prompt('Link URL:', 'https://'); + if (promptUrl === null) return; + linkUrl = promptUrl || 'https://'; + } + + if (!linkUrl) linkUrl = 'https://'; + const markdown = `[${linkText}](${linkUrl})`; + + editor.executeEdits('insert-link', [{ range: selection, text: markdown, forceMoveMarkers: true }]); + + if (!url && selection.startLineNumber === selection.endLineNumber) { + const startCol = selection.startColumn + linkText.length + 3; + const endCol = startCol + linkUrl.length; + editor.setSelection(new monaco.Selection(selection.startLineNumber, startCol, selection.startLineNumber, endCol)); + } + editor.focus(); + }; + + const insertImage = (url?: string, alt?: string) => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + const selectedText = model.getValueInRange(selection); + let altText = alt || selectedText || 'image'; + let imgUrl = url || ''; + + if (!url) { + if (!selectedText && !alt) { + const promptAlt = window.prompt('Image alt text:', altText); + if (promptAlt === null) return; + altText = promptAlt || 'image'; + } + const promptUrl = window.prompt('Image URL:', 'https://'); + if (promptUrl === null) return; + imgUrl = promptUrl || 'https://'; + } + + if (!imgUrl) imgUrl = 'https://'; + const markdown = `![${altText}](${imgUrl})`; + + editor.executeEdits('insert-image', [{ range: selection, text: markdown, forceMoveMarkers: true }]); + + if (!url && selection.startLineNumber === selection.endLineNumber) { + const startCol = selection.startColumn + altText.length + 4; + const endCol = startCol + imgUrl.length; + editor.setSelection(new monaco.Selection(selection.startLineNumber, startCol, selection.startLineNumber, endCol)); + } + editor.focus(); + }; + + const getFullLineRange = (model: monaco.editor.ITextModel, lineNumber: number) => { + if (lineNumber < model.getLineCount()) { + return new monaco.Range(lineNumber, 1, lineNumber + 1, 1); + } + return new monaco.Range(lineNumber, 1, lineNumber, model.getLineMaxColumn(lineNumber)); + }; + + const insertCodeBlock = (language: string = '') => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + const selectedText = model.getValueInRange(selection); + + const startLine = selection.startLineNumber; + let codeBlockStart = -1; + let codeBlockEnd = -1; + + for (let i = startLine; i >= 1; i--) { + const line = model.getLineContent(i); + if (line.startsWith('```')) { + codeBlockStart = i; + break; + } + } + + if (codeBlockStart !== -1) { + for (let i = startLine; i <= model.getLineCount(); i++) { + const line = model.getLineContent(i); + if (line.startsWith('```') && i !== codeBlockStart) { + codeBlockEnd = i; + break; + } + } + } + + const inCodeBlock = codeBlockStart !== -1 && codeBlockEnd !== -1 && codeBlockStart < startLine && codeBlockEnd > startLine; + + if (inCodeBlock) { + const edits: monaco.editor.IIdentifiedSingleEditOperation[] = [ + { range: getFullLineRange(model, codeBlockEnd), text: '' }, + { range: getFullLineRange(model, codeBlockStart), text: '' }, + ]; + editor.executeEdits('code-block-remove', edits); + editor.focus(); + return; + } + + const codeBlock = selectedText + ? `\`\`\`${language}\n${selectedText}\n\`\`\`` + : `\`\`\`${language}\n\n\`\`\``; + + editor.executeEdits('code-block-insert', [{ range: selection, text: codeBlock, forceMoveMarkers: true }]); + + if (!selectedText) { + const newPos = new monaco.Position(selection.startLineNumber + 1, 1); + editor.setPosition(newPos); + } + editor.focus(); + }; + + const insertHorizontalRule = () => { + const context = getEditorContext(); + if (!context) return; + const { model, selection } = context; + const currentLine = model.getLineContent(selection.startLineNumber); + const isEmptyLine = currentLine.trim() === ''; + const hr = isEmptyLine ? '---\n' : '\n---\n'; + + const insertPos = isEmptyLine + ? new monaco.Range(selection.startLineNumber, 1, selection.startLineNumber, 1) + : new monaco.Range(selection.startLineNumber, currentLine.length + 1, selection.startLineNumber, currentLine.length + 1); + + editor.executeEdits('insert-hr', [{ range: insertPos, text: hr, forceMoveMarkers: true }]); + const targetLine = selection.startLineNumber + (isEmptyLine ? 1 : 2); + editor.setPosition(new monaco.Position(targetLine, 1)); + editor.focus(); + }; + + const insertTable = () => { + const context = getEditorContext(); + if (!context) return; + const { selection } = context; + + const cols = 3; + const rows = 2; + let table = '\n'; + table += '| ' + Array(cols).fill('Header').join(' | ') + ' |\n'; + table += '| ' + Array(cols).fill('---').join(' | ') + ' |\n'; + for (let i = 0; i < rows; i++) { + table += '| ' + Array(cols).fill('Cell').join(' | ') + ' |\n'; + } + table += '\n'; + + editor.executeEdits('insert-table', [ + { + range: selection, + text: table, + forceMoveMarkers: true, + }, + ]); + editor.focus(); + }; + + const formatInline = (marker: string) => { + const context = getEditorContext(); + if (!context) return; + handleInlineFormat(context.model, context.selection, marker); + editor.focus(); + }; + + const formatTag = (startTag: string, endTag: string) => { + const context = getEditorContext(); + if (!context) return; + handleTagFormat(context.model, context.selection, startTag, endTag); + editor.focus(); + }; + + const formatLine = (prefix: string) => { + const context = getEditorContext(); + if (!context) return; + handleLineFormat(context.model, context.selection, prefix); + editor.focus(); + }; + + const getFormattingAPI = () => ({ + bold: () => formatInline('**'), + italic: () => formatInline('*'), + strikethrough: () => formatInline('~~'), + inlineCode: () => formatInline('`'), + underline: () => formatTag('', ''), + heading1: () => formatLine('# '), + heading2: () => formatLine('## '), + heading3: () => formatLine('### '), + heading4: () => formatLine('#### '), + heading5: () => formatLine('##### '), + heading6: () => formatLine('###### '), + cycleHeading: () => cycleHeading('down'), + blockquote: () => formatLine('> '), + unorderedList: () => toggleUnorderedList(), + orderedList: () => toggleOrderedList(), + taskList: () => toggleTaskList(), + insertLink: () => insertLink(), + insertImage: () => insertImage(), + insertCodeBlock: () => insertCodeBlock(), + insertTable: () => insertTable(), + insertHorizontalRule: () => insertHorizontalRule(), + focus: () => editor?.focus(), + }); + + export function format(action: string, params?: any) { + const api = getFormattingAPI() as Record void>; + const fn = api[action]; + if (typeof fn === 'function') { + params ? fn(params) : fn(); + } + } + + export function focusEditor() { + editor?.focus(); + } + self.MonacoEnvironment = { getWorker: function (_moduleId: any, label: string) { if (label === 'json') { @@ -278,87 +866,123 @@ if (onsave) onsave(); }); - const insertTextAtCursor = (text: string) => { - const selection = editor.getSelection(); - if (!selection) return; - const id = { major: 1, minor: 1 }; - const op = { range: selection, text: text, forceMoveMarkers: true }; - editor.executeEdits('my-source', [op]); - }; - - const toggleFormat = (marker: string, type: 'wrap' | 'block' | 'tag' = 'wrap') => { - const selection = editor.getSelection(); - if (!selection) return; - - const model = editor.getModel(); - if (!model) return; - - const text = model.getValueInRange(selection); - - if (type === 'wrap') { - if (text.startsWith(marker) && text.endsWith(marker)) { - const newText = text.slice(marker.length, -marker.length); - editor.executeEdits('toggle-format', [{ range: selection, text: newText }]); - } else { - editor.executeEdits('toggle-format', [{ range: selection, text: `${marker}${text}${marker}` }]); - } - } else if (type === 'tag') { - const [startTag, endTag] = marker.split('|'); - if (text.startsWith(startTag) && text.endsWith(endTag)) { - const newText = text.slice(startTag.length, -endTag.length); - editor.executeEdits('toggle-format', [{ range: selection, text: newText }]); - } else { - editor.executeEdits('toggle-format', [{ range: selection, text: `${startTag}${text}${endTag}` }]); - } - } - }; - editor.addAction({ id: 'fmt-bold', label: 'Format: Bold', keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB], - run: () => toggleFormat('**'), + run: () => formatInline('**'), }); editor.addAction({ id: 'fmt-italic', label: 'Format: Italic', keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI], - run: () => toggleFormat('*'), + run: () => formatInline('*'), }); editor.addAction({ id: 'fmt-underline', label: 'Format: Underline', keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyU], - run: () => toggleFormat('|', 'tag'), + run: () => formatTag('', ''), + }); + + editor.addAction({ + id: 'fmt-strikethrough', + label: 'Format: Strikethrough', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyS], + run: () => formatInline('~~'), + }); + + editor.addAction({ + id: 'fmt-inline-code', + label: 'Format: Inline Code', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Backquote], + run: () => formatInline('`'), + }); + + editor.addAction({ + id: 'fmt-heading-1', + label: 'Format: Heading 1', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Digit1], + run: () => formatLine('# '), + }); + + editor.addAction({ + id: 'fmt-heading-2', + label: 'Format: Heading 2', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Digit2], + run: () => formatLine('## '), + }); + + editor.addAction({ + id: 'fmt-heading-3', + label: 'Format: Heading 3', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Digit3], + run: () => formatLine('### '), + }); + + editor.addAction({ + id: 'fmt-blockquote', + label: 'Format: Blockquote', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Period], + run: () => formatLine('> '), + }); + + editor.addAction({ + id: 'fmt-unordered-list', + label: 'Format: Bullet List', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Digit8], + run: () => toggleUnorderedList(), + }); + + editor.addAction({ + id: 'fmt-ordered-list', + label: 'Format: Numbered List', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Digit7], + run: () => toggleOrderedList(), + }); + + editor.addAction({ + id: 'fmt-task-list', + label: 'Format: Task List', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Digit9], + run: () => toggleTaskList(), + }); + + editor.addAction({ + id: 'fmt-code-block', + label: 'Format: Code Block', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyK], + run: () => insertCodeBlock(), + }); + + editor.addAction({ + id: 'insert-link', + label: 'Insert Link', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK], + run: () => insertLink(), + }); + + editor.addAction({ + id: 'insert-image', + label: 'Insert Image', + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyI], + run: () => insertImage(), + }); + + editor.addAction({ + id: 'insert-hr', + label: 'Insert Horizontal Rule', + run: () => insertHorizontalRule(), }); editor.addAction({ id: 'insert-table-simple', label: 'Insert Table', - keybindings: [monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK, monaco.KeyCode.KeyT)], + keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.KeyT], run: () => { - const selection = editor.getSelection(); - if (!selection) return; - - const cols = 3; - const rows = 2; - let table = '\n'; - table += '| ' + Array(cols).fill('Header').join(' | ') + ' |\n'; - table += '| ' + Array(cols).fill('---').join(' | ') + ' |\n'; - for (let i = 0; i < rows; i++) { - table += '| ' + Array(cols).fill('Cell').join(' | ') + ' |\n'; - } - table += '\n'; - - editor.executeEdits('insert-table', [ - { - range: selection, - text: table, - forceMoveMarkers: true, - }, - ]); + insertTable(); }, }); diff --git a/src/lib/components/EditorToolbar.svelte b/src/lib/components/EditorToolbar.svelte new file mode 100644 index 0000000..e2b459b --- /dev/null +++ b/src/lib/components/EditorToolbar.svelte @@ -0,0 +1,210 @@ + + +
+ {#each toolbarGroups as group} +
+ {#each group.buttons as btn} + + {/each} +
+ {/each} +
+ +{#if tooltip.show} +
+ {tooltip.text} + {#if tooltip.shortcut} + {tooltip.shortcut} + {/if} +
+{/if} + + From a2b608f3617e9c4c0648f7116df1b7cad79c5f6f Mon Sep 17 00:00:00 2001 From: softyoda Date: Fri, 13 Feb 2026 17:40:56 +0100 Subject: [PATCH 2/2] fix: resolve compatibility issues after rebase onto upstream master - Add {theme} prop to Editor in toolbar wrapper - Fix TypeScript errors in EditorToolbar (btn.style) and MarkdownViewer (editorRef type) Co-Authored-By: Claude Opus 4.6 --- src/lib/MarkdownViewer.svelte | 2 +- src/lib/components/EditorToolbar.svelte | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/MarkdownViewer.svelte b/src/lib/MarkdownViewer.svelte index 770c33d..9fbbbdd 100644 --- a/src/lib/MarkdownViewer.svelte +++ b/src/lib/MarkdownViewer.svelte @@ -39,7 +39,7 @@ let isEditing = $derived(activeTab?.isEditing ?? false); let rawContent = $derived(activeTab?.rawContent ?? ''); let isSplit = $derived(activeTab?.isSplit ?? false); - let editorRef = $state>(); + let editorRef = $state(); // derived from tab manager let currentFile = $derived(tabManager.activeTab?.path ?? ''); diff --git a/src/lib/components/EditorToolbar.svelte b/src/lib/components/EditorToolbar.svelte index e2b459b..78396c8 100644 --- a/src/lib/components/EditorToolbar.svelte +++ b/src/lib/components/EditorToolbar.svelte @@ -17,7 +17,7 @@ { id: 'italic', icon: 'I', label: 'Italic', shortcut: 'Ctrl+I', style: 'font-style: italic' }, { id: 'underline', icon: 'U', label: 'Underline', shortcut: 'Ctrl+U', style: 'text-decoration: underline' }, { id: 'strikethrough', icon: 'S', label: 'Strikethrough', shortcut: 'Ctrl+Shift+S', style: 'text-decoration: line-through' }, - { id: 'inlineCode', icon: '<>', label: 'Inline Code', shortcut: 'Ctrl+`' }, + { id: 'inlineCode', icon: '<>', label: 'Inline Code', shortcut: 'Ctrl+`', style: '' }, ], }, { @@ -98,7 +98,7 @@ onmouseenter={(e) => showTooltip(e, btn.label, btn.shortcut)} onmouseleave={hideTooltip} aria-label={btn.label} - style={btn.style || ''}> + style={'style' in btn ? btn.style : ''}> {#if btn.icon.length <= 2} {btn.icon} {:else}