From 90d1607eecbea3af6633e6d12da393fc5327c9c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Jan 2026 11:01:27 +0000 Subject: [PATCH] feat: migrate syntax highlighting from Prism.js to Shiki Replace Prism.js with Shiki for syntax highlighting with several key improvements: - Lazy loading: Languages loaded on-demand via dynamic imports instead of bundling all upfront - Broader language support: 200+ TextMate grammars vs 11 statically imported - Singleton highlighter: Core languages (JS, TS, JSON, diff, bash) preloaded, others loaded on first use New files: - src/lib/shiki.ts: Shiki service with highlightCode(), normalizeLanguage(), language aliases - src/hooks/useHighlightedCode.ts: React hook for async highlighting with loading states - src/styles/shiki-theme.css: Grimoire dark theme matching previous minimalistic style Updated components: - SyntaxHighlight: Now uses Shiki with graceful loading/error states - CodeSnippetRenderer/DetailRenderer: Simplified, removed manual language mapping - MarkdownContent: Removed type casts, any language now supported Removed: - prismjs and @types/prismjs dependencies - src/styles/prism-theme.css --- package-lock.json | 733 +++++++++++------- package.json | 3 +- src/components/SyntaxHighlight.tsx | 92 ++- src/components/nostr/MarkdownContent.tsx | 2 +- .../nostr/kinds/CodeSnippetDetailRenderer.tsx | 68 +- .../nostr/kinds/CodeSnippetRenderer.tsx | 54 +- src/hooks/useHighlightedCode.ts | 51 ++ src/index.css | 631 ++++----------- src/lib/shiki.ts | 375 +++++++++ src/styles/prism-theme.css | 144 ---- src/styles/shiki-theme.css | 81 ++ 11 files changed, 1148 insertions(+), 1086 deletions(-) create mode 100644 src/hooks/useHighlightedCode.ts create mode 100644 src/lib/shiki.ts delete mode 100644 src/styles/prism-theme.css create mode 100644 src/styles/shiki-theme.css diff --git a/package-lock.json b/package-lock.json index e9e2da0..60fae40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,6 @@ "js-yaml": "^4.1.1", "lucide-react": "latest", "media-chrome": "^4.17.2", - "prismjs": "^1.30.0", "qrcode": "^1.5.4", "react": "^19.2.1", "react-dom": "^19.2.1", @@ -73,6 +72,7 @@ "remark-gfm": "^4.0.1", "rxjs": "^7.8.1", "shell-quote": "^1.8.3", + "shiki": "^3.20.0", "sonner": "^2.0.7", "tailwind-merge": "^2.5.5", "tippy.js": "^6.3.7" @@ -85,7 +85,6 @@ "@testing-library/react": "^16.3.1", "@types/js-yaml": "^4.0.9", "@types/node": "^24.10.1", - "@types/prismjs": "^1.26.5", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@types/shell-quote": "^1.7.5", @@ -113,9 +112,9 @@ } }, "node_modules/@acemir/cssom": { - "version": "0.9.30", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", - "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", "dev": true, "license": "MIT" }, @@ -140,9 +139,9 @@ } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -164,9 +163,9 @@ } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -685,13 +684,14 @@ } }, "node_modules/@cashu/cashu-ts": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-3.2.2.tgz", - "integrity": "sha512-FD3EBYQiDRhZFwCMXuhAGRAb279WpGEWePzRQk58GJSZy16OdcP3hrYmj7L9wWdETy2fQU0wn+bCuw2NAB6szQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-3.3.0.tgz", + "integrity": "sha512-hHUOhjPLK77axDdj/4qO5mJ14rkh+rZGe1Gz2RbkW2j+SIglNbc2NsKSvjvoQcshupm02FudKi9Y3s3M8ZSYzg==", "license": "MIT", "dependencies": { "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", + "@scure/base": "^2.0.0", "@scure/bip32": "^2.0.1" }, "engines": { @@ -710,6 +710,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@cashu/cashu-ts/node_modules/@scure/base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", + "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", @@ -806,9 +815,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", - "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.26.tgz", + "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==", "dev": true, "funding": [ { @@ -820,10 +829,7 @@ "url": "https://opencollective.com/csstools" } ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } + "license": "MIT-0" }, "node_modules/@csstools/css-tokenizer": { "version": "3.0.4", @@ -1456,19 +1462,19 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.8.0.tgz", - "integrity": "sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.10.0.tgz", + "integrity": "sha512-tf8YdcbirXdPnJ+Nd4UN1EXnz+IP2DI45YVEr3vvzcVTOyrApkmIB4zvOQVd3XPr7RXnfBtAx+PXImXOIU0Ajg==", "dev": true, "license": "MIT", "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@exodus/crypto": "^1.0.0-rc.4" + "@noble/hashes": "^1.8.0 || ^2.0.0" }, "peerDependenciesMeta": { - "@exodus/crypto": { + "@noble/hashes": { "optional": true } } @@ -4859,6 +4865,73 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@shikijs/core": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.20.0.tgz", + "integrity": "sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.20.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.20.0.tgz", + "integrity": "sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.20.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.20.0.tgz", + "integrity": "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.20.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.20.0.tgz", + "integrity": "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.20.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.20.0.tgz", + "integrity": "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.20.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz", + "integrity": "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", @@ -5159,9 +5232,9 @@ } }, "node_modules/@testing-library/react": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.1.tgz", - "integrity": "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==", + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", "dev": true, "license": "MIT", "dependencies": { @@ -5187,48 +5260,48 @@ } }, "node_modules/@tiptap/core": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.15.3.tgz", - "integrity": "sha512-bmXydIHfm2rEtGju39FiQNfzkFx9CDvJe+xem1dgEZ2P6Dj7nQX9LnA1ZscW7TuzbBRkL5p3dwuBIi3f62A66A==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.18.0.tgz", + "integrity": "sha512-Gczd4GbK1DNgy/QUPElMVozoa0GW9mW8E31VIi7Q4a9PHHz8PcrxPmuWwtJ2q0PF8MWpOSLuBXoQTWaXZRPRnQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^3.15.3" + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-blockquote": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.15.3.tgz", - "integrity": "sha512-13x5UsQXtttFpoS/n1q173OeurNxppsdWgP3JfsshzyxIghhC141uL3H6SGYQLPU31AizgDs2OEzt6cSUevaZg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.18.0.tgz", + "integrity": "sha512-1HjEoM5vZDfFnq2OodNpW13s56a9pbl7jolUv1V9FrE3X5s7n0HCfDzIVpT7z1HgTdPtlN5oSt5uVyBwuwSUfA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-bold": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.15.3.tgz", - "integrity": "sha512-I8JYbkkUTNUXbHd/wCse2bR0QhQtJD7+0/lgrKOmGfv5ioLxcki079Nzuqqay3PjgYoJLIJQvm3RAGxT+4X91w==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.18.0.tgz", + "integrity": "sha512-xUgOvHCdGXh9Lfxd7DtgsSr0T/egIwBllWHIBWDjQEQQ0b+ICn+0+i703btHMB4hjdduZtgVDrhK8jAW3U6swA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.15.3.tgz", - "integrity": "sha512-e88DG1bTy6hKxrt7iPVQhJnH5/EOrnKpIyp09dfRDgWrrW88fE0Qjys7a/eT8W+sXyXM3z10Ye7zpERWsrLZDg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.18.0.tgz", + "integrity": "sha512-9kYG1fVYQcA3Kp5Bq96lrKCp9oLpQqceDsK688r7iT1yymQlBPMunaqaqb5ZLQGhnNYbhfG+8xcQsvEKjklErA==", "license": "MIT", "optional": true, "dependencies": { @@ -5239,80 +5312,80 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-bullet-list": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.15.3.tgz", - "integrity": "sha512-MGwEkNT7ltst6XaWf0ObNgpKQ4PvuuV3igkBrdYnQS+qaAx9IF4isygVPqUc9DvjYC306jpyKsNqNrENIXcosA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.18.0.tgz", + "integrity": "sha512-8sEpY0nxAGGFDYlF+WVFPKX00X2dAAjmoi0+2eWvK990PdQqwXrQsRs7pkUbpE2mDtATV8+GlDXk9KDkK/ZXhA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "^3.15.3" + "@tiptap/extension-list": "^3.18.0" } }, "node_modules/@tiptap/extension-code": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.15.3.tgz", - "integrity": "sha512-x6LFt3Og6MFINYpsMzrJnz7vaT9Yk1t4oXkbJsJRSavdIWBEBcoRudKZ4sSe/AnsYlRJs8FY2uR76mt9e+7xAQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.18.0.tgz", + "integrity": "sha512-0SU53O0NRmdtRM2Hgzm372dVoHjs2F40o/dtB7ls4kocf4W89FyWeC2R6ZsFQqcXisNh9RTzLtYfbNyizGuZIw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-code-block": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.15.3.tgz", - "integrity": "sha512-q1UB9icNfdJppTqMIUWfoRKkx5SSdWIpwZoL2NeOI5Ah3E20/dQKVttIgLhsE521chyvxCYCRaHD5tMNGKfhyw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.18.0.tgz", + "integrity": "sha512-fCx1oT95ikGfoizw+XCjeglQxlLK4lWgUcB4Dcn5TdaCoFBQMEaZs7Q0jVajxxxULnyArkg60uarc1ac/IF2Hw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-document": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.15.3.tgz", - "integrity": "sha512-AC72nI2gnogBuETCKbZekn+h6t5FGGcZG2abPGKbz/x9rwpb6qV2hcbAQ30t6M7H6cTOh2/Ut8bEV2MtMB15sw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.18.0.tgz", + "integrity": "sha512-e0hOGrjTMpCns8IC5p+c5CEiE1BBmFBFL+RpIxU/fjT2SaZ7q2xsFguBu94lQDT0cD6fdZokFRpGwEMxZNVGCg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-dropcursor": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.15.3.tgz", - "integrity": "sha512-jGI5XZpdo8GSYQFj7HY15/oEwC2m2TqZz0/Fln5qIhY32XlZhWrsMuMI6WbUJrTH16es7xO6jmRlDsc6g+vJWg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.18.0.tgz", + "integrity": "sha512-pIW/K9fGth221dkfA5SInHcqfnCr0aG9LGkRiEh4gwM4cf6ceUBrvcD+QlemSZ4q9oktNGJmXT+sEXVOQ8QoeQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "^3.15.3" + "@tiptap/extensions": "^3.18.0" } }, "node_modules/@tiptap/extension-floating-menu": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.15.3.tgz", - "integrity": "sha512-+3DVBleKKffadEJEdLYxmYAJOjHjLSqtiSFUE3RABT4V2ka1ODy2NIpyKX0o1SvQ5N1jViYT9Q+yUbNa6zCcDw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.18.0.tgz", + "integrity": "sha512-a2cBQi0I/X0o3a9b+adwJvkdxLzQzJIkP9dc/v25qGTSCjC1+ycois5WQOn8T4T8t4g/fAH1UOXEWnkWyTxLIg==", "license": "MIT", "optional": true, "funding": { @@ -5321,80 +5394,80 @@ }, "peerDependencies": { "@floating-ui/dom": "^1.0.0", - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.15.3.tgz", - "integrity": "sha512-Kaw0sNzP0bQI/xEAMSfIpja6xhsu9WqqAK/puzOIS1RKWO47Wps/tzqdSJ9gfslPIb5uY5mKCfy8UR8Xgiia8w==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.18.0.tgz", + "integrity": "sha512-covioXPPHX3SnlTwC/1rcHUHAc7/JFd4vN0kZQmZmvGHlxqq2dPmtrPh8D7TuDuhG0k/3Z6i8dJFP0phfRAhuA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "^3.15.3" + "@tiptap/extensions": "^3.18.0" } }, "node_modules/@tiptap/extension-hard-break": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.15.3.tgz", - "integrity": "sha512-8HjxmeRbBiXW+7JKemAJtZtHlmXQ9iji398CPQ0yYde68WbIvUhHXjmbJE5pxFvvQTJ/zJv1aISeEOZN2bKBaw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.18.0.tgz", + "integrity": "sha512-IXLiOHEmbU2Wn1jFRZC6apMxiJQvSRWhwoiubAvRxyiPSnFTeaEgT8Qgo5DjwB39NckP+o7XX7RrgzlkwdFPQQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-heading": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.15.3.tgz", - "integrity": "sha512-G1GG6iN1YXPS+75arDpo+bYRzhr3dNDw99c7D7na3aDawa9Qp7sZ/bVrzFUUcVEce0cD6h83yY7AooBxEc67hA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.18.0.tgz", + "integrity": "sha512-MTamVnYsFWVndLSq5PRQ7ZmbF6AExsFS9uIvGtUAwuhzvR4of/WHh6wpvWYjA+BLXTWRrfuGHaZTl7UXBN13fg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-horizontal-rule": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.15.3.tgz", - "integrity": "sha512-FYkN7L6JsfwwNEntmLklCVKvgL0B0N47OXMacRk6kYKQmVQ4Nvc7q/VJLpD9sk4wh4KT1aiCBfhKEBTu5pv1fg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.18.0.tgz", + "integrity": "sha512-fEq7DwwQZ496RHNbMQypBVNqoWnhDEERbzWMBqlmfCfc/0FvJrHtsQkk3k4lgqMYqmBwym3Wp0SrRYiyKCPGTw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-italic": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.15.3.tgz", - "integrity": "sha512-6XeuPjcWy7OBxpkgOV7bD6PATO5jhIxc8SEK4m8xn8nelGTBIbHGqK37evRv+QkC7E0MUryLtzwnmmiaxcKL0Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.18.0.tgz", + "integrity": "sha512-1C4nB08psiRo0BPxAbpYq8peUOKnjQWtBCLPbE6B9ToTK3vmUk0AZTqLO11FvokuM1GF5l2Lg3sKrKFuC2hcjQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-link": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.15.3.tgz", - "integrity": "sha512-PdDXyBF9Wco9U1x6e+b7tKBWG+kqBDXDmaYXHkFm/gYuQCQafVJ5mdrDdKgkHDWVnJzMWZXBcZjT9r57qtlLWg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.18.0.tgz", + "integrity": "sha512-1J28C4+fKAMQi7q/UsTjAmgmKTnzjExXY98hEBneiVzFDxqF69n7+Vb7nVTNAIhmmJkZMA0DEcMhSiQC/1/u4A==", "license": "MIT", "dependencies": { "linkifyjs": "^4.3.2" @@ -5404,161 +5477,161 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-list": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.15.3.tgz", - "integrity": "sha512-n7y/MF9lAM5qlpuH5IR4/uq+kJPEJpe9NrEiH+NmkO/5KJ6cXzpJ6F4U17sMLf2SNCq+TWN9QK8QzoKxIn50VQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.18.0.tgz", + "integrity": "sha512-9lQBo45HNqIFcLEHAk+CY3W51eMMxIJjWbthm2CwEWr4PB3+922YELlvq8JcLH1nVFkBVpmBFmQe/GxgnCkzwQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/extension-list-item": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.15.3.tgz", - "integrity": "sha512-CCxL5ek1p0lO5e8aqhnPzIySldXRSigBFk2fP9OLgdl5qKFLs2MGc19jFlx5+/kjXnEsdQTFbGY1Sizzt0TVDw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.18.0.tgz", + "integrity": "sha512-auTSt+NXoUnT0xofzFa+FnXsrW1TPdT1OB3U1OqQCIWkumZqL45A8OK9kpvyQsWj/xJ8fy1iZwFlKXPtxjLd2w==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "^3.15.3" + "@tiptap/extension-list": "^3.18.0" } }, "node_modules/@tiptap/extension-list-keymap": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.15.3.tgz", - "integrity": "sha512-UxqnTEEAKrL+wFQeSyC9z0mgyUUVRS2WTcVFoLZCE6/Xus9F53S4bl7VKFadjmqI4GpDk5Oe2IOUc72o129jWg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.18.0.tgz", + "integrity": "sha512-ZzO5r/cW7G0zpL/eM69WPnMpzb0YsSjtI60CYGA0iQDRJnK9INvxu0RU0ewM2faqqwASmtjuNJac+Fjk6scdXg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "^3.15.3" + "@tiptap/extension-list": "^3.18.0" } }, "node_modules/@tiptap/extension-mention": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-3.15.3.tgz", - "integrity": "sha512-4YpwiQyumKZrlfiw4ExDzrDRarC4kkaC7RjEl4kYhzutID1Zy1WLES1B0CoZN9wRds/mjrQjfCFE5HE+2g3D6w==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-3.18.0.tgz", + "integrity": "sha512-2obPAXksR4I2OwKZKYEoMwKGFEnsANlE83hAILNYGb5oSnDkHj8KHxQKcIutv6G25OLDTfMMh7VE/YUq2iempw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3", - "@tiptap/suggestion": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0", + "@tiptap/suggestion": "^3.18.0" } }, "node_modules/@tiptap/extension-ordered-list": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.15.3.tgz", - "integrity": "sha512-/8uhw528Iy0c9wF6tHCiIn0ToM0Ml6Ll2c/3iPRnKr4IjXwx2Lr994stUFihb+oqGZwV1J8CPcZJ4Ufpdqi4Dw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.18.0.tgz", + "integrity": "sha512-5bUAfklYLS5o6qvLLfreGyGvD1JKXqOQF0YntLyPuCGrXv7+XjPWQL2BmEf59fOn2UPT2syXLQ1WN5MHTArRzg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extension-list": "^3.15.3" + "@tiptap/extension-list": "^3.18.0" } }, "node_modules/@tiptap/extension-paragraph": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.15.3.tgz", - "integrity": "sha512-lc0Qu/1AgzcEfS67NJMj5tSHHhH6NtA6uUpvppEKGsvJwgE2wKG1onE4isrVXmcGRdxSMiCtyTDemPNMu6/ozQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.18.0.tgz", + "integrity": "sha512-uvFhdwiur4NhhUdBmDsajxjGAIlg5qga55fYag2DzOXxIQE2M7/aVMRkRpuJzb88GY4EHSh8rY34HgMK2FJt2Q==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-placeholder": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.15.3.tgz", - "integrity": "sha512-XcHHnojT186hKIoOgcPBesXk89+caNGVUdMtc171Vcr/5s0dpnr4q5LfE+YRC+S85CpCxCRRnh84Ou+XRtOqrw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-3.18.0.tgz", + "integrity": "sha512-jhN1Xa+MpfrTcCYZsFSvZYpUuMutPTC20ms0IsH1yN0y9tbAS+T6PHPC+dsvyAinYdA8yKElM6OO+jpyz4X1cw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/extensions": "^3.15.3" + "@tiptap/extensions": "^3.18.0" } }, "node_modules/@tiptap/extension-strike": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.15.3.tgz", - "integrity": "sha512-Y1P3eGNY7RxQs2BcR6NfLo9VfEOplXXHAqkOM88oowWWOE7dMNeFFZM9H8HNxoQgXJ7H0aWW9B7ZTWM9hWli2Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.18.0.tgz", + "integrity": "sha512-kl/fa68LZg8NWUqTkRTfgyCx+IGqozBmzJxQDc1zxurrIU+VFptDV9UuZim587sbM2KGjCi/PNPjPGk1Uu0PVg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-text": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.15.3.tgz", - "integrity": "sha512-MhkBz8ZvrqOKtKNp+ZWISKkLUlTrDR7tbKZc2OnNcUTttL9dz0HwT+cg91GGz19fuo7ttDcfsPV6eVmflvGToA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.18.0.tgz", + "integrity": "sha512-9TvctdnBCwK/zyTi9kS7nGFNl5OvGM8xE0u38ZmQw5t79JOqJHgOroyqMjw8LHK/1PWrozfNCmsZbpq4IZuKXw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extension-underline": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.15.3.tgz", - "integrity": "sha512-r/IwcNN0W366jGu4Y0n2MiFq9jGa4aopOwtfWO4d+J0DyeS2m7Go3+KwoUqi0wQTiVU74yfi4DF6eRsMQ9/iHQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.18.0.tgz", + "integrity": "sha512-009IeXURNJ/sm1pBqbj+2YQgjQaBtNlJR3dbl6xu49C+qExqCmI7klhKQuwsVVGLR7ahsYlp7d9RlftnhCXIcQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3" + "@tiptap/core": "^3.18.0" } }, "node_modules/@tiptap/extensions": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.15.3.tgz", - "integrity": "sha512-ycx/BgxR4rc9tf3ZyTdI98Z19yKLFfqM3UN+v42ChuIwkzyr9zyp7kG8dB9xN2lNqrD+5y/HyJobz/VJ7T90gA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.18.0.tgz", + "integrity": "sha512-uSRIE9HGshBN6NRFR3LX2lZqBLvX92SgU5A9AvUbJD4MqU63E+HdruJnRjsVlX3kPrmbIDowxrzXlUcg3K0USQ==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@tiptap/pm": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.15.3.tgz", - "integrity": "sha512-Zm1BaU1TwFi3CQiisxjgnzzIus+q40bBKWLqXf6WEaus8Z6+vo1MT2pU52dBCMIRaW9XNDq3E5cmGtMc1AlveA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.18.0.tgz", + "integrity": "sha512-8RoI5gW0xBVCsuxahpK8vx7onAw6k2/uR3hbGBBnH+HocDMaAZKot3nTyY546ij8ospIC1mnQ7k4BhVUZesZDQ==", "license": "MIT", "dependencies": { "prosemirror-changeset": "^2.3.0", @@ -5586,9 +5659,9 @@ } }, "node_modules/@tiptap/react": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.15.3.tgz", - "integrity": "sha512-XvouB+Hrqw8yFmZLPEh+HWlMeRSjZfHSfWfWuw5d8LSwnxnPeu3Bg/rjHrRrdwb+7FumtzOnNWMorpb/PSOttQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.18.0.tgz", + "integrity": "sha512-VC20YhoiWe2E03D1BRH+AVMgXeA7li+bzIoaBtpK9+AdizAC+TvWCb2I/9mQCy9m31zGYTD0vv0e7bVlJi+aKA==", "license": "MIT", "dependencies": { "@types/use-sync-external-store": "^0.0.6", @@ -5600,12 +5673,12 @@ "url": "https://github.com/sponsors/ueberdosis" }, "optionalDependencies": { - "@tiptap/extension-bubble-menu": "^3.15.3", - "@tiptap/extension-floating-menu": "^3.15.3" + "@tiptap/extension-bubble-menu": "^3.18.0", + "@tiptap/extension-floating-menu": "^3.18.0" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3", + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", @@ -5613,35 +5686,35 @@ } }, "node_modules/@tiptap/starter-kit": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.15.3.tgz", - "integrity": "sha512-ia+eQr9Mt1ln2UO+kK4kFTJOrZK4GhvZXFjpCCYuHtco3rhr2fZAIxEEY4cl/vo5VO5WWyPqxhkFeLcoWmNjSw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.18.0.tgz", + "integrity": "sha512-LctpCelqI/5nHEeZgCPiwI1MmTjGr6YCIBGWmS5s4DJE7NfevEkwomR/C05QKdVUwPhpCXIMeS1+h/RYqRo1KA==", "license": "MIT", "dependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/extension-blockquote": "^3.15.3", - "@tiptap/extension-bold": "^3.15.3", - "@tiptap/extension-bullet-list": "^3.15.3", - "@tiptap/extension-code": "^3.15.3", - "@tiptap/extension-code-block": "^3.15.3", - "@tiptap/extension-document": "^3.15.3", - "@tiptap/extension-dropcursor": "^3.15.3", - "@tiptap/extension-gapcursor": "^3.15.3", - "@tiptap/extension-hard-break": "^3.15.3", - "@tiptap/extension-heading": "^3.15.3", - "@tiptap/extension-horizontal-rule": "^3.15.3", - "@tiptap/extension-italic": "^3.15.3", - "@tiptap/extension-link": "^3.15.3", - "@tiptap/extension-list": "^3.15.3", - "@tiptap/extension-list-item": "^3.15.3", - "@tiptap/extension-list-keymap": "^3.15.3", - "@tiptap/extension-ordered-list": "^3.15.3", - "@tiptap/extension-paragraph": "^3.15.3", - "@tiptap/extension-strike": "^3.15.3", - "@tiptap/extension-text": "^3.15.3", - "@tiptap/extension-underline": "^3.15.3", - "@tiptap/extensions": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/extension-blockquote": "^3.18.0", + "@tiptap/extension-bold": "^3.18.0", + "@tiptap/extension-bullet-list": "^3.18.0", + "@tiptap/extension-code": "^3.18.0", + "@tiptap/extension-code-block": "^3.18.0", + "@tiptap/extension-document": "^3.18.0", + "@tiptap/extension-dropcursor": "^3.18.0", + "@tiptap/extension-gapcursor": "^3.18.0", + "@tiptap/extension-hard-break": "^3.18.0", + "@tiptap/extension-heading": "^3.18.0", + "@tiptap/extension-horizontal-rule": "^3.18.0", + "@tiptap/extension-italic": "^3.18.0", + "@tiptap/extension-link": "^3.18.0", + "@tiptap/extension-list": "^3.18.0", + "@tiptap/extension-list-item": "^3.18.0", + "@tiptap/extension-list-keymap": "^3.18.0", + "@tiptap/extension-ordered-list": "^3.18.0", + "@tiptap/extension-paragraph": "^3.18.0", + "@tiptap/extension-strike": "^3.18.0", + "@tiptap/extension-text": "^3.18.0", + "@tiptap/extension-underline": "^3.18.0", + "@tiptap/extensions": "^3.18.0", + "@tiptap/pm": "^3.18.0" }, "funding": { "type": "github", @@ -5649,17 +5722,17 @@ } }, "node_modules/@tiptap/suggestion": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.15.3.tgz", - "integrity": "sha512-+CbaHhPfKUe+fNpUIQaOPhh6xI+xL5jbK1zw++U+CZIRrVAAmHRhO+D0O2HdiE1RK7596y8bRqMiB2CRHF7emA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.18.0.tgz", + "integrity": "sha512-AxJfM34e6wFPKVsfyXSvHN1wBBiXIm65hUmY+newop+DMeOjsvkO7M6j7tzUR2Nnrh1AQEsVr6iR0UzO91PBSA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.15.3", - "@tiptap/pm": "^3.15.3" + "@tiptap/core": "^3.18.0", + "@tiptap/pm": "^3.18.0" } }, "node_modules/@types/aria-query": { @@ -5825,13 +5898,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/@types/prismjs": { - "version": "1.26.5", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", - "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/qrcode": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.6.tgz", @@ -6445,9 +6511,9 @@ } }, "node_modules/applesauce-actions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/applesauce-actions/-/applesauce-actions-5.0.0.tgz", - "integrity": "sha512-Lw9x3P3+p9udmA9BvAssJDasDr+eIXq22SBwS3D6kt+3TOnBmJqONR3ru6K3j5S5MflYsiiy66b4TcATrBOXgQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/applesauce-actions/-/applesauce-actions-5.0.2.tgz", + "integrity": "sha512-ctdx2m4H0biItXBCefJwhwla2XTOsaJvMm9RmGebfYoVKr/NQQ3UROHCZFtgmsrYz/OCYooC2EpNFlLj8fTYOA==", "license": "MIT", "dependencies": { "applesauce-common": "^5.0.0", @@ -6500,9 +6566,9 @@ } }, "node_modules/applesauce-core": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/applesauce-core/-/applesauce-core-5.0.0.tgz", - "integrity": "sha512-l41CGztEakxAl8nk3KhaHrf7LLIe7+6tfDF1gC5mLnfSpV9raEsUUlmhE+t0AzQPmoEmyUPiWzc32KeP/u85YA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/applesauce-core/-/applesauce-core-5.0.3.tgz", + "integrity": "sha512-ErhWsRlR7Q6of1bjtWSWLza51HHv3Hqk3Vhfe8IHsPoVma8wvj4ES35sPHapdoXLSIz25Qe9szwuO4j3NUd1uw==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -6518,9 +6584,9 @@ } }, "node_modules/applesauce-loaders": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/applesauce-loaders/-/applesauce-loaders-5.0.0.tgz", - "integrity": "sha512-iu06vscZyaA+tA5cndMrKBsmYk1wLucwP5Gb0n0GmAAKeG58SPIIR8lEJhfKoVGlDoV65jiurVml7X5e9TNq0Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/applesauce-loaders/-/applesauce-loaders-5.0.2.tgz", + "integrity": "sha512-ia+0SD0iPklAAkweFnxyp9SXIyfyxKsK7SGa1ZoDu5Q6ZRZzMSijP+NhIdCawNH/eYym8930y1OO00Jj3pUifQ==", "license": "MIT", "dependencies": { "applesauce-core": "^5.0.0", @@ -6760,29 +6826,26 @@ } }, "node_modules/blossom-client-sdk/node_modules/@cashu/cashu-ts": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-2.8.1.tgz", - "integrity": "sha512-4HO3LC3VqiMs0K7ccQdfSs3l1wJNL0VuE8ZQ6zAfMsoeKRwswA1eC5BaGFrEDv7PcPqjliE/RBRw3+1Hz/SmsA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-2.9.0.tgz", + "integrity": "sha512-UesYcBkkJAGPbob2I/SX0aht4MQlfxUVPzI+NQqLKSg2l3m0EnmMznvnXZQnDZnhGy0Hd6rkgwAJTVOYcr0v/Q==", "license": "MIT", "dependencies": { - "@noble/curves": "^1.9.5", - "@noble/hashes": "^1.5.0", + "@noble/curves": "^2.0.1", + "@noble/hashes": "^2.0.1", "@scure/bip32": "^1.5.0" }, "engines": { "node": ">=22.4.0" } }, - "node_modules/blossom-client-sdk/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "node_modules/blossom-client-sdk/node_modules/@cashu/cashu-ts/node_modules/@noble/hashes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, "engines": { - "node": "^14.21.3 || >=16" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -6802,6 +6865,21 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/blossom-client-sdk/node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -6928,9 +7006,9 @@ "license": "MIT" }, "node_modules/cborg": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.3.2.tgz", - "integrity": "sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A==", + "version": "4.5.8", + "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.5.8.tgz", + "integrity": "sha512-6/viltD51JklRhq4L7jC3zgy6gryuG5xfZ3kzpE+PravtyeQLeQmCYLREhQH7pWENg5pY4Yu/XCd6a7dKScVlw==", "license": "Apache-2.0", "bin": { "cborg": "lib/bin.js" @@ -7250,9 +7328,9 @@ } }, "node_modules/cssstyle": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.6.tgz", - "integrity": "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", + "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7266,9 +7344,9 @@ } }, "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -7288,27 +7366,27 @@ "license": "MIT" }, "node_modules/data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.1.tgz", + "integrity": "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==", "dev": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^15.1.0" }, "engines": { "node": ">=20" } }, "node_modules/data-urls/node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/date-fns": { @@ -7517,10 +7595,9 @@ } }, "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -8197,37 +8274,23 @@ "license": "MIT" }, "node_modules/happy-dom": { - "version": "20.0.11", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.0.11.tgz", - "integrity": "sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.4.0.tgz", + "integrity": "sha512-RDeQm3dT9n0A5f/TszjUmNCLEuPnMGv3Tv4BmNINebz/h17PA6LMBcxJ5FrcqltNBMh9jA/8ufgDdBYUdBt+eg==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "^20.0.0", + "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", - "whatwg-mimetype": "^3.0.0" + "@types/ws": "^8.18.1", + "entities": "^4.5.0", + "whatwg-mimetype": "^3.0.0", + "ws": "^8.18.3" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/happy-dom/node_modules/@types/node": { - "version": "20.19.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", - "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/happy-dom/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8257,6 +8320,29 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", @@ -8369,6 +8455,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -9208,18 +9304,6 @@ "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/markdown-it/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -10394,6 +10478,23 @@ ], "license": "MIT" }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -10530,6 +10631,19 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10728,15 +10842,6 @@ "dev": true, "license": "MIT" }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/proc-log": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", @@ -10874,9 +10979,9 @@ } }, "node_modules/prosemirror-markdown": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz", - "integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.3.tgz", + "integrity": "sha512-3E+Et6cdXIH0EgN2tGYQ+EBT7N4kMiZFsW+hzx+aPtOmADDHWCdd2uUQb7yklJrfUYUOjEEu22BiN6UFgPe4cQ==", "license": "MIT", "dependencies": { "@types/markdown-it": "^14.0.0", @@ -10965,18 +11070,18 @@ } }, "node_modules/prosemirror-transform": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.5.tgz", - "integrity": "sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz", + "integrity": "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.21.0" } }, "node_modules/prosemirror-view": { - "version": "1.41.4", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.4.tgz", - "integrity": "sha512-WkKgnyjNncri03Gjaz3IFWvCAE94XoiEgvtr0/r2Xw7R8/IjK3sKLSiDoCHWcsXSAinVaKlGRZDvMCsF1kbzjA==", + "version": "1.41.5", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.5.tgz", + "integrity": "sha512-UDQbIPnDrjE8tqUBbPmCOZgtd75htE6W3r0JCmY9bL6W1iemDM37MZEKC49d+tdQ0v/CKx4gjxLoLsfkD2NiZA==", "license": "MIT", "dependencies": { "prosemirror-model": "^1.20.0", @@ -11370,6 +11475,30 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, "node_modules/remark": { "version": "15.0.1", "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", @@ -11678,6 +11807,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shiki": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.20.0.tgz", + "integrity": "sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.20.0", + "@shikijs/engine-javascript": "3.20.0", + "@shikijs/engine-oniguruma": "3.20.0", + "@shikijs/langs": "3.20.0", + "@shikijs/themes": "3.20.0", + "@shikijs/types": "3.20.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -12940,9 +13085,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 8587bbc..d2ec65b 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,6 @@ "js-yaml": "^4.1.1", "lucide-react": "latest", "media-chrome": "^4.17.2", - "prismjs": "^1.30.0", "qrcode": "^1.5.4", "react": "^19.2.1", "react-dom": "^19.2.1", @@ -82,6 +81,7 @@ "remark-gfm": "^4.0.1", "rxjs": "^7.8.1", "shell-quote": "^1.8.3", + "shiki": "^3.20.0", "sonner": "^2.0.7", "tailwind-merge": "^2.5.5", "tippy.js": "^6.3.7" @@ -93,7 +93,6 @@ "@testing-library/react": "^16.3.1", "@types/js-yaml": "^4.0.9", "@types/node": "^24.10.1", - "@types/prismjs": "^1.26.5", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@types/shell-quote": "^1.7.5", diff --git a/src/components/SyntaxHighlight.tsx b/src/components/SyntaxHighlight.tsx index df2db8c..e89316e 100644 --- a/src/components/SyntaxHighlight.tsx +++ b/src/components/SyntaxHighlight.tsx @@ -1,45 +1,24 @@ -import { useEffect, useRef } from "react"; -import Prism from "prismjs"; - -// Core languages -import "prismjs/components/prism-diff"; -import "prismjs/components/prism-javascript"; -import "prismjs/components/prism-typescript"; -import "prismjs/components/prism-jsx"; -import "prismjs/components/prism-tsx"; -import "prismjs/components/prism-bash"; -import "prismjs/components/prism-json"; -import "prismjs/components/prism-markdown"; -import "prismjs/components/prism-css"; -import "prismjs/components/prism-python"; -import "prismjs/components/prism-yaml"; +import { useHighlightedCode } from "@/hooks/useHighlightedCode"; +import { cn } from "@/lib/utils"; interface SyntaxHighlightProps { code: string; - language: - | "diff" - | "javascript" - | "typescript" - | "jsx" - | "tsx" - | "bash" - | "shell" - | "json" - | "markdown" - | "css" - | "python" - | "yaml"; + language?: string | null; className?: string; showLineNumbers?: boolean; } /** - * Syntax highlighting component using Prism.js - * Matches Grimoire's dark theme using CSS custom properties + * Syntax highlighting component using Shiki with lazy language loading + * + * Languages are loaded on-demand - the first render of a new language + * will show a brief loading state while the grammar is fetched. * * @example * ```tsx * + * + * * ``` */ export function SyntaxHighlight({ @@ -48,26 +27,45 @@ export function SyntaxHighlight({ className = "", showLineNumbers = false, }: SyntaxHighlightProps) { - const codeRef = useRef(null); + const { html, loading, error } = useHighlightedCode(code, language); - // Normalize language aliases - const normalizedLanguage = language === "shell" ? "bash" : language; + // Loading state - show code without highlighting + if (loading) { + return ( +
+        {code}
+      
+ ); + } - useEffect(() => { - // Check for browser environment (SSR safety) - if (typeof window === "undefined" || !codeRef.current) return; - - // Highlight the code element - Prism.highlightElement(codeRef.current); - }, [code, normalizedLanguage]); + // Error state - fallback to plain code + if (error || !html) { + return ( +
+        {code}
+      
+ ); + } + // Render highlighted HTML return ( -
-      
-        {code}
-      
-    
+
); } diff --git a/src/components/nostr/MarkdownContent.tsx b/src/components/nostr/MarkdownContent.tsx index 8838598..e0f087e 100644 --- a/src/components/nostr/MarkdownContent.tsx +++ b/src/components/nostr/MarkdownContent.tsx @@ -135,7 +135,7 @@ function CodeBlock({ return (
{language ? ( - + ) : (
 {
-    if (!language) return null;
-    const lang = language.toLowerCase();
-
-    // Map common language names to Prism identifiers
-    const languageMap: Record = {
-      js: "javascript",
-      ts: "typescript",
-      py: "python",
-      sh: "bash",
-      shell: "bash",
-      yml: "yaml",
-    };
-
-    const mapped = languageMap[lang] || lang;
-
-    // Check if it's a supported language
-    const supported = [
-      "javascript",
-      "typescript",
-      "jsx",
-      "tsx",
-      "bash",
-      "json",
-      "markdown",
-      "css",
-      "python",
-      "yaml",
-      "diff",
-    ];
-
-    return supported.includes(mapped) ? mapped : null;
-  }, [language]);
-
   return (
     
{/* Header */} @@ -195,29 +160,16 @@ export function Kind1337DetailRenderer({ event }: Kind1337DetailRendererProps) { {/* Code Section */}
- {normalizedLanguage ? ( - <> - - - - ) : ( -
-            
-            {event.content}
-          
- )} + +
); diff --git a/src/components/nostr/kinds/CodeSnippetRenderer.tsx b/src/components/nostr/kinds/CodeSnippetRenderer.tsx index c542d59..d9ca145 100644 --- a/src/components/nostr/kinds/CodeSnippetRenderer.tsx +++ b/src/components/nostr/kinds/CodeSnippetRenderer.tsx @@ -11,58 +11,6 @@ import { import { Label } from "@/components/ui/label"; import { SyntaxHighlight } from "@/components/SyntaxHighlight"; -// Map common language names to Prism-supported languages -function mapLanguage( - lang: string | null | undefined, -): - | "javascript" - | "typescript" - | "jsx" - | "tsx" - | "bash" - | "json" - | "markdown" - | "css" - | "python" - | "yaml" - | "diff" { - if (!lang) return "javascript"; - - const normalized = lang.toLowerCase(); - - // Direct matches - if ( - [ - "javascript", - "typescript", - "jsx", - "tsx", - "bash", - "json", - "markdown", - "css", - "python", - "yaml", - "diff", - ].includes(normalized) - ) { - return normalized as any; - } - - // Common aliases - const aliases: Record = { - js: "javascript", - ts: "typescript", - sh: "bash", - shell: "bash", - py: "python", - md: "markdown", - yml: "yaml", - }; - - return (aliases[normalized] as any) || "javascript"; -} - /** * Renderer for Kind 1337 - Code Snippet (NIP-C0) * Displays code snippet name, language, description, and preview in feed @@ -109,7 +57,7 @@ export function Kind1337Renderer({ event }: BaseEventProps) {
diff --git a/src/hooks/useHighlightedCode.ts b/src/hooks/useHighlightedCode.ts new file mode 100644 index 0000000..85ad38f --- /dev/null +++ b/src/hooks/useHighlightedCode.ts @@ -0,0 +1,51 @@ +import { useState, useEffect } from "react"; +import { highlightCode } from "@/lib/shiki"; + +interface UseHighlightedCodeResult { + html: string | null; + loading: boolean; + error: Error | null; +} + +/** + * Hook to highlight code asynchronously with lazy language loading + * + * @example + * const { html, loading } = useHighlightedCode(code, "typescript") + * if (loading) return
{code}
+ * return
+ */ +export function useHighlightedCode( + code: string, + language: string | null | undefined, +): UseHighlightedCodeResult { + const [html, setHtml] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + setLoading(true); + setError(null); + + highlightCode(code, language) + .then((result) => { + if (!cancelled) { + setHtml(result); + setLoading(false); + } + }) + .catch((err) => { + if (!cancelled) { + setError(err instanceof Error ? err : new Error(String(err))); + setLoading(false); + } + }); + + return () => { + cancelled = true; + }; + }, [code, language]); + + return { html, loading, error }; +} diff --git a/src/index.css b/src/index.css index 0bbb5a2..cec4235 100644 --- a/src/index.css +++ b/src/index.css @@ -1,8 +1,8 @@ /* Tailwind CSS v4 - CSS-first configuration */ @import "tailwindcss"; -/* Prism syntax highlighting theme */ -@import "./styles/prism-theme.css"; +/* Shiki syntax highlighting theme */ +@import "./styles/shiki-theme.css"; /* ========================================================================== Theme Configuration (@theme) @@ -45,562 +45,219 @@ @keyframes skeleton-pulse { 0%, 100% { - opacity: 1; + opacity: 0.4; } 50% { - opacity: 0.5; + opacity: 0.7; } } - /* ========================================================================== - Color Tokens - These map runtime CSS variables (set by ThemeProvider) to Tailwind colors. - The runtime variables use HSL values WITHOUT the hsl() wrapper. - ========================================================================== */ - - /* Core Colors */ + /* Colors - Map Tailwind utilities to CSS variables */ --color-background: hsl(var(--background)); --color-foreground: hsl(var(--foreground)); - - /* Card */ --color-card: hsl(var(--card)); --color-card-foreground: hsl(var(--card-foreground)); - - /* Popover */ --color-popover: hsl(var(--popover)); --color-popover-foreground: hsl(var(--popover-foreground)); - - /* Primary */ --color-primary: hsl(var(--primary)); --color-primary-foreground: hsl(var(--primary-foreground)); - - /* Secondary */ --color-secondary: hsl(var(--secondary)); --color-secondary-foreground: hsl(var(--secondary-foreground)); - - /* Accent */ - --color-accent: hsl(var(--accent)); - --color-accent-foreground: hsl(var(--accent-foreground)); - - /* Muted */ --color-muted: hsl(var(--muted)); --color-muted-foreground: hsl(var(--muted-foreground)); - - /* Destructive */ + --color-accent: hsl(var(--accent)); + --color-accent-foreground: hsl(var(--accent-foreground)); --color-destructive: hsl(var(--destructive)); --color-destructive-foreground: hsl(var(--destructive-foreground)); - - /* Form Elements */ --color-border: hsl(var(--border)); --color-input: hsl(var(--input)); --color-ring: hsl(var(--ring)); - - /* Status Colors */ - --color-success: hsl(var(--success)); - --color-warning: hsl(var(--warning)); - --color-info: hsl(var(--info)); - - /* Nostr-specific Colors */ - --color-zap: hsl(var(--zap)); - --color-live: hsl(var(--live)); - --color-highlight: hsl(var(--highlight)); - - /* Tooltip */ - --color-tooltip: hsl(var(--tooltip)); - --color-tooltip-foreground: hsl(var(--tooltip-foreground)); + --color-sidebar: hsl(var(--sidebar)); + --color-sidebar-foreground: hsl(var(--sidebar-foreground)); + --color-sidebar-primary: hsl(var(--sidebar-primary)); + --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground)); + --color-sidebar-accent: hsl(var(--sidebar-accent)); + --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground)); + --color-sidebar-border: hsl(var(--sidebar-border)); + --color-sidebar-ring: hsl(var(--sidebar-ring)); + --color-chart-1: hsl(var(--chart-1)); + --color-chart-2: hsl(var(--chart-2)); + --color-chart-3: hsl(var(--chart-3)); + --color-chart-4: hsl(var(--chart-4)); + --color-chart-5: hsl(var(--chart-5)); } /* ========================================================================== - Runtime Theme Variables - These are HSL values WITHOUT the hsl() wrapper, allowing alpha transparency. - Set dynamically by ThemeProvider via applyTheme(). - ========================================================================== */ - -:root { - /* Core colors - light theme defaults (overridden by ThemeProvider) */ - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; - --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; - --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - --primary: 222.2 47.4% 11.2%; - --primary-foreground: 210 40% 98%; - --secondary: 210 40% 96.1%; - --secondary-foreground: 222.2 47.4% 11.2%; - --muted: 210 40% 96.1%; - --muted-foreground: 215.4 16.3% 46.9%; - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 210 40% 98%; - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 222.2 84% 4.9%; - --radius: 0.5rem; - - /* Status colors */ - --success: 142 76% 36%; - --warning: 45 93% 47%; - --info: 199 89% 48%; - - /* Nostr-specific colors */ - --zap: 45 93% 40%; - --live: 0 72% 45%; - - /* UI highlight (active user, self-references) */ - --highlight: 25 90% 35%; - - /* Tooltip colors */ - --tooltip: 222.2 47.4% 11.2%; - --tooltip-foreground: 210 40% 98%; - - /* Syntax highlighting */ - --syntax-comment: 215.4 16.3% 46.9%; - --syntax-punctuation: 222.2 84% 30%; - --syntax-property: 222.2 47.4% 11.2%; - --syntax-string: 142 60% 30%; - --syntax-keyword: 270 80% 50%; - --syntax-function: 222.2 47.4% 11.2%; - --syntax-variable: 222.2 84% 4.9%; - --syntax-operator: 222.2 84% 20%; - - /* Diff colors */ - --diff-inserted: 142 60% 30%; - --diff-inserted-bg: 142 60% 50% / 0.15; - --diff-deleted: 0 70% 45%; - --diff-deleted-bg: 0 70% 50% / 0.15; - --diff-meta: 199 80% 40%; - --diff-meta-bg: 199 80% 50% / 0.1; - - /* Scrollbar */ - --scrollbar-thumb: 222.2 84% 4.9% / 0.2; - --scrollbar-thumb-hover: 222.2 84% 4.9% / 0.3; - --scrollbar-track: 0 0% 0% / 0; - - /* Gradient colors (RGB values) */ - --gradient-1: 234 179 8; - --gradient-2: 249 115 22; - --gradient-3: 147 51 234; - --gradient-4: 6 182 212; -} - -/* Dark theme - applied via .dark class or ThemeProvider */ -.dark { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - --primary: 210 40% 98%; - --primary-foreground: 222.2 47.4% 11.2%; - --secondary: 217.2 32.6% 17.5%; - --secondary-foreground: 210 40% 98%; - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 70%; - --accent: 270 100% 70%; - --accent-foreground: 222.2 84% 4.9%; - --destructive: 0 75% 75%; - --destructive-foreground: 210 40% 98%; - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 212.7 26.8% 83.9%; - - /* Status colors */ - --success: 142 76% 46%; - --warning: 38 92% 60%; - --info: 199 89% 58%; - - /* Nostr-specific colors */ - --zap: 45 93% 58%; - --live: 0 72% 51%; - - /* UI highlight (active user, self-references) */ - --highlight: 27 96% 61%; - - /* Tooltip colors */ - --tooltip: 217.2 32.6% 30%; - --tooltip-foreground: 210 40% 98%; - - /* Syntax highlighting */ - --syntax-comment: 215 20.2% 70%; - --syntax-punctuation: 210 40% 70%; - --syntax-property: 210 40% 98%; - --syntax-string: 215 20.2% 70%; - --syntax-keyword: 210 40% 98%; - --syntax-function: 210 40% 98%; - --syntax-variable: 210 40% 98%; - --syntax-operator: 210 40% 98%; - - /* Diff colors */ - --diff-inserted: 134 60% 76%; - --diff-inserted-bg: 145 63% 42% / 0.1; - --diff-deleted: 0 100% 76%; - --diff-deleted-bg: 0 100% 60% / 0.1; - --diff-meta: 190 77% 70%; - --diff-meta-bg: 190 77% 70% / 0.08; - - /* Scrollbar */ - --scrollbar-thumb: 0 0% 100% / 0.2; - --scrollbar-thumb-hover: 0 0% 100% / 0.3; - --scrollbar-track: 0 0% 0% / 0; - - /* Gradient colors (RGB values) */ - --gradient-1: 250 204 21; - --gradient-2: 251 146 60; - --gradient-3: 168 85 247; - --gradient-4: 34 211 238; -} - -/* ========================================================================== - Custom Scrollbar Styling - ========================================================================== */ - -* { - scrollbar-width: thin; - scrollbar-color: hsl(var(--scrollbar-thumb)) hsl(var(--scrollbar-track)); -} - -*::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -*::-webkit-scrollbar-track { - background: hsl(var(--scrollbar-track)); -} - -*::-webkit-scrollbar-thumb { - background-color: hsl(var(--scrollbar-thumb)); - border-radius: 4px; -} - -*::-webkit-scrollbar-thumb:hover { - background-color: hsl(var(--scrollbar-thumb-hover)); -} - -/* ========================================================================== - Base Layer - Global Styles + Base Styles (@layer base) + These are low-specificity foundational styles. ========================================================================== */ @layer base { * { @apply border-border; } + body { - @apply bg-background text-foreground font-mono; - /* iOS PWA safe area insets for notch support */ - padding-top: env(safe-area-inset-top, 0); - padding-right: env(safe-area-inset-right, 0); - padding-bottom: env(safe-area-inset-bottom, 0); - padding-left: env(safe-area-inset-left, 0); + @apply bg-background text-foreground; + } + + :root { + color-scheme: light; + --radius: 0.5rem; + } + + .dark { + color-scheme: dark; + } + + /* Force hardware acceleration for smooth scrolling */ + .hardware-accelerated { + transform: translateZ(0); + will-change: transform; + backface-visibility: hidden; } } /* ========================================================================== - Custom Utilities (v4 @utility syntax) + Theme Variables + Runtime CSS variables that power the design system. + These are toggled by adding/removing the .dark class on . ========================================================================== */ -@utility no-scrollbar { - -ms-overflow-style: none !important; - scrollbar-width: none !important; - - &::-webkit-scrollbar { - display: none !important; - width: 0 !important; - height: 0 !important; - } +:root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --sidebar: 0 0% 98%; + --sidebar-foreground: 0 0% 9%; + --sidebar-primary: 0 0% 9%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 0 0% 94%; + --sidebar-accent-foreground: 0 0% 9%; + --sidebar-border: 0 0% 89%; + --sidebar-ring: 0 0% 3.9%; } -@utility hide-scrollbar { - -ms-overflow-style: none !important; - scrollbar-width: none !important; - - &::-webkit-scrollbar { - display: none !important; - width: 0 !important; - height: 0 !important; - } -} - -@utility text-grimoire-gradient { - background: linear-gradient( - to bottom, - rgb(var(--gradient-1)), - rgb(var(--gradient-2)), - rgb(var(--gradient-3)), - rgb(var(--gradient-4)) - ); - background-clip: text; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; +.dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --sidebar: 0 0% 5%; + --sidebar-foreground: 0 0% 98%; + --sidebar-primary: 0 0% 98%; + --sidebar-primary-foreground: 0 0% 9%; + --sidebar-accent: 0 0% 12%; + --sidebar-accent-foreground: 0 0% 98%; + --sidebar-border: 0 0% 14.9%; + --sidebar-ring: 0 0% 83.1%; } /* ========================================================================== - Third-Party Component Overrides + Component Styles ========================================================================== */ -/* react-medium-image-zoom theme customization */ -[data-rmiz-modal-overlay] { - background-color: hsl(var(--background) / 0.92) !important; +/* Custom scrollbar for dark theme */ +.dark ::-webkit-scrollbar { + width: 8px; + height: 8px; } -[data-rmiz-modal-content] { - box-shadow: 0 0 40px hsl(var(--foreground) / 0.2); -} - -/* ========================================================================== - React Mosaic Theme Customization - ========================================================================== */ - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme { +.dark ::-webkit-scrollbar-track { background: hsl(var(--background)); } -/* Smooth animations for window resizing and repositioning */ -/* Only animate during preset application, not manual resize/drag */ -body.animating-layout - .mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-tile { - transition: - width 150ms cubic-bezier(0.25, 0.1, 0.25, 1), - height 150ms cubic-bezier(0.25, 0.1, 0.25, 1), - top 150ms cubic-bezier(0.25, 0.1, 0.25, 1), - left 150ms cubic-bezier(0.25, 0.1, 0.25, 1); - contain: layout; /* Isolate layout calculations for better performance */ -} - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window - .mosaic-window-toolbar { +.dark ::-webkit-scrollbar-thumb { background: hsl(var(--muted)); - border: none; - border-bottom: 1px solid hsl(var(--border)); - border-radius: 0; - color: hsl(var(--foreground)); - height: 30px; + border-radius: 4px; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window - .mosaic-window-title { - color: hsl(var(--foreground)); - font-family: inherit; +.dark ::-webkit-scrollbar-thumb:hover { + background: hsl(var(--muted-foreground) / 0.5); } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-window { - background: hsl(var(--background)); - outline: none; - border-radius: 0 !important; +/* Mosaic component overrides */ +.mosaic-root { + background: transparent !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-window * { - border-radius: 0 !important; +.mosaic-tile { + margin: 2px !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-window::before, -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-window::after { - display: none; +.mosaic-window { + border-radius: var(--radius) !important; + overflow: hidden; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme.bp4-dark .mosaic-window, -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme.bp4-dark .mosaic-preview { - box-shadow: none; +.mosaic-window-toolbar { + display: none !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window - .mosaic-window-body { - background: hsl(var(--background)); - color: hsl(var(--foreground)); +.mosaic-window-body { + background: transparent !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-window-controls { - color: hsl(var(--muted-foreground)); +.mosaic-split { + background: transparent !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window-controls:hover { - color: hsl(var(--foreground)); +.mosaic-split:hover { + background: hsl(var(--primary) / 0.2) !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window-toolbar - .separator { - border-left: 1px solid hsl(var(--border)); +.mosaic-split.-row { + margin: 0 -2px !important; + width: 6px !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme - .mosaic-window-body-overlay { - background: hsl(var(--background)); +.mosaic-split.-column { + margin: -2px 0 !important; + height: 6px !important; } -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-preview { - background: hsl(var(--accent) / 0.3); - border: 2px solid hsl(var(--primary)); - outline: none; -} - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-drop-target { - border: 2px solid var(--border); - outline: none; -} - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-split:hover { - background: hsl(var(--primary)); -} - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-split.-row { - width: 4px; - margin: 0 -2px; -} - -.mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-split.-column { - height: 4px; - margin: -2px 0; -} - -/* Mobile: Wider split dividers for touch dragging */ -@media (max-width: 767px) { - .mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-split.-row { - width: 12px; - margin: 0 -6px; - } - - .mosaic.mosaic-blueprint-theme.mosaic-blueprint-theme .mosaic-split.-column { - height: 12px; - margin: -6px 0; - } -} - -/* ========================================================================== - Accessibility: Focus Indicators - ========================================================================== */ - -@layer base { - /* Focus-visible for buttons and interactive elements */ - button:focus-visible, - a:focus-visible, - [role="button"]:focus-visible { - outline: 2px solid hsl(var(--ring)); - outline-offset: 2px; - } - - /* Focus-visible for input elements */ - input:focus-visible, - textarea:focus-visible, - select:focus-visible { - outline: 2px solid hsl(var(--ring)); - outline-offset: 0; - } - - /* Focus-visible for command launcher items */ - [cmdk-item]:focus-visible { - outline: 2px solid hsl(var(--ring)); - outline-offset: -2px; - } - - /* Focus-visible for tab buttons */ - .tabbar-button:focus-visible { - outline: 2px solid hsl(var(--ring)); - outline-offset: 2px; - } -} - -/* ========================================================================== - TipTap Editor Styles - ========================================================================== */ - -.ProseMirror { - min-height: 1.25rem; - line-height: 1.25rem; - position: relative; -} - -.ProseMirror:focus { - outline: none; -} - -.ProseMirror p { - margin: 0; - line-height: 1.25rem; -} - -.ProseMirror p.is-editor-empty:first-child::before { - content: attr(data-placeholder); - color: hsl(var(--muted-foreground)); - pointer-events: none; - position: absolute; - left: 0; - top: 0; -} - -/* Disable link navigation in editor - allow editing instead of clicking */ -.ProseMirror a { - pointer-events: none; -} - -/* Mention styles */ -.ProseMirror .mention { - color: hsl(var(--primary)); - background-color: hsl(var(--primary) / 0.1); - padding: 0.125rem 0.25rem; - border-radius: 0.25rem; - text-decoration: none; - cursor: pointer; - font-weight: 500; -} - -.ProseMirror .mention:hover { - background-color: hsl(var(--primary) / 0.2); -} - -/* Emoji styles */ -.ProseMirror .emoji-node { - display: inline-flex; - align-items: center; - vertical-align: middle; -} - -.ProseMirror .emoji-image { - height: 1.2em; - width: auto; - vertical-align: middle; - object-fit: contain; -} - -.ProseMirror .emoji-unicode { - font-size: 1.1em; - line-height: 1; - vertical-align: middle; -} - -/* Nostr event preview styles */ -.ProseMirror .nostr-event-preview { - display: inline-flex; - align-items: center; - gap: 0.25rem; - padding: 0.125rem 0.375rem; - background-color: hsl(var(--primary) / 0.1); - border: 1px solid hsl(var(--primary) / 0.3); - border-radius: 0.25rem; - font-size: 0.75rem; - vertical-align: middle; - cursor: default; - transition: background-color 0.2s; -} - -.ProseMirror .nostr-event-preview:hover { - background-color: hsl(var(--primary) / 0.15); -} - -/* Hide scrollbar in RichEditor */ -.rich-editor .ProseMirror { - scrollbar-width: none; /* Firefox */ - -ms-overflow-style: none; /* IE/Edge */ -} - -.rich-editor .ProseMirror::-webkit-scrollbar { - display: none; /* Chrome/Safari/Opera */ +/* Active split highlight */ +.mosaic-split:active { + background: hsl(var(--primary) / 0.4) !important; } diff --git a/src/lib/shiki.ts b/src/lib/shiki.ts new file mode 100644 index 0000000..bc6c955 --- /dev/null +++ b/src/lib/shiki.ts @@ -0,0 +1,375 @@ +import { + createHighlighterCore, + type HighlighterCore, + type ThemeRegistration, +} from "shiki/core"; +import { createOnigurumaEngine } from "shiki/engine/oniguruma"; + +// Singleton highlighter instance +let highlighter: HighlighterCore | null = null; +let highlighterPromise: Promise | null = null; +const loadedLanguages = new Set(); + +/** + * Grimoire dark theme matching current minimalistic Prism styles + * Uses muted colors with primary accent for keywords/functions + */ +const grimoireTheme: ThemeRegistration = { + name: "grimoire-dark", + type: "dark", + colors: { + "editor.background": "#000000", + "editor.foreground": "#e5e5e5", + }, + tokenColors: [ + // Comments - muted + { + scope: ["comment", "punctuation.definition.comment"], + settings: { foreground: "#6b7280" }, + }, + // Strings - muted but slightly emphasized + { + scope: ["string", "string.quoted"], + settings: { foreground: "#9ca3af" }, + }, + // Keywords, operators - primary color + { + scope: [ + "keyword", + "storage", + "storage.type", + "storage.modifier", + "keyword.operator", + "keyword.control", + ], + settings: { foreground: "#a855f7" }, + }, + // Functions, methods - primary bold + { + scope: ["entity.name.function", "support.function", "meta.function-call"], + settings: { foreground: "#a855f7", fontStyle: "bold" }, + }, + // Classes, types - primary bold + { + scope: [ + "entity.name.class", + "entity.name.type", + "support.class", + "support.type", + ], + settings: { foreground: "#a855f7", fontStyle: "bold" }, + }, + // Numbers, constants - primary + { + scope: [ + "constant", + "constant.numeric", + "constant.language", + "constant.character", + ], + settings: { foreground: "#a855f7" }, + }, + // Variables, parameters - foreground + { + scope: ["variable", "variable.parameter", "variable.other"], + settings: { foreground: "#e5e5e5" }, + }, + // Punctuation - slightly muted + { + scope: ["punctuation", "meta.brace"], + settings: { foreground: "#b3b3b3" }, + }, + // Properties, attributes + { + scope: [ + "variable.other.property", + "entity.other.attribute-name", + "support.type.property-name", + ], + settings: { foreground: "#d4d4d4" }, + }, + // Tags (HTML/JSX) + { + scope: ["entity.name.tag", "support.class.component"], + settings: { foreground: "#a855f7" }, + }, + // JSON keys + { + scope: ["support.type.property-name.json"], + settings: { foreground: "#d4d4d4" }, + }, + // Diff - deleted (red) + { + scope: [ + "markup.deleted", + "punctuation.definition.deleted", + "meta.diff.header.from-file", + ], + settings: { foreground: "#ff8787" }, + }, + // Diff - inserted (green) + { + scope: [ + "markup.inserted", + "punctuation.definition.inserted", + "meta.diff.header.to-file", + ], + settings: { foreground: "#69db7c" }, + }, + // Diff - changed/range + { + scope: ["markup.changed", "meta.diff.range", "meta.diff.header"], + settings: { foreground: "#66d9ef" }, + }, + // Markdown headings + { + scope: ["markup.heading", "entity.name.section"], + settings: { foreground: "#a855f7", fontStyle: "bold" }, + }, + // Markdown bold/italic + { + scope: ["markup.bold"], + settings: { fontStyle: "bold" }, + }, + { + scope: ["markup.italic"], + settings: { fontStyle: "italic" }, + }, + // Markdown links + { + scope: ["markup.underline.link"], + settings: { foreground: "#a855f7" }, + }, + ], +}; + +/** + * Language alias mapping (file extensions and common names to Shiki IDs) + */ +const LANGUAGE_ALIASES: Record = { + // JavaScript family + ts: "typescript", + tsx: "tsx", + js: "javascript", + jsx: "jsx", + mjs: "javascript", + cjs: "javascript", + // Python + py: "python", + pyw: "python", + // Ruby + rb: "ruby", + // Rust + rs: "rust", + // Go + go: "go", + // Shell + sh: "bash", + bash: "bash", + shell: "bash", + zsh: "bash", + fish: "fish", + // Config/Data + yml: "yaml", + yaml: "yaml", + toml: "toml", + ini: "ini", + // JSON + json: "json", + jsonc: "jsonc", + json5: "json5", + // Markdown + md: "markdown", + mdx: "mdx", + // CSS + css: "css", + scss: "scss", + sass: "sass", + less: "less", + // HTML/XML + html: "html", + htm: "html", + xml: "xml", + svg: "xml", + // SQL + sql: "sql", + // C family + c: "c", + h: "c", + cpp: "cpp", + "c++": "cpp", + cc: "cpp", + cxx: "cpp", + hpp: "cpp", + hxx: "cpp", + // C# + cs: "csharp", + csharp: "csharp", + // Java/JVM + java: "java", + kt: "kotlin", + kotlin: "kotlin", + scala: "scala", + groovy: "groovy", + // Apple + swift: "swift", + objc: "objective-c", + // PHP + php: "php", + // Lua + lua: "lua", + // Vim + vim: "viml", + // Docker + dockerfile: "dockerfile", + docker: "dockerfile", + // Make + makefile: "makefile", + make: "makefile", + // Diff/Patch + diff: "diff", + patch: "diff", + // Blockchain + sol: "solidity", + solidity: "solidity", + // Zig + zig: "zig", + // Functional + ex: "elixir", + exs: "elixir", + erl: "erlang", + hs: "haskell", + ml: "ocaml", + clj: "clojure", + cljs: "clojure", + // GraphQL + graphql: "graphql", + gql: "graphql", + // Protocol Buffers + proto: "protobuf", + // Nix + nix: "nix", + // Terraform + tf: "hcl", + hcl: "hcl", + // PowerShell + ps1: "powershell", + psm1: "powershell", + // R + r: "r", + // Perl + pl: "perl", + pm: "perl", + // LaTeX + tex: "latex", + latex: "latex", + // WASM + wat: "wasm", + wasm: "wasm", +}; + +/** + * Core languages to preload (most commonly used in Grimoire) + */ +const CORE_LANGUAGES = [ + "javascript", + "typescript", + "json", + "diff", + "bash", +] as const; + +/** + * Normalize language identifier to Shiki language ID + */ +export function normalizeLanguage(lang: string | null | undefined): string { + if (!lang) return "text"; + const normalized = lang.toLowerCase().trim(); + return LANGUAGE_ALIASES[normalized] || normalized; +} + +/** + * Get or create the singleton highlighter instance + */ +export async function getHighlighter(): Promise { + if (highlighter) return highlighter; + + if (!highlighterPromise) { + highlighterPromise = createHighlighterCore({ + themes: [grimoireTheme], + langs: [ + import("shiki/langs/javascript.mjs"), + import("shiki/langs/typescript.mjs"), + import("shiki/langs/json.mjs"), + import("shiki/langs/diff.mjs"), + import("shiki/langs/bash.mjs"), + ], + engine: createOnigurumaEngine(import("shiki/wasm")), + }).then((hl) => { + highlighter = hl; + CORE_LANGUAGES.forEach((l) => loadedLanguages.add(l)); + return hl; + }); + } + + return highlighterPromise; +} + +/** + * Load a language on demand + */ +async function loadLanguage(lang: string): Promise { + if (lang === "text" || loadedLanguages.has(lang)) return true; + + const hl = await getHighlighter(); + + try { + // Dynamic import for the language + const langModule = await import(`shiki/langs/${lang}.mjs`); + await hl.loadLanguage(langModule.default || langModule); + loadedLanguages.add(lang); + return true; + } catch { + // Language not available + console.warn( + `[shiki] Language "${lang}" not available, falling back to plaintext`, + ); + return false; + } +} + +/** + * Highlight code with lazy language loading + * Returns HTML string + */ +export async function highlightCode( + code: string, + language: string | null | undefined, +): Promise { + const lang = normalizeLanguage(language); + const hl = await getHighlighter(); + + // Try to load the language if not already loaded + const loaded = await loadLanguage(lang); + const effectiveLang = loaded ? lang : "text"; + + return hl.codeToHtml(code, { + lang: effectiveLang, + theme: "grimoire-dark", + }); +} + +/** + * Check if a language is loaded + */ +export function isLanguageLoaded(lang: string): boolean { + return loadedLanguages.has(normalizeLanguage(lang)); +} + +/** + * Preload languages (e.g., before rendering known content) + */ +export async function preloadLanguages(langs: string[]): Promise { + await getHighlighter(); + await Promise.all(langs.map((l) => loadLanguage(normalizeLanguage(l)))); +} diff --git a/src/styles/prism-theme.css b/src/styles/prism-theme.css deleted file mode 100644 index a3f9dfe..0000000 --- a/src/styles/prism-theme.css +++ /dev/null @@ -1,144 +0,0 @@ -/* Grimoire Prism Theme - Uses CSS theme variables */ - -code[class*="language-"], -pre[class*="language-"] { - color: hsl(var(--foreground)); - background: none; - text-shadow: none; - font-family: "Oxygen Mono", monospace; - font-size: 0.75rem; - line-height: 1.5; - white-space: pre; - word-spacing: normal; - word-break: normal; - tab-size: 4; - hyphens: none; -} - -/* Diff-specific tokens */ - -/* Deleted lines (red) - subtle background, no strikethrough */ -.token.deleted { - color: hsl(var(--diff-deleted)); - background: hsl(var(--diff-deleted-bg)); - display: block; - margin: 0 -1rem; - padding: 0 1rem; -} - -/* Added lines (green) - subtle background */ -.token.inserted { - color: hsl(var(--diff-inserted)); - background: hsl(var(--diff-inserted-bg)); - display: block; - margin: 0 -1rem; - padding: 0 1rem; -} - -/* Hunk headers (@@ -1,5 +1,7 @@) - cyan/blue */ -.token.diff.coord, -.token.coord { - color: hsl(var(--diff-meta)); - background: hsl(var(--diff-meta-bg)); - display: block; - margin: 0 -1rem; - padding: 0 1rem; - font-weight: 600; - font-style: normal; -} - -/* File headers (diff --git, ---, +++) */ -.token.diff.range, -.token.prefix.unchanged, -.language-diff .token.unchanged { - color: hsl(var(--muted-foreground)); - font-weight: normal; -} - -/* Prefix characters (+/-) */ -.language-diff .token.prefix { - font-weight: 700; - opacity: 0.7; -} - -/* General syntax tokens */ -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: hsl(var(--syntax-comment)); -} - -.token.punctuation { - color: hsl(var(--syntax-punctuation)); -} - -.token.property, -.token.tag, -.token.boolean, -.token.number, -.token.constant, -.token.symbol { - color: hsl(var(--syntax-property)); -} - -.token.selector, -.token.attr-name, -.token.string, -.token.char, -.token.builtin { - color: hsl(var(--syntax-string)); -} - -.token.operator, -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string { - color: hsl(var(--syntax-operator)); -} - -.token.atrule, -.token.attr-value, -.token.keyword { - color: hsl(var(--syntax-keyword)); -} - -.token.function, -.token.class-name { - color: hsl(var(--syntax-function)); - font-weight: bold; -} - -.token.regex, -.token.important, -.token.variable { - color: hsl(var(--syntax-variable)); -} - -.token.important, -.token.bold { - font-weight: bold; -} - -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - -/* Line highlighting */ -pre[class*="language-"] > code { - display: block; -} - -/* Optional: Line numbers support */ -.line-numbers .line-numbers-rows { - border-right: 1px solid hsl(var(--border)); -} - -.line-numbers-rows > span:before { - color: hsl(var(--muted-foreground)); -} diff --git a/src/styles/shiki-theme.css b/src/styles/shiki-theme.css new file mode 100644 index 0000000..87a72da --- /dev/null +++ b/src/styles/shiki-theme.css @@ -0,0 +1,81 @@ +/* Shiki syntax highlighting - Grimoire dark theme overrides */ + +/* Base container styling */ +.shiki-container pre { + background: transparent !important; + margin: 0; + padding: 0; +} + +.shiki-container code { + font-family: "Oxygen Mono", monospace; + font-size: 0.75rem; + line-height: 1.5; + white-space: pre; + word-spacing: normal; + word-break: normal; + tab-size: 4; +} + +/* Ensure shiki's inline styles don't conflict */ +.shiki-container .shiki { + background: transparent !important; +} + +.shiki-container .shiki code { + background: transparent !important; +} + +/* Loading state - subtle pulse animation */ +.shiki-loading { + animation: shiki-pulse 1.5s ease-in-out infinite; +} + +@keyframes shiki-pulse { + 0%, + 100% { + opacity: 0.7; + } + 50% { + opacity: 0.5; + } +} + +/* Diff-specific styling - block-level backgrounds for inserted/deleted */ +/* These target the line spans that Shiki generates for diff content */ +.shiki-container .line:has(.diff.add), +.shiki-container .line:has([style*="color:#69db7c"]) { + background: rgba(52, 199, 89, 0.1); + display: block; + margin: 0 -1rem; + padding: 0 1rem; +} + +.shiki-container .line:has(.diff.remove), +.shiki-container .line:has([style*="color:#ff8787"]) { + background: rgba(255, 59, 48, 0.1); + display: block; + margin: 0 -1rem; + padding: 0 1rem; +} + +/* Hunk headers (@@ lines) - cyan background */ +.shiki-container .line:has([style*="color:#66d9ef"]) { + background: rgba(102, 217, 239, 0.08); + display: block; + margin: 0 -1rem; + padding: 0 1rem; + font-weight: 600; +} + +/* Optional: Line numbers */ +.shiki-container.line-numbers .line::before { + content: attr(data-line); + display: inline-block; + width: 2rem; + margin-right: 1rem; + text-align: right; + color: hsl(var(--muted-foreground)); + border-right: 1px solid hsl(var(--border)); + padding-right: 0.5rem; +}