diff --git a/README.md b/README.md index 022ba40..7946aa5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This library is a complete react-native implementation of [FastComments](https:/ It supports live commenting, chat, threads, emoticons, notifications, SSO, skins, and full customization by passing in a stylesheet object. All assets can also be customized, and it supports toggling different assets based on dark mode. -The benefit of this library is that it is more flexible than the `fastcomments-react-native` wrapper. Comments are rendered with native components rather than inside a webview. Note: `react-native-webview` is still required as a transitive dependency of the rich text editor (`@10play/tentap-editor`). +The benefit of this library is that it is more flexible than the `fastcomments-react-native` wrapper. Comments are rendered with native components rather than inside a webview. It all runs on the FastComments backend, so you only have to incorporate the UI: @@ -40,7 +40,9 @@ Add live chat to your existing React Native application, or even build a social ### Rich Text Editor -This library uses the 10tap editor for rich text editing functionality, which provides a powerful WYSIWYG editing experience. +This library uses [`react-native-enriched`](https://github.com/software-mansion/react-native-enriched) for rich text editing, which provides a powerful WYSIWYG editing experience. The same editor powers iOS, Android, and the web (via `react-native-web`), so the composer behaves consistently across every platform with a single implementation. + +`react-native-enriched` requires the React Native New Architecture (Fabric) on native, and a bundler that resolves package `exports` conditions (Metro with package exports / RN 0.72+). Web support is currently experimental. ### Configuration Options diff --git a/example-web/index.html b/example-web/index.html index 343de92..54d213f 100644 --- a/example-web/index.html +++ b/example-web/index.html @@ -6,6 +6,9 @@ FastComments React Native SDK - Web Example diff --git a/example-web/package-lock.json b/example-web/package-lock.json index 469a420..68b7da0 100644 --- a/example-web/package-lock.json +++ b/example-web/package-lock.json @@ -8,13 +8,13 @@ "name": "fastcomments-react-native-sdk-example-web", "version": "0.0.1", "dependencies": { - "react": "18.2.0", - "react-dom": "18.2.0", - "react-native-web": "^0.19.10" + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-native-web": "^0.21.0" }, "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.3.0", "typescript": "^5.4.0", "vite": "^5.4.0" @@ -1206,32 +1206,24 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", - "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "dev": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@vitejs/plugin-react": { @@ -1435,12 +1427,6 @@ "node": ">=6" } }, - "node_modules/fast-loops": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-loops/-/fast-loops-1.1.4.tgz", - "integrity": "sha512-8dbd3XWoKCTms18ize6JmQF1SFnnfj5s0B7rRry22EofgMu7B6LKHVh+XfFqFGsqnbH54xgeO83PzpKI+ODhlg==", - "license": "MIT" - }, "node_modules/fbjs": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", @@ -1494,13 +1480,12 @@ "license": "BSD-3-Clause" }, "node_modules/inline-style-prefixer": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.4.tgz", - "integrity": "sha512-FwXmZC2zbeeS7NzGjJ6pAiqRhXR0ugUShSNb6GApMl6da0/XGc4MOJsoWAywia52EEWbXNSy0pzkwz/+Y+swSg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", + "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==", "license": "MIT", "dependencies": { - "css-in-js-utils": "^3.1.0", - "fast-loops": "^1.1.3" + "css-in-js-utils": "^3.1.0" } }, "node_modules/js-tokens": { @@ -1683,48 +1668,44 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^19.2.7" } }, "node_modules/react-native-web": { - "version": "0.19.13", - "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.13.tgz", - "integrity": "sha512-etv3bN8rJglrRCp/uL4p7l8QvUNUC++QwDbdZ8CB7BvZiMvsxfFIRM1j04vxNldG3uo2puRd6OSWR3ibtmc29A==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz", + "integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.6", "@react-native/normalize-colors": "^0.74.1", "fbjs": "^3.0.4", - "inline-style-prefixer": "^6.0.1", + "inline-style-prefixer": "^7.0.1", "memoize-one": "^6.0.0", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", "styleq": "^0.1.3" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/react-refresh": { @@ -1783,13 +1764,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", diff --git a/example-web/package.json b/example-web/package.json index 6b0e9fc..d7a6672 100644 --- a/example-web/package.json +++ b/example-web/package.json @@ -10,13 +10,13 @@ "preview": "vite preview" }, "dependencies": { - "react": "18.2.0", - "react-dom": "18.2.0", - "react-native-web": "^0.19.10" + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-native-web": "^0.21.0" }, "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.3.0", "typescript": "^5.4.0", "vite": "^5.4.0" diff --git a/example-web/vite.config.ts b/example-web/vite.config.ts index 5110473..67fb460 100644 --- a/example-web/vite.config.ts +++ b/example-web/vite.config.ts @@ -54,7 +54,26 @@ export default defineConfig({ resolve: { alias: [ { find: /^fastcomments-react-native-sdk$/, replacement: path.join(sdkRoot, 'index.ts') }, + // `react-native-enriched`'s web build (and react-native-render-html) import + // the bare `react-native` specifier (e.g. `processColor`). The custom + // `reactNativeWebAlias` plugin handles top-level resolves, but Rollup's + // commonjs resolver bypasses it for nested dep imports during build, pulling + // in the real (Flow-typed) react-native and failing to parse. An exact-match + // alias redirects it to react-native-web everywhere. The `$` anchor avoids + // catching `react-native-enriched` / `react-native-web` themselves. + { find: /^react-native$/, replacement: path.dirname(require.resolve('react-native-web/package.json')) }, + // react-native-web's ESM dist imports inline-style-prefixer's CJS `lib/` + // deep paths (e.g. `inline-style-prefixer/lib/plugins/cursor`). Served raw + // to the browser, those CJS files expose no ESM `default` export and throw + // "doesn't provide an export named: 'default'". The package also ships a + // real ESM build under `es/`; redirect the deep `lib/` paths there. + { find: /^inline-style-prefixer\/lib\/(.*)$/, replacement: path.join(path.dirname(require.resolve('inline-style-prefixer/package.json')), 'es/$1') }, ], + // The demo imports the SDK from source (`../src`), whose files `import 'react'`. + // Without deduping, that resolves to the SDK root's own React copy while the + // app uses example-web's React 19 -> two React instances -> "invalid hook + // call". Force a single copy (example-web's React 19) for the whole graph. + dedupe: ['react', 'react-dom'], extensions: ['.web.tsx', '.web.ts', '.web.jsx', '.web.js', '.tsx', '.ts', '.jsx', '.js', '.json'], mainFields: ['module', 'browser', 'main'], }, @@ -81,10 +100,20 @@ export default defineConfig({ 'react-native-web > memoize-one', 'react-native-web > styleq', 'react-native-web > postcss-value-parser', + // react-native-web's ESM dist also imports these CJS *sub-entry* points + // directly. They aren't reachable from each package's main entry, so the + // `> pkg` includes above don't cover them, and served raw they expose no + // ESM named/default export ("doesn't provide an export named ..."). List + // them so Vite pre-bundles each with CJS->ESM interop. + 'styleq/transform-localize-style', + 'fbjs/lib/invariant', + 'fbjs/lib/warning', + // react-native-web's renderer imports `{ createRoot }` from this CJS + // sub-entry; same raw-CJS named-export problem as the deps above. + 'react-dom/client', 'lodash', 'fastcomments-typescript', - 'react-quill-new', - 'quill', + 'react-native-enriched', ], exclude: ['react-native'], }, diff --git a/package-lock.json b/package-lock.json index ce9721e..c05c870 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,12 +28,10 @@ "metro-react-native-babel-preset": "^0.66.2", "pod-install": "^0.1.0", "prettier": "^2.0.5", - "quill": "^2.0.3", "react": "18.3.1", "react-native": "^0.69.4", "react-native-builder-bob": "^0.18.2", - "react-native-enriched": "^0.5.2", - "react-quill-new": "^3.8.3", + "react-native-enriched": "^0.7.0", "react-test-renderer": "^18.3.1", "ts-clean": "^1.0.3", "ts-jest": "^29.0.1", @@ -43,21 +41,12 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-enriched": ">=0.4.0", - "react-quill-new": ">=3.8.0" - }, - "peerDependenciesMeta": { - "react-native-enriched": { - "optional": true - }, - "react-quill-new": { - "optional": true - } + "react-native-enriched": ">=0.7.0" } }, "../fastcomments-sdk-js": { "name": "fastcomments-sdk", - "version": "3.2.2", + "version": "3.2.3", "dev": true, "license": "MIT", "devDependencies": { @@ -2095,6 +2084,37 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -3512,6 +3532,13 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==", "dev": true }, + "node_modules/@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "dev": true, + "license": "MIT" + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -3646,6 +3673,303 @@ "node": ">=8" } }, + "node_modules/@tiptap/core": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.4.tgz", + "integrity": "sha512-3i/DG89TFY/b34T5P+j35UcjYuB5d3+9K8u6qID+iUqNPiza015HPIZLuPfE5elNwVdV3EXIoPo0LLeBLgXXAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.4.tgz", + "integrity": "sha512-9sskyyhYj2oKat//lyZVXCp9YrPt4oJAZnGHYWXS0xlskjsLElrfKKlM4vpbhGss3VrhQRoEGqWLnIaJYPF1zw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.4.tgz", + "integrity": "sha512-Md7/mNAeJCY+VLJc8JRGI+8XkVPKiOGB1NgqQPdh3aYtxXQDChQOZoJEQl6TuudDxZ85bLZB67NjZlx3jo8/0g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.24.0.tgz", + "integrity": "sha512-jRXD+JPu9ayvq78g8hsCxx4q/qUFtrdfIYirRSf5YUseuuUbtfrq83AsGabcygpUTefjJkMQoXNITkh6294Ggw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "3.24.0", + "@tiptap/pm": "3.24.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.4.tgz", + "integrity": "sha512-7j8Hi964bH1SZ9oLdZC1fkqWz27mliSDV7M8lmL/M14+Qw42D/VOAKS4Aw9OCFtHMlTsjLR6qsoVxL8Lpkt6NA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.4.tgz", + "integrity": "sha512-zF1CIFVLt8MfSpWWnPwtGyxPOsT0xYM2qJKcXf2yZcTG37wDKmUi6heG53vGigIavbQlLaAFvs+1mNdOu2x/0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.24.0.tgz", + "integrity": "sha512-7QEbf3mUzFAkejjQGX9f0L507oMtnOBRwHt2skUTR+9yXgudsN8zaDBSSRHLeMWGk9b7L293ZMA6zCRrZaHrfA==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@floating-ui/dom": "^1.0.0", + "@tiptap/core": "3.24.0", + "@tiptap/pm": "3.24.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.4.tgz", + "integrity": "sha512-xsnkmTGggJc5P2iCwS1lv8KFG31xC/GNPJKoi/3UH67j/lKDhA3AdtshsLeyv2FKtTtYDb8oV0IqzHB1MM6a7w==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.4.tgz", + "integrity": "sha512-4ZqiWr7cmqPFux8tj1ZLiYytyWf343IvQemNX6AvVWvscrJcrfj3YX4Le2BA0RW3A3M6RpLQXXozuF8vxYFDeQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.4.tgz", + "integrity": "sha512-JNDSkWrVdb8NSvbQXwHWvK5tCMbTWwOHFOweknQZ1JPK4dei9FJVofYQaHyW4bJBdcCjds3NZSnXE8DM9iAWmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.3.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4", + "@tiptap/pm": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-list": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.4.tgz", + "integrity": "sha512-X+5plTKhOioNcQ4KsAFJJSb/3+zR8Xhdpow4HzXtoV1KcbdDey1fhZdpsfkbrzCL0s6/wAgwZuAchCK7HujurQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4", + "@tiptap/pm": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.4.tgz", + "integrity": "sha512-lm6fOScWuZAF/Sfp97igUwFd3L1QHIVLAWP5NVdh0DTLrEIt4rMBmsww+yOpMQRhvz2uTgMbMXynrimhzi/QVw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.4.tgz", + "integrity": "sha512-It1Px9uDGTsVqyyg6cy7DigLoenljpQwqdI0jssM7QclZrHnsrye9fZxBBiiuCzzV1305MxKgHvratkHwqmVNA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.4.tgz", + "integrity": "sha512-jchJcBZixDEO2J66Zx5dchsI2mA6IYsROqF8P1poxL4ienH7RVQRCTsBNnSfIeOtREKKWeOU/tEs5fcpvvGwIQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.4.tgz", + "integrity": "sha512-0OjMc3FDujX16G+jhvqcY/mLot8SrNtDu8ggUwNLAfiI/QIvMVgk7giFD71DATC/4Nb8i/iwAEegTD8MxBIXCg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4" + } + }, + "node_modules/@tiptap/extensions": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.4.tgz", + "integrity": "sha512-8p6hVT65DjuQjtEdlH6ewX9SOJHlVQAOee3sWIJQmeJNRnZNvqPIBLleebUqDiljNTpxBv6s6QWkSTKgf3btwg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4", + "@tiptap/pm": "^3.20.4" + } + }, + "node_modules/@tiptap/pm": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.4.tgz", + "integrity": "sha512-rCHYSBToilBEuI6PtjziHDdRkABH/XqwJ7dG4Amn/SD3yGiZKYCiEApQlTUS2zZeo8DsLeuqqqB4vEOeD4OEPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/react": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.20.4.tgz", + "integrity": "sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "optionalDependencies": { + "@tiptap/extension-bubble-menu": "^3.20.4", + "@tiptap/extension-floating-menu": "^3.20.4" + }, + "peerDependencies": { + "@tiptap/core": "^3.20.4", + "@tiptap/pm": "^3.20.4", + "@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", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -3762,11 +4086,36 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.14.185", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", "integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==" }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "18.7.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", @@ -3840,6 +4189,13 @@ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz", "integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -5096,6 +5452,13 @@ "node": ">=4" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -5589,13 +5952,6 @@ "node": ">=6" } }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -5858,12 +6214,15 @@ "node": ">=0.10.0" } }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } }, "node_modules/fast-glob": { "version": "3.2.12", @@ -9481,6 +9840,33 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/linkify-it": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz", + "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", + "dev": true, + "license": "MIT" + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -9522,34 +9908,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -9696,6 +10060,61 @@ "node": ">=0.10.0" } }, + "node_modules/markdown-it": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.1", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "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==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -10958,6 +11377,13 @@ "node": ">=8" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "dev": true, + "license": "MIT" + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -11028,13 +11454,6 @@ "node": ">=6" } }, - "node_modules/parchment": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", - "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11366,6 +11785,232 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz", + "integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.2.tgz", + "integrity": "sha512-6VgUJTYod0nMBlCaYJGhXGLu7Gt4AvcwcOq0YfJCY/6Uh+3S7UsWhpy6rJFCBFOmonq1hD8KyWOtZhkppd4YPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.25.7", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.7.tgz", + "integrity": "sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.25.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.22.1", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.33.8" + } + }, + "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.41.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -11376,6 +12021,16 @@ "once": "^1.3.1" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11405,37 +12060,6 @@ "node": ">=4" } }, - "node_modules/quill": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", - "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "eventemitter3": "^5.0.1", - "lodash-es": "^4.17.21", - "parchment": "^3.0.0", - "quill-delta": "^5.1.0" - }, - "engines": { - "npm": ">=8.2.3" - } - }, - "node_modules/quill-delta": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", - "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.3.0", - "lodash.clonedeep": "^4.5.0", - "lodash.isequal": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/ramda": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", @@ -11890,15 +12514,33 @@ } }, "node_modules/react-native-enriched": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.5.2.tgz", - "integrity": "sha512-9texMnu5+CXLCuVJv987UmzgB70F8Q3okOm2zqZ8jYSEz8IGyd7kbJdZ4J1rW99x3hYaeV+u+cSECzrCj7F4EA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.7.0.tgz", + "integrity": "sha512-WrhaRUMM8HaV+6XwESS1k7i1/QxZb4K2lpELIxLTiXXMdUP5b9207AjXp6d8Op0XulvFNC8HJdDdanQZUUI6Zg==", "dev": true, "license": "MIT", "workspaces": [ "apps/example", "apps/example-web" ], + "dependencies": { + "@tiptap/core": "3.20.4", + "@tiptap/extension-blockquote": "3.20.4", + "@tiptap/extension-bold": "3.20.4", + "@tiptap/extension-code": "3.20.4", + "@tiptap/extension-document": "3.20.4", + "@tiptap/extension-heading": "3.20.4", + "@tiptap/extension-italic": "3.20.4", + "@tiptap/extension-link": "3.20.4", + "@tiptap/extension-list": "3.20.4", + "@tiptap/extension-paragraph": "3.20.4", + "@tiptap/extension-strike": "3.20.4", + "@tiptap/extension-text": "3.20.4", + "@tiptap/extension-underline": "3.20.4", + "@tiptap/extensions": "3.20.4", + "@tiptap/pm": "3.20.4", + "@tiptap/react": "3.20.4" + }, "peerDependencies": { "react": "*", "react-native": "*" @@ -11975,23 +12617,7 @@ "dev": true, "license": "MIT", "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/react-quill-new": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/react-quill-new/-/react-quill-new-3.8.3.tgz", - "integrity": "sha512-c96PYqFTo0pI4R3e79B3rH9LUIce1kIQbmTBu/imJQZk8305ogyLyBqKKjG2UoInDlquXqePSzmBo2aVia3ttw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash-es": "^4.17.21", - "quill": "~2.0.3" - }, - "peerDependencies": { - "quill-delta": "^5.1.0", - "react": "^16 || ^17 || ^18 || ^19", - "react-dom": "^16 || ^17 || ^18 || ^19" + "async-limiter": "~1.0.0" } }, "node_modules/react-refresh": { @@ -12463,6 +13089,13 @@ "rimraf": "bin.js" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -14078,6 +14711,13 @@ "node": ">=4.2.0" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, "node_modules/uglify-es": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.10.tgz", @@ -14301,12 +14941,13 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "dev": true, + "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/util-deprecate": { @@ -14365,6 +15006,13 @@ "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", "dev": true }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "dev": true, + "license": "MIT" + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -16013,6 +16661,34 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dev": true, + "optional": true, + "requires": { + "@floating-ui/utils": "^0.2.11" + } + }, + "@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dev": true, + "optional": true, + "requires": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "dev": true, + "optional": true + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -17158,6 +17834,12 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==", "dev": true }, + "@remirror/core-constants": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz", + "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==", + "dev": true + }, "@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -17258,6 +17940,149 @@ } } }, + "@tiptap/core": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.4.tgz", + "integrity": "sha512-3i/DG89TFY/b34T5P+j35UcjYuB5d3+9K8u6qID+iUqNPiza015HPIZLuPfE5elNwVdV3EXIoPo0LLeBLgXXAg==", + "dev": true + }, + "@tiptap/extension-blockquote": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.4.tgz", + "integrity": "sha512-9sskyyhYj2oKat//lyZVXCp9YrPt4oJAZnGHYWXS0xlskjsLElrfKKlM4vpbhGss3VrhQRoEGqWLnIaJYPF1zw==", + "dev": true + }, + "@tiptap/extension-bold": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.4.tgz", + "integrity": "sha512-Md7/mNAeJCY+VLJc8JRGI+8XkVPKiOGB1NgqQPdh3aYtxXQDChQOZoJEQl6TuudDxZ85bLZB67NjZlx3jo8/0g==", + "dev": true + }, + "@tiptap/extension-bubble-menu": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.24.0.tgz", + "integrity": "sha512-jRXD+JPu9ayvq78g8hsCxx4q/qUFtrdfIYirRSf5YUseuuUbtfrq83AsGabcygpUTefjJkMQoXNITkh6294Ggw==", + "dev": true, + "optional": true, + "requires": { + "@floating-ui/dom": "^1.0.0" + } + }, + "@tiptap/extension-code": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.4.tgz", + "integrity": "sha512-7j8Hi964bH1SZ9oLdZC1fkqWz27mliSDV7M8lmL/M14+Qw42D/VOAKS4Aw9OCFtHMlTsjLR6qsoVxL8Lpkt6NA==", + "dev": true + }, + "@tiptap/extension-document": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.4.tgz", + "integrity": "sha512-zF1CIFVLt8MfSpWWnPwtGyxPOsT0xYM2qJKcXf2yZcTG37wDKmUi6heG53vGigIavbQlLaAFvs+1mNdOu2x/0A==", + "dev": true + }, + "@tiptap/extension-floating-menu": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.24.0.tgz", + "integrity": "sha512-7QEbf3mUzFAkejjQGX9f0L507oMtnOBRwHt2skUTR+9yXgudsN8zaDBSSRHLeMWGk9b7L293ZMA6zCRrZaHrfA==", + "dev": true, + "optional": true + }, + "@tiptap/extension-heading": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.4.tgz", + "integrity": "sha512-xsnkmTGggJc5P2iCwS1lv8KFG31xC/GNPJKoi/3UH67j/lKDhA3AdtshsLeyv2FKtTtYDb8oV0IqzHB1MM6a7w==", + "dev": true + }, + "@tiptap/extension-italic": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.4.tgz", + "integrity": "sha512-4ZqiWr7cmqPFux8tj1ZLiYytyWf343IvQemNX6AvVWvscrJcrfj3YX4Le2BA0RW3A3M6RpLQXXozuF8vxYFDeQ==", + "dev": true + }, + "@tiptap/extension-link": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.4.tgz", + "integrity": "sha512-JNDSkWrVdb8NSvbQXwHWvK5tCMbTWwOHFOweknQZ1JPK4dei9FJVofYQaHyW4bJBdcCjds3NZSnXE8DM9iAWmg==", + "dev": true, + "requires": { + "linkifyjs": "^4.3.2" + } + }, + "@tiptap/extension-list": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.4.tgz", + "integrity": "sha512-X+5plTKhOioNcQ4KsAFJJSb/3+zR8Xhdpow4HzXtoV1KcbdDey1fhZdpsfkbrzCL0s6/wAgwZuAchCK7HujurQ==", + "dev": true + }, + "@tiptap/extension-paragraph": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.4.tgz", + "integrity": "sha512-lm6fOScWuZAF/Sfp97igUwFd3L1QHIVLAWP5NVdh0DTLrEIt4rMBmsww+yOpMQRhvz2uTgMbMXynrimhzi/QVw==", + "dev": true + }, + "@tiptap/extension-strike": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.4.tgz", + "integrity": "sha512-It1Px9uDGTsVqyyg6cy7DigLoenljpQwqdI0jssM7QclZrHnsrye9fZxBBiiuCzzV1305MxKgHvratkHwqmVNA==", + "dev": true + }, + "@tiptap/extension-text": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.4.tgz", + "integrity": "sha512-jchJcBZixDEO2J66Zx5dchsI2mA6IYsROqF8P1poxL4ienH7RVQRCTsBNnSfIeOtREKKWeOU/tEs5fcpvvGwIQ==", + "dev": true + }, + "@tiptap/extension-underline": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.4.tgz", + "integrity": "sha512-0OjMc3FDujX16G+jhvqcY/mLot8SrNtDu8ggUwNLAfiI/QIvMVgk7giFD71DATC/4Nb8i/iwAEegTD8MxBIXCg==", + "dev": true + }, + "@tiptap/extensions": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.4.tgz", + "integrity": "sha512-8p6hVT65DjuQjtEdlH6ewX9SOJHlVQAOee3sWIJQmeJNRnZNvqPIBLleebUqDiljNTpxBv6s6QWkSTKgf3btwg==", + "dev": true + }, + "@tiptap/pm": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.4.tgz", + "integrity": "sha512-rCHYSBToilBEuI6PtjziHDdRkABH/XqwJ7dG4Amn/SD3yGiZKYCiEApQlTUS2zZeo8DsLeuqqqB4vEOeD4OEPg==", + "dev": true, + "requires": { + "prosemirror-changeset": "^2.3.0", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.6.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.13.1", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.24.1", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.5.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.6.4", + "prosemirror-trailing-node": "^3.0.0", + "prosemirror-transform": "^1.10.2", + "prosemirror-view": "^1.38.1" + } + }, + "@tiptap/react": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-3.20.4.tgz", + "integrity": "sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw==", + "dev": true, + "requires": { + "@tiptap/extension-bubble-menu": "^3.20.4", + "@tiptap/extension-floating-menu": "^3.20.4", + "@types/use-sync-external-store": "^0.0.6", + "fast-equals": "^5.3.3", + "use-sync-external-store": "^1.4.0" + } + }, "@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -17367,11 +18192,33 @@ } } }, + "@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, "@types/lodash": { "version": "4.14.185", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz", "integrity": "sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==" }, + "@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "requires": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, "@types/node": { "version": "18.7.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", @@ -17440,6 +18287,12 @@ "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz", "integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg==" }, + "@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "dev": true + }, "@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -18380,6 +19233,12 @@ "parse-json": "^4.0.0" } }, + "crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -18735,12 +19594,6 @@ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dev": true }, - "eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true - }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -18953,10 +19806,10 @@ } } }, - "fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", "dev": true }, "fast-glob": { @@ -21703,6 +22556,21 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "linkify-it": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "dev": true, + "requires": { + "uc.micro": "^2.0.0" + } + }, + "linkifyjs": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz", + "integrity": "sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==", + "dev": true + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -21737,30 +22605,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash-es": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", - "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "dev": true - }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "dev": true - }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -21875,6 +22725,40 @@ "object-visit": "^1.0.0" } }, + "markdown-it": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", + "dev": true, + "requires": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.1", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + } + } + }, + "mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -22893,6 +23777,12 @@ } } }, + "orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", + "dev": true + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -22938,12 +23828,6 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "parchment": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", - "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==", - "dev": true - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -23199,6 +24083,204 @@ } } }, + "prosemirror-changeset": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz", + "integrity": "sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==", + "dev": true, + "requires": { + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "dev": true, + "requires": { + "prosemirror-state": "^1.0.0" + } + }, + "prosemirror-commands": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz", + "integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==", + "dev": true, + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.10.2" + } + }, + "prosemirror-dropcursor": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz", + "integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==", + "dev": true, + "requires": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "prosemirror-gapcursor": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz", + "integrity": "sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==", + "dev": true, + "requires": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "prosemirror-history": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz", + "integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==", + "dev": true, + "requires": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "prosemirror-inputrules": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz", + "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==", + "dev": true, + "requires": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "prosemirror-keymap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz", + "integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==", + "dev": true, + "requires": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "prosemirror-markdown": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz", + "integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==", + "dev": true, + "requires": { + "@types/markdown-it": "^14.0.0", + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.25.0" + } + }, + "prosemirror-menu": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.2.tgz", + "integrity": "sha512-6VgUJTYod0nMBlCaYJGhXGLu7Gt4AvcwcOq0YfJCY/6Uh+3S7UsWhpy6rJFCBFOmonq1hD8KyWOtZhkppd4YPg==", + "dev": true, + "requires": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "prosemirror-model": { + "version": "1.25.7", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.7.tgz", + "integrity": "sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==", + "dev": true, + "requires": { + "orderedmap": "^2.0.0" + } + }, + "prosemirror-schema-basic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz", + "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==", + "dev": true, + "requires": { + "prosemirror-model": "^1.25.0" + } + }, + "prosemirror-schema-list": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz", + "integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==", + "dev": true, + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "prosemirror-state": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", + "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", + "dev": true, + "requires": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "prosemirror-tables": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz", + "integrity": "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==", + "dev": true, + "requires": { + "prosemirror-keymap": "^1.2.3", + "prosemirror-model": "^1.25.4", + "prosemirror-state": "^1.4.4", + "prosemirror-transform": "^1.10.5", + "prosemirror-view": "^1.41.4" + } + }, + "prosemirror-trailing-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz", + "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==", + "dev": true, + "requires": { + "@remirror/core-constants": "3.0.0", + "escape-string-regexp": "^4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, + "prosemirror-transform": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz", + "integrity": "sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==", + "dev": true, + "requires": { + "prosemirror-model": "^1.21.0" + } + }, + "prosemirror-view": { + "version": "1.41.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz", + "integrity": "sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==", + "dev": true, + "requires": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -23209,6 +24291,12 @@ "once": "^1.3.1" } }, + "punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -23221,29 +24309,6 @@ "integrity": "sha512-tRS7sTgyxMXtLum8L65daJnHUhfDUgboRdcWW2bR9vBfrj2+O5HSMbQOJfJJjIVSPFqbBCF37FpwWXGitDc5tA==", "dev": true }, - "quill": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", - "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", - "dev": true, - "requires": { - "eventemitter3": "^5.0.1", - "lodash-es": "^4.17.21", - "parchment": "^3.0.0", - "quill-delta": "^5.1.0" - } - }, - "quill-delta": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", - "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", - "dev": true, - "requires": { - "fast-diff": "^1.3.0", - "lodash.clonedeep": "^4.5.0", - "lodash.isequal": "^4.5.0" - } - }, "ramda": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", @@ -23622,10 +24687,28 @@ } }, "react-native-enriched": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.5.2.tgz", - "integrity": "sha512-9texMnu5+CXLCuVJv987UmzgB70F8Q3okOm2zqZ8jYSEz8IGyd7kbJdZ4J1rW99x3hYaeV+u+cSECzrCj7F4EA==", - "dev": true + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.7.0.tgz", + "integrity": "sha512-WrhaRUMM8HaV+6XwESS1k7i1/QxZb4K2lpELIxLTiXXMdUP5b9207AjXp6d8Op0XulvFNC8HJdDdanQZUUI6Zg==", + "dev": true, + "requires": { + "@tiptap/core": "3.20.4", + "@tiptap/extension-blockquote": "3.20.4", + "@tiptap/extension-bold": "3.20.4", + "@tiptap/extension-code": "3.20.4", + "@tiptap/extension-document": "3.20.4", + "@tiptap/extension-heading": "3.20.4", + "@tiptap/extension-italic": "3.20.4", + "@tiptap/extension-link": "3.20.4", + "@tiptap/extension-list": "3.20.4", + "@tiptap/extension-paragraph": "3.20.4", + "@tiptap/extension-strike": "3.20.4", + "@tiptap/extension-text": "3.20.4", + "@tiptap/extension-underline": "3.20.4", + "@tiptap/extensions": "3.20.4", + "@tiptap/pm": "3.20.4", + "@tiptap/react": "3.20.4" + } }, "react-native-gradle-plugin": { "version": "0.0.7", @@ -23649,16 +24732,6 @@ "urijs": "^1.19.6" } }, - "react-quill-new": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/react-quill-new/-/react-quill-new-3.8.3.tgz", - "integrity": "sha512-c96PYqFTo0pI4R3e79B3rH9LUIce1kIQbmTBu/imJQZk8305ogyLyBqKKjG2UoInDlquXqePSzmBo2aVia3ttw==", - "dev": true, - "requires": { - "lodash-es": "^4.17.21", - "quill": "~2.0.3" - } - }, "react-refresh": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", @@ -24025,6 +25098,12 @@ "glob": "^7.1.3" } }, + "rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==", + "dev": true + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -25282,6 +26361,12 @@ "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true }, + "uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "uglify-es": { "version": "3.3.10", "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.10.tgz", @@ -25440,9 +26525,9 @@ "dev": true }, "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "dev": true }, "util-deprecate": { @@ -25490,6 +26575,12 @@ "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", "dev": true }, + "w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "dev": true + }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", diff --git a/package.json b/package.json index 824a62b..5b43f80 100644 --- a/package.json +++ b/package.json @@ -63,12 +63,10 @@ "metro-react-native-babel-preset": "^0.66.2", "pod-install": "^0.1.0", "prettier": "^2.0.5", - "quill": "^2.0.3", "react": "18.3.1", "react-native": "^0.69.4", "react-native-builder-bob": "^0.18.2", - "react-native-enriched": "^0.5.2", - "react-quill-new": "^3.8.3", + "react-native-enriched": "^0.7.0", "react-test-renderer": "^18.3.1", "ts-clean": "^1.0.3", "ts-jest": "^29.0.1", @@ -85,15 +83,6 @@ "peerDependencies": { "react": "*", "react-native": "*", - "react-native-enriched": ">=0.4.0", - "react-quill-new": ">=3.8.0" - }, - "peerDependenciesMeta": { - "react-native-enriched": { - "optional": true - }, - "react-quill-new": { - "optional": true - } + "react-native-enriched": ">=0.7.0" } } diff --git a/src/components/comment-text-area.native.tsx b/src/components/comment-text-area.tsx similarity index 57% rename from src/components/comment-text-area.native.tsx rename to src/components/comment-text-area.tsx index fc1e77e..184fcee 100644 --- a/src/components/comment-text-area.native.tsx +++ b/src/components/comment-text-area.tsx @@ -12,6 +12,7 @@ import { ScrollView, TouchableOpacity, Image, + Platform, } from "react-native"; import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { @@ -20,13 +21,33 @@ import { type OnChangeStateEvent, } from 'react-native-enriched'; import type { NativeSyntheticEvent } from 'react-native'; -import { MentionPopup } from './mention-popup'; +import { MentionPopup, MentionPopupHandle } from './mention-popup'; +import { MentionPortal } from './mention-portal'; import { MentionUser } from '../services/mentions'; +import { detectMentionQuery, htmlToPlainText, replaceActiveMention } from '../services/mention-detection'; // Library's own event types follow snake->camelCase with `strikeThrough`. // eslint-disable-next-line @typescript-eslint/no-explicit-any type OnChangeHtmlEvent = { value: string }; +// react-native-enriched's web build renders tiptap's contenteditable +// (`.ProseMirror`) inside a wrapper (`.eti-editor`) that receives our `style` +// (minHeight/flex). The contenteditable itself only auto-sizes to its content +// (one line), so the lower part of the bordered box is a dead, unclickable div. +// The library ships no CSS to stretch it. Inject a tiny web-only rule once so +// the editor fills its wrapper and the whole box is clickable/typable. +const WEB_EDITOR_STYLE_ID = 'fastcomments-enriched-web-fill'; +function ensureWebEditorFillStyles() { + if (typeof document === 'undefined') return; + if (document.getElementById(WEB_EDITOR_STYLE_ID)) return; + const el = document.createElement('style'); + el.id = WEB_EDITOR_STYLE_ID; + el.textContent = + '.eti-editor{display:flex;flex-direction:column;}' + + '.eti-editor>.tiptap,.eti-editor>.ProseMirror{flex:1 1 auto;}'; + document.head.appendChild(el); +} + export interface ValueObserver { getValue?: () => string } @@ -66,6 +87,7 @@ type ActiveFormats = { italic: boolean underline: boolean strikethrough: boolean + code: boolean }; const defaultToolbarButtons: ToolbarButtonConfig = { @@ -78,44 +100,9 @@ const defaultToolbarButtons: ToolbarButtonConfig = { gif: true, }; -/** - * Strip simple HTML tags / decode common entities so we can detect `@...` triggers - * in rich-text HTML the editor emits. Comment editors typically wrap text in - *

/

with breaks; we just need readable text for the trigger regex. - */ -function htmlToPlainText(html: string): string { - if (!html) return ''; - const stripped = html - .replace(/(\n)?/gi, '\n') - .replace(/<\/(p|div|li)>/gi, '\n') - .replace(/<[^>]+>/g, ''); - return stripped - .replace(/ /g, ' ') - .replace(/&/g, '&') - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/"/g, '"') - .replace(/'/g, "'"); -} - -/** - * Returns the active mention query (text after the most recent `@` that starts - * a token) or undefined when no mention is active. A trailing space terminates - * the mention. - */ -export function detectMentionQuery(value: string): string | undefined { - const text = htmlToPlainText(value); - const atIdx = text.lastIndexOf('@'); - if (atIdx === -1) return undefined; - if (atIdx > 0) { - const prev = text.charAt(atIdx - 1); - if (!/\s/.test(prev)) return undefined; - } - const after = text.substring(atIdx + 1); - if (/\n/.test(after)) return undefined; - if (after.length > 0 && /\s$/.test(after)) return undefined; - return after; -} +// Re-exported for any existing importers (the implementations now live in the +// dependency-free `../services/mention-detection` module). +export { detectMentionQuery, htmlToPlainText }; export function CommentTextArea({ emoticonBarConfig, @@ -138,12 +125,94 @@ export function CommentTextArea({ const editorRef = useRef(null); const htmlRef = useRef(value || ''); + // For keyboard-driving the mention popup (web): the wrapper DOM node we + // attach a capture-phase keydown listener to, the popup's imperative handle, + // and a ref mirror of `mentionQuery` so that once-attached listener sees the + // current open state without re-binding. + const wrapperRef = useRef(null); + const editorBoxRef = useRef(null); + const mentionPopupRef = useRef(null); + const mentionActiveRef = useRef(false); const [imageUploadProgress, setImageUploadProgress] = useState(null); - const [active, setActive] = useState({ bold: false, italic: false, underline: false, strikethrough: false }); + const [active, setActive] = useState({ bold: false, italic: false, underline: false, strikethrough: false, code: false }); const [mentionQuery, setMentionQuery] = useState(undefined); + // On web the composer lives inside the scrollable comment list (as its + // header), so an `absolute` popup gets clipped by the list's overflow and + // painted under later comment-row cells. Position it `fixed` (measured off + // the editor box) to escape both. Native keeps the in-flow `absolute` overlay. + const [mentionOverlayStyle, setMentionOverlayStyle] = useState | null>(null); + mentionActiveRef.current = mentionQuery !== undefined; const buttons = { ...defaultToolbarButtons, ...toolbarButtons }; + useEffect(() => { + if (Platform.OS === 'web') ensureWebEditorFillStyles(); + }, []); + + // Web-only: drive the mention popup from the keyboard. react-native-enriched's + // web editor forwards keydown but always returns false to ProseMirror, so it + // can't tell PM "handled - don't move the cursor / insert a newline". Instead + // we listen on the wrapper in the CAPTURE phase: the event is intercepted + // before it reaches the contenteditable, so stopping it keeps PM from acting. + useEffect(() => { + if (Platform.OS !== 'web') return; + // The tsconfig has no DOM lib (this is an RN project), so we type the web + // key event minimally rather than relying on the global KeyboardEvent + // (which resolves to react-native's unrelated KeyboardEvent type). + type WebKeyEvent = { key: string; preventDefault: () => void; stopPropagation: () => void }; + const node = wrapperRef.current as unknown as { + addEventListener?: (t: string, h: (e: WebKeyEvent) => void, c?: boolean) => void; + removeEventListener?: (t: string, h: (e: WebKeyEvent) => void, c?: boolean) => void; + } | null; + if (!node || typeof node.addEventListener !== 'function') return; + const onKeyDown = (e: WebKeyEvent) => { + if (!mentionActiveRef.current) return; + const key = e.key; + if (key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); + setMentionQuery(undefined); + return; + } + if (key === 'ArrowDown' || key === 'ArrowUp' || key === 'Enter' || key === 'Tab') { + if (mentionPopupRef.current?.handleKey(key)) { + e.preventDefault(); + e.stopPropagation(); + } + } + }; + node.addEventListener('keydown', onKeyDown, true); + return () => node.removeEventListener?.('keydown', onKeyDown, true); + }, []); + + // Web-only: keep the fixed-positioned mention popup anchored under the editor + // box while it's open (reposition on scroll/resize since `fixed` is relative + // to the viewport). + useEffect(() => { + if (Platform.OS !== 'web') return; + if (mentionQuery === undefined) { + setMentionOverlayStyle(null); + return; + } + const win = globalThis as unknown as { + addEventListener?: (t: string, h: () => void, c?: boolean) => void; + removeEventListener?: (t: string, h: () => void, c?: boolean) => void; + }; + const reposition = () => { + const box = editorBoxRef.current as unknown as { getBoundingClientRect?: () => { bottom: number; left: number; width: number } } | null; + const rect = box?.getBoundingClientRect?.(); + if (!rect) return; + setMentionOverlayStyle({ position: 'fixed', top: rect.bottom, left: rect.left, width: rect.width, zIndex: 2147483000 }); + }; + reposition(); + win.addEventListener?.('scroll', reposition, true); + win.addEventListener?.('resize', reposition); + return () => { + win.removeEventListener?.('scroll', reposition, true); + win.removeEventListener?.('resize', reposition); + }; + }, [mentionQuery]); + useEffect(() => { if (value !== undefined && value !== htmlRef.current) { htmlRef.current = value; @@ -170,23 +239,7 @@ export function CommentTextArea({ const handleMentionSelect = useCallback((user: MentionUser) => { const label = user.displayName || user.name; - const current = htmlRef.current || ''; - const plain = htmlToPlainText(current); - const atIdx = plain.lastIndexOf('@'); - // Only safely rewrite when the editor's value is plain text (no HTML - // markup difference). When the editor has rich HTML, we replace the - // raw current value with a plain-text-friendly mention insert; the - // editor will re-render via setValue. - let nextValue: string; - if (current === plain) { - nextValue = current.substring(0, atIdx) + `@${label} `; - } else { - nextValue = current.replace(/@[^@<>\n]*$/, `@${label} `); - if (nextValue === current) { - // Fallback: append. - nextValue = current + `@${label} `; - } - } + const nextValue = replaceActiveMention(htmlRef.current || '', label); htmlRef.current = nextValue; editorRef.current?.setValue(nextValue); setMentionQuery(undefined); @@ -199,6 +252,7 @@ export function CommentTextArea({ italic: !!s.italic?.isActive, underline: !!s.underline?.isActive, strikethrough: !!s.strikeThrough?.isActive, + code: !!s.inlineCode?.isActive, }); }, []); @@ -270,37 +324,57 @@ export function CommentTextArea({ const activeBackground = hasDarkBackground ? '#666' : '#d8d8d8'; return ( - - - onFocus() : undefined} - style={{ - minHeight: useSingleLineCommentInput ? 32 : 92, - flex: 1, - backgroundColor: 'transparent', - }} - /> - + + {/* Relative anchor so that on native the mention popup overlays + (position:absolute, top:100%) directly under the editor box. On web + the popup is positioned `fixed` instead (see mentionOverlayStyle) to + escape the scrollable comment list that clips/stacks over it. */} + + + onFocus() : undefined} + style={{ + minHeight: useSingleLineCommentInput ? 32 : 92, + flex: 1, + backgroundColor: 'transparent', + }} + /> + - + + + + + + {emoticonBarConfig?.emoticons && ( @@ -361,6 +435,15 @@ export function CommentTextArea({ S )} + {buttons.code && ( + editorRef.current?.toggleInlineCode()} + activeOpacity={0.7} + > + {"<>"} + + )} {buttons.image && pickImage && ( string -} - -export interface FocusObserver { - setFocused?: (focused: boolean) => void -} - -export interface EmoticonBarConfig { - emoticons?: Array<[string, React.ReactNode]> - addEmoticon?: (src: string) => void -} - -export interface ToolbarButtonConfig { - bold?: boolean - italic?: boolean - underline?: boolean - strikethrough?: boolean - code?: boolean - image?: boolean - gif?: boolean -} - -export interface CommentTextAreaProps extends Pick { - emoticonBarConfig?: EmoticonBarConfig - focusObserver?: FocusObserver - store: FastCommentsStore - styles: IFastCommentsStyles - output: ValueObserver - onFocus?: () => void - value?: string - toolbarButtons?: ToolbarButtonConfig -} - -type ActiveFormats = { - bold: boolean - italic: boolean - underline: boolean - strike: boolean - code: boolean -}; - -const defaultToolbarButtons: ToolbarButtonConfig = { - bold: true, - italic: true, - underline: true, - strikethrough: true, - code: false, - image: true, - gif: true, -}; - -// Quill accepts a fixed set of format names. We only whitelist ones we expose -// via the toolbar plus link/image so paste-with-formatting still renders. -const allowedFormats = ['bold', 'italic', 'underline', 'strike', 'code', 'link', 'image']; - -export function CommentTextArea({ - emoticonBarConfig, - focusObserver, - store, - styles, - output, - onFocus, - pickImage, - pickGIF, - value, - toolbarButtons, -}: CommentTextAreaProps) { - const maxLength = useStoreValue(store, (s) => s.config.maxCommentCharacterLength) || 2000; - const hasDarkBackground = useStoreValue(store, (s) => !!s.config.hasDarkBackground); - const apiHost = useStoreValue(store, (s) => s.apiHost); - const tenantId = useStoreValue(store, (s) => s.config.tenantId); - const imageAssets = useStoreValue(store, (s) => s.imageAssets); - const useSingleLineCommentInput = useStoreValue(store, (s) => !!s.config.useSingleLineCommentInput); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const quillRef = useRef(null); - const [html, setHtml] = useState(value || ''); - useEffect(() => { ensureQuillFillStyles(); }, []); - const [imageUploadProgress, setImageUploadProgress] = useState(null); - const [active, setActive] = useState({ bold: false, italic: false, underline: false, strike: false, code: false }); - - const buttons = { ...defaultToolbarButtons, ...toolbarButtons }; - - useEffect(() => { - if (value !== undefined && value !== html) { - setHtml(value); - } - }, [value]); - - useEffect(() => { - if (!focusObserver) return; - focusObserver.setFocused = (focused) => { - const editor = quillRef.current?.getEditor?.(); - if (!editor) return; - if (focused) editor.focus(); - else editor.blur(); - }; - }, [focusObserver]); - - output.getValue = () => html.substring(0, maxLength); - - const updateActive = useCallback(() => { - const editor = quillRef.current?.getEditor?.(); - if (!editor) return; - const fmts = editor.getFormat(); - setActive({ - bold: !!fmts.bold, - italic: !!fmts.italic, - underline: !!fmts.underline, - strike: !!fmts.strike, - code: !!fmts.code, - }); - }, []); - - const toggleFormat = useCallback((name: keyof ActiveFormats) => { - const editor = quillRef.current?.getEditor?.(); - if (!editor) return; - editor.focus(); - const current = editor.getFormat(); - editor.format(name, !current[name]); - updateActive(); - }, [updateActive]); - - const insertImageByUrl = useCallback((url: string) => { - const editor = quillRef.current?.getEditor?.(); - if (!editor) return; - const range = editor.getSelection(true) || { index: editor.getLength(), length: 0 }; - editor.insertEmbed(range.index, 'image', url, 'user'); - editor.setSelection(range.index + 1, 0); - }, []); - - const handleImageUpload = async () => { - if (!pickImage) return; - try { - const photoData = await pickImage(); - if (!photoData) return; - if (typeof photoData === 'string' && photoData.startsWith('http')) { - insertImageByUrl(photoData); - return; - } - setImageUploadProgress(0); - const formData = new FormData(); - formData.append('file', photoData as string); - const xhr = new XMLHttpRequest(); - xhr.open('POST', apiHost + '/upload-image/' + tenantId); - xhr.upload.onprogress = (ev) => { - if (ev.lengthComputable) setImageUploadProgress(ev.loaded / ev.total); - }; - const url = await new Promise((resolve, reject) => { - xhr.onload = () => { - setImageUploadProgress(null); - if (xhr.status === 200) resolve(JSON.parse(xhr.response).url); - else reject(new Error(xhr.response)); - }; - xhr.onerror = () => { - setImageUploadProgress(null); - reject(new Error('Upload failed')); - }; - xhr.send(formData); - }); - insertImageByUrl(url); - } catch (err) { - console.error('Image upload failed:', err); - setImageUploadProgress(null); - } - }; - - const handleGIFPick = async () => { - if (!pickGIF) return; - try { - const url = await pickGIF(); - if (url) insertImageByUrl(url); - } catch (err) { - console.error('GIF pick failed:', err); - } - }; - - if (emoticonBarConfig) { - emoticonBarConfig.addEmoticon = (src: string) => { - insertImageByUrl(src); - }; - } - - const quillModules = useMemo(() => ({ toolbar: false }), []); - - const toolbarButtonStyle = useMemo(() => ({ - backgroundColor: hasDarkBackground ? '#444' : 'white', - paddingHorizontal: 8, - paddingVertical: 6, - borderRadius: 4, - borderWidth: 1, - borderColor: styles.commentTextArea?.textarea?.borderColor || (hasDarkBackground ? '#555' : '#a2a2a2'), - minWidth: 28, - alignItems: 'center' as const, - justifyContent: 'center' as const, - marginRight: 6, - }), [hasDarkBackground, styles.commentTextArea?.textarea?.borderColor]); - - const activeBackground = hasDarkBackground ? '#666' : '#d8d8d8'; - - return ( - - - { - setHtml(content); - updateActive(); - }} - onChangeSelection={updateActive} - onFocus={onFocus as any} - modules={quillModules} - formats={allowedFormats} - /> - - - {emoticonBarConfig?.emoticons && ( - - {emoticonBarConfig.emoticons.map(([src, element], index) => ( - emoticonBarConfig.addEmoticon?.(src)} - style={styles.commentTextAreaEmoticonBar?.button} - > - {element} - - ))} - - )} - - - {buttons.bold && ( - toggleFormat('bold')} - activeOpacity={0.7} - > - B - - )} - {buttons.italic && ( - toggleFormat('italic')} - activeOpacity={0.7} - > - I - - )} - {buttons.underline && ( - toggleFormat('underline')} - activeOpacity={0.7} - > - U - - )} - {buttons.strikethrough && ( - toggleFormat('strike')} - activeOpacity={0.7} - > - S - - )} - {buttons.code && ( - toggleFormat('code')} - activeOpacity={0.7} - > - {"<>"} - - )} - {buttons.image && pickImage && ( - - - - )} - {buttons.gif && pickGIF && ( - - - - )} - - - {imageUploadProgress !== null && ( - - - - - {Math.round(imageUploadProgress * 100)}% - - - - )} - - ); -} diff --git a/src/components/mention-popup.tsx b/src/components/mention-popup.tsx index 8cbfe0a..02303cf 100644 --- a/src/components/mention-popup.tsx +++ b/src/components/mention-popup.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'; import { ActivityIndicator, Image, @@ -23,7 +23,20 @@ export interface MentionPopupProps { onSelect: (user: MentionUser) => void; } -export function MentionPopup({ store, styles, query, onSelect }: MentionPopupProps) { +/** + * Imperative handle so the editor can drive the popup from the keyboard + * (arrow keys to move the highlight, Enter/Tab to select). `handleKey` returns + * true when it consumed the key, so the caller knows to preventDefault. + */ +export interface MentionPopupHandle { + isOpen: () => boolean; + handleKey: (key: string) => boolean; +} + +export const MentionPopup = forwardRef(function MentionPopup( + { store, styles, query, onSelect }, + ref +) { const tenantId = useStoreValue(store, (s) => s.config.tenantId); const urlId = useStoreValue(store, (s) => s.config.urlId); const ssoConfigString = useStoreValue(store, (s) => s.ssoConfigString); @@ -33,6 +46,7 @@ export function MentionPopup({ store, styles, query, onSelect }: MentionPopupPro const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(0); const requestSeqRef = useRef(0); useEffect(() => { @@ -71,6 +85,32 @@ export function MentionPopup({ store, styles, query, onSelect }: MentionPopupPro return () => clearTimeout(handle); }, [query, store, tenantId, urlId, ssoConfigString]); + // Highlight the first result whenever the result set changes. + useEffect(() => { + setSelectedIndex(0); + }, [users]); + + useImperativeHandle(ref, () => ({ + isOpen: () => query !== undefined && users.length > 0, + handleKey: (key: string): boolean => { + if (query === undefined || users.length === 0) return false; + if (key === 'ArrowDown') { + setSelectedIndex((i) => (i + 1) % users.length); + return true; + } + if (key === 'ArrowUp') { + setSelectedIndex((i) => (i - 1 + users.length) % users.length); + return true; + } + if (key === 'Enter' || key === 'Tab') { + const user = users[selectedIndex] || users[0]; + if (user) onSelect(user); + return true; + } + return false; + }, + }), [query, users, selectedIndex, onSelect]); + const popupStyle = useMemo(() => ({ backgroundColor: hasDarkBackground ? '#2c2c2c' : 'white', borderRadius: 8, @@ -108,14 +148,16 @@ export function MentionPopup({ store, styles, query, onSelect }: MentionPopupPro )} {users.length > 0 && ( - {users.map((user) => { + {users.map((user, index) => { const label = user.displayName || user.name; + const isSelected = index === selectedIndex; return ( onSelect(user)} + onPressIn={() => setSelectedIndex(index)} style={[ { flexDirection: 'row', @@ -124,6 +166,7 @@ export function MentionPopup({ store, styles, query, onSelect }: MentionPopupPro paddingHorizontal: 12, }, styles.mentionPopup?.item, + isSelected && { backgroundColor: hasDarkBackground ? '#3a3a3a' : '#eef2ff' }, ]} > ); -} +}); diff --git a/src/components/mention-portal.tsx b/src/components/mention-portal.tsx new file mode 100644 index 0000000..5f6fea9 --- /dev/null +++ b/src/components/mention-portal.tsx @@ -0,0 +1,10 @@ +import * as React from 'react'; + +/** + * Native (and any non-web bundler / jest) has no DOM portal, so render the + * mention dropdown in place. The web variant (mention-portal.web.tsx) portals it + * to document.body so it can escape the scrollable comment list. + */ +export function MentionPortal({ children }: { children: React.ReactNode }) { + return <>{children}; +} diff --git a/src/components/mention-portal.web.tsx b/src/components/mention-portal.web.tsx new file mode 100644 index 0000000..88b85b1 --- /dev/null +++ b/src/components/mention-portal.web.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +// `react-dom` is only present in a web bundler context (it's a react-native-web +// peer). The SDK's own tsconfig has no react-dom installed, so suppress the +// resolution error here; web bundlers (vite/webpack) resolve it fine. +// @ts-ignore - resolved by the web bundler, not the SDK's tsconfig +import { createPortal } from 'react-dom'; + +/** + * Render the mention dropdown into document.body. The composer lives inside the + * scrollable, transformed comment list, which clips an absolutely/fixed + * positioned popup and paints later comment-row cells on top of it. Portaling to + * body escapes that container entirely; the popup is then positioned via a fixed + * style measured off the editor box (see comment-text-area `mentionOverlayStyle`). + */ +export function MentionPortal({ children }: { children: React.ReactNode }) { + if (typeof document === 'undefined') return <>{children}; + return createPortal(children, document.body); +} diff --git a/src/components/reply-area.tsx b/src/components/reply-area.tsx index f2ee755..ce1b900 100644 --- a/src/components/reply-area.tsx +++ b/src/components/reply-area.tsx @@ -180,6 +180,17 @@ async function submit( (currentUserBeforeSubmit && 'email' in currentUserBeforeSubmit && (currentUserBeforeSubmit as any).email) )))) ) { + // The submit can't proceed (no text, or guest hasn't supplied the + // name/email this tenant requires). The caller turned the spinner on + // before awaiting us; reset it so it doesn't hang forever, and surface + // the name/email form when identity is what's missing. + const missingIdentity = + !!replyState.comment && + !allowAnon && + !(replyState.username || (currentUserBeforeSubmit as any)?.username); + const patch: Partial = { isReplySaving: false }; + if (missingIdentity) patch.showAuthInputForm = true; + setReplyState(patch); return; } @@ -260,15 +271,18 @@ async function submit( incOverallCommentCount(latest.config.countAll, store, comment.parentId); if (response.user) { - const responseUser = response.user; - if (latest.config.simpleSSO) { - latest.setCurrentUser({ - ...(latest.currentUser as object), - ...responseUser, - } as FastCommentsSessionUser); - } else { - latest.setCurrentUser(responseUser as FastCommentsSessionUser); - } + // Merge the server's user into the existing session, like the web + // widget (frontend/comment-ui copies each response.user key onto + // currentUser). The server returns an authorized user with the + // email/username the guest just entered; consuming it hides the + // name/email form and populates the top bar. Merging (vs replacing) + // preserves any fields the response omits (e.g. avatar). + const existingUser = latest.currentUser as object | null; + latest.setCurrentUser( + (existingUser + ? { ...existingUser, ...response.user } + : response.user) as FastCommentsSessionUser + ); onAuthenticationChange && onAuthenticationChange('user-set', store.getState().currentUser, comment); } @@ -279,12 +293,19 @@ async function submit( 'sessionId' in response.user && response.user.sessionId ) { - latest.setCurrentUser({ - ...(latest.currentUser as object), - sessionId: response.user.sessionId, - } as FastCommentsSessionUser); - onAuthenticationChange && - onAuthenticationChange('session-id-set', store.getState().currentUser, comment); + // Apply the sessionId on top of the freshly-merged user. Reading + // `store.getState().currentUser` (not the stale `latest` snapshot + // captured before the merge above) avoids reverting to the prior + // anon user, which is what kept the auth form showing after submit. + const mergedUser = store.getState().currentUser as object | null; + if (mergedUser) { + latest.setCurrentUser({ + ...mergedUser, + sessionId: response.user.sessionId, + } as FastCommentsSessionUser); + onAuthenticationChange && + onAuthenticationChange('session-id-set', store.getState().currentUser, comment); + } } if (replyingToId === null && !latest.config.disableSuccessMessage) showSuccessMessage = true; const newCurrentUserId = @@ -368,7 +389,16 @@ export function ReplyArea(props: ReplyAreaProps) { const ssoConfig = useStoreValue(store, (s) => s.config.sso || s.config.simpleSSO); const inlineReactImages = useStoreValue(store, (s) => s.config.inlineReactImages); - const needsAuth = !currentUser && !!parentComment; + // Mirror the web widget (frontend/shared/get-reply-area-html.ts): a guest must + // supply a name (and email, unless the tenant allows fully-anonymous) before + // commenting. Show the auth prompt when there's no authorized user, or when an + // anon session still owes us an email. The old `!currentUser && !!parentComment` + // was wrong: it only prompted on replies and treated the anon session (which + // exists from connect, with no username/email) as fully logged in - so root + // comments silently failed validation. + const currentUserAny = currentUser as { authorized?: boolean; isAnonSession?: boolean; email?: string } | null | undefined; + const anonSessionNeedsEmail = !!(currentUserAny && currentUserAny.isAnonSession && !currentUserAny.email && !allowAnon); + const needsAuth = !currentUserAny || !currentUserAny.authorized || anonSessionNeedsEmail; const valueGetter: ValueObserver = {}; const focusObserver: FocusObserver = {}; @@ -413,7 +443,7 @@ export function ReplyArea(props: ReplyAreaProps) { let commentSubmitButton = null; let authFormArea = null; - if (!currentUser && ssoConfig && !allowAnon) { + if (needsAuth && ssoConfig && !allowAnon) { if (ssoConfig.loginURL || ssoConfig.loginCallback) { ssoLoginWrapper = ( @@ -586,7 +616,11 @@ export function ReplyArea(props: ReplyAreaProps) { ); } + // Like the frontend, render the name/email inputs whenever the guest still + // needs to identify themselves (recomputed each render so it tracks the + // anon session loading in), plus the explicit toggle / signup-error cases. const showAuth = + needsAuth || commentReplyState.showAuthInputForm || (commentReplyState.lastSaveResponse?.code && SignUpErrorsTranslationIds[commentReplyState.lastSaveResponse.code!]); @@ -607,7 +641,7 @@ export function ReplyArea(props: ReplyAreaProps) { textContentType="emailAddress" keyboardType="email-address" autoComplete="email" - value={commentReplyState.email} + value={commentReplyState.email || ''} returnKeyType={enableCommenterLinks ? 'next' : 'send'} onChangeText={(value) => setCommentReplyState({ email: value })} /> @@ -619,7 +653,7 @@ export function ReplyArea(props: ReplyAreaProps) { placeholder={translations.PUBLICLY_DISPLAYED_USERNAME} textContentType="username" autoComplete="username" - value={commentReplyState.username} + value={commentReplyState.username || ''} returnKeyType={enableCommenterLinks ? 'next' : 'send'} onChangeText={(value) => setCommentReplyState({ username: value })} /> diff --git a/src/resources/styles.ts b/src/resources/styles.ts index a51344f..7ff06ec 100644 --- a/src/resources/styles.ts +++ b/src/resources/styles.ts @@ -1,13 +1,16 @@ import {IFastCommentsStyles} from "../types"; import {ViewStyle} from "react-native"; +// The loading state is a sole, full-area render (the widget early-returns this +// while fetching). It must NOT be `position: absolute`: an absolutely-positioned +// sole child is out of flow, so its container collapses to 0 height, and on web +// (where the host's #root is not always a flex container that propagates height) +// a 0-height `inset: 0` box centers the spinner on y=0 - i.e. half off the top of +// the screen. Filling via normal flow (flex + a minHeight floor) centers it +// reliably on both web and native. const LoadingOverlay: ViewStyle = { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, flex: 1, + minHeight: 200, alignItems: 'center', justifyContent: 'center', backgroundColor: '#ffffff50' diff --git a/src/services/__tests__/mention-detection.test.ts b/src/services/__tests__/mention-detection.test.ts new file mode 100644 index 0000000..a46c6b1 --- /dev/null +++ b/src/services/__tests__/mention-detection.test.ts @@ -0,0 +1,120 @@ +import { detectMentionQuery, htmlToPlainText, replaceActiveMention } from '../mention-detection'; + +// Committed mentions end with a non-breaking space (so the trailing space isn't +// collapsed by the HTML editor). Tests assert against it explicitly. +const NBSP = '\u00a0'; + +describe('detectMentionQuery', () => { + describe('plain text (legacy / native paths)', () => { + it('returns the query after a leading @', () => { + expect(detectMentionQuery('@a')).toBe('a'); + expect(detectMentionQuery('@alice')).toBe('alice'); + }); + + it('returns the query after an @ at a word boundary', () => { + expect(detectMentionQuery('hello @bob')).toBe('bob'); + }); + + it('returns undefined with no @', () => { + expect(detectMentionQuery('hello world')).toBeUndefined(); + }); + + it('returns undefined when @ is mid-token (e.g. an email)', () => { + expect(detectMentionQuery('me@example')).toBeUndefined(); + }); + + it('terminates the mention on a trailing space', () => { + expect(detectMentionQuery('@bob ')).toBeUndefined(); + }); + + it('terminates at the first space - no re-trigger after a completed mention', () => { + // After selecting a mention we insert "@name " as plain text; once the + // user keeps typing ("@name hello") the query must NOT reactivate. + expect(detectMentionQuery('@asdad hello')).toBeUndefined(); + expect(detectMentionQuery('

@asdad hello world

')).toBeUndefined(); + }); + + it('treats a non-breaking space as a terminator too', () => { + // The committed mention "@nameĀ " must not be read as an active query. + expect(detectMentionQuery('@asdad' + NBSP)).toBeUndefined(); + expect(detectMentionQuery('

@asdad' + NBSP + 'hello

')).toBeUndefined(); + }); + + it('still tracks a single token being typed', () => { + expect(detectMentionQuery('

@asd

')).toBe('asd'); + }); + + it('a second, fresh mention after a completed one is active', () => { + expect(detectMentionQuery('

@asdad hello @bo

')).toBe('bo'); + }); + }); + + // The web (tiptap) editor - and react-native-enriched generally - emit the + // value wrapped in block elements (e.g. `

...

`). The + // `

` becomes a trailing newline in plain text, which previously made the + // detector bail and the mention popup never appear on web. + describe('block-wrapped HTML (real editor output)', () => { + it('detects a mention in

-wrapped HTML', () => { + expect(detectMentionQuery('

@a

')).toBe('a'); + expect(detectMentionQuery('

@alice

')).toBe('alice'); + }); + + it('detects a mention in the web build full-document HTML', () => { + expect(detectMentionQuery('

@a

')).toBe('a'); + expect(detectMentionQuery('

hello @bob

')).toBe('bob'); + }); + + it('still terminates on a trailing space inside block HTML', () => { + expect(detectMentionQuery('

@bob

')).toBeUndefined(); + }); + + it('does not trigger when the @ is on an earlier line/paragraph', () => { + // User typed "@foo", pressed enter, and is now typing on a new line. + expect(detectMentionQuery('

@foo

bar

')).toBeUndefined(); + }); + + it('detects a mention typed on a later line', () => { + expect(detectMentionQuery('

line one

@bob

')).toBe('bob'); + }); + }); +}); + +describe('replaceActiveMention', () => { + it('replaces the @query inline in block-wrapped HTML (no new line)', () => { + // Regression: previously produced "

@a

@audrey" which + // re-parsed to "@a\n@audrey". + expect(replaceActiveMention('

@a

', 'audrey')).toBe('

@audrey' + NBSP + '

'); + expect(replaceActiveMention('

@a

', 'audrey')).toBe('

@audrey' + NBSP + '

'); + }); + + it('replaces the @query in plain text', () => { + expect(replaceActiveMention('@a', 'audrey')).toBe('@audrey' + NBSP); + expect(replaceActiveMention('hello @bo', 'Bob Smith')).toBe('hello @Bob Smith' + NBSP); + }); + + it('keeps text before the mention intact', () => { + expect(replaceActiveMention('

great point @al

', 'Alice')).toBe('

great point @Alice' + NBSP + '

'); + }); + + it('handles a bare @ (empty query)', () => { + expect(replaceActiveMention('

hi @

', 'x')).toBe('

hi @x' + NBSP + '

'); + }); + + it('escapes HTML-significant characters in the label', () => { + expect(replaceActiveMention('

@a

', 'a&c')).toBe('

@a<b>&c' + NBSP + '

'); + }); + + it('ends with a non-breaking space so the next keystroke does not re-trigger', () => { + const result = replaceActiveMention('

@as

', 'asdad'); + expect(result).toBe('

@asdad' + NBSP + '

'); + // detection on the committed value must be inactive + expect(detectMentionQuery(result)).toBeUndefined(); + }); +}); + +describe('htmlToPlainText', () => { + it('strips tags and decodes entities', () => { + expect(htmlToPlainText('

a & b

')).toBe('a & b\n'); + expect(htmlToPlainText('')).toBe(''); + }); +}); diff --git a/src/services/mention-detection.ts b/src/services/mention-detection.ts new file mode 100644 index 0000000..661de04 --- /dev/null +++ b/src/services/mention-detection.ts @@ -0,0 +1,78 @@ +// Pure helpers for detecting an in-progress `@mention` from the rich-text HTML +// the comment editor emits. Kept dependency-free (no react-native) so they can +// be unit-tested directly and shared across platforms. + +// Non-breaking space inserted after a committed mention. A regular trailing +// space collapses in HTML (the editor trims "

@name

"), which would let +// the user's next keystrokes attach to the name and re-trigger detection. NBSP +// is preserved and still counts as whitespace for the regexes below. +const MENTION_TRAILING_SPACE = '\u00a0'; + +/** + * Strip simple HTML tags / decode common entities so we can detect `@...` triggers + * in rich-text HTML the editor emits. Comment editors typically wrap text in + *

/

with breaks; we just need readable text for the trigger regex. + */ +export function htmlToPlainText(html: string): string { + if (!html) return ''; + const stripped = html + .replace(/(\n)?/gi, '\n') + .replace(/<\/(p|div|li)>/gi, '\n') + .replace(/<[^>]+>/g, ''); + return stripped + .replace(/ /g, ' ') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, "'"); +} + +/** + * Returns the active mention query (text after the most recent `@` that starts + * a token) or undefined when no mention is active. The query is a single token: + * any whitespace after the `@` ends it. + */ +export function detectMentionQuery(value: string): string | undefined { + // Block elements (

,
, ) become newlines in plain text, so the + // editor's value almost always ends in one (`

@a

` -> "@a\n"). That + // trailing newline is structural, not typed, but the whitespace guard below + // would treat it as "the mention ended" - which is why the popup never showed + // on web/native rich-text. Drop trailing newlines (only) before detecting. + const text = htmlToPlainText(value).replace(/\n+$/, ''); + const atIdx = text.lastIndexOf('@'); + if (atIdx === -1) return undefined; + if (atIdx > 0) { + const prev = text.charAt(atIdx - 1); + if (!/\s/.test(prev)) return undefined; + } + const after = text.substring(atIdx + 1); + // Any whitespace after the `@` ends the trigger token. This dismisses on a + // trailing space and - importantly - stops the popup from reactivating when + // the user keeps typing past a completed mention (we insert mentions as plain + // "@name " text, so the old `@name` would otherwise keep matching). + if (/\s/.test(after)) return undefined; + return after; +} + +/** + * Replace the active `@query` in the editor's value with the committed mention + * (`@label` + a non-breaking space). Operates on the literal value string so it + * works for both plain text and the block-wrapped HTML the rich editor emits. + * The previous end-anchored regex failed on HTML like `

@a

` + * (the `@a` isn't at the end), fell through to appending, and the appended text + * re-parsed onto a new line ("@a\n@label"). Splicing at the located `@query` + * keeps the mention inline. + */ +export function replaceActiveMention(value: string, label: string): string { + const escLabel = label + .replace(/&/g, '&') + .replace(//g, '>'); + const replacement = '@' + escLabel + MENTION_TRAILING_SPACE; + const query = detectMentionQuery(value); + const needle = query !== undefined ? '@' + query : '@'; + const lastIdx = value.lastIndexOf(needle); + if (lastIdx === -1) return value + replacement; + return value.substring(0, lastIdx) + replacement + value.substring(lastIdx + needle.length); +} diff --git a/tests-ui/framework/mocks/react-native-enriched.tsx b/tests-ui/framework/mocks/react-native-enriched.tsx index 2e7af8a..bfa6286 100644 --- a/tests-ui/framework/mocks/react-native-enriched.tsx +++ b/tests-ui/framework/mocks/react-native-enriched.tsx @@ -22,6 +22,7 @@ export type EnrichedTextInputInstance = { toggleItalic: () => void; toggleUnderline: () => void; toggleStrikeThrough: () => void; + toggleInlineCode: () => void; }; export type OnChangeStateEvent = { @@ -29,6 +30,7 @@ export type OnChangeStateEvent = { italic?: { isActive?: boolean }; underline?: { isActive?: boolean }; strikeThrough?: { isActive?: boolean }; + inlineCode?: { isActive?: boolean }; }; export interface EnrichedTextInputProps { @@ -60,6 +62,7 @@ export const EnrichedTextInput = forwardRef {}, toggleUnderline: () => {}, toggleStrikeThrough: () => {}, + toggleInlineCode: () => {}, })); return ( diff --git a/tests-ui/specs/mentions.test.tsx b/tests-ui/specs/mentions.test.tsx index 9a2f03e..75373d2 100644 --- a/tests-ui/specs/mentions.test.tsx +++ b/tests-ui/specs/mentions.test.tsx @@ -52,8 +52,9 @@ maybe('Mention UI tests', () => { label: 'commentInput visible', }); - // Type "@Tester a" to trigger the mention search. - fireEvent.changeText(getByTestId('commentInput'), '@Tester a'); + // Type "@Tester" to trigger the mention search (the query is a single + // token - a space ends it - and "Tester" prefix-matches all seeded users). + fireEvent.changeText(getByTestId('commentInput'), '@Tester'); // Wait for the popup to appear. await pollUntil(() => !!queryByTestId('mentionPopup'), { @@ -118,14 +119,14 @@ maybe('Mention UI tests', () => { }); // Trigger the mention search. - fireEvent.changeText(getByTestId('commentInput'), '@Tester a'); + fireEvent.changeText(getByTestId('commentInput'), '@Tester'); await pollUntil(() => !!queryByTestId('mentionPopup'), { timeoutMs: 15000, label: 'mentionPopup visible', }); // Type a trailing space; popup should be dismissed. - fireEvent.changeText(getByTestId('commentInput'), '@Tester a '); + fireEvent.changeText(getByTestId('commentInput'), '@Tester '); await pollUntil(() => queryByTestId('mentionPopup') === null, { timeoutMs: 5000, label: 'mentionPopup dismissed after trailing space', diff --git a/yarn.lock b/yarn.lock index 238d28b..b00d312 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1081,6 +1081,26 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@floating-ui/core@^1.7.5": + version "1.7.5" + resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz" + integrity sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ== + dependencies: + "@floating-ui/utils" "^0.2.11" + +"@floating-ui/dom@^1.0.0": + version "1.7.6" + resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz" + integrity sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ== + dependencies: + "@floating-ui/core" "^1.7.5" + "@floating-ui/utils" "^0.2.11" + +"@floating-ui/utils@^0.2.11": + version "0.2.11" + resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz" + integrity sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" @@ -1621,6 +1641,11 @@ resolved "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-2.0.0.tgz" integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ== +"@remirror/core-constants@3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz" + integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg== + "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz" @@ -1666,6 +1691,126 @@ pretty-format "^29.7.0" redent "^3.0.0" +"@tiptap/core@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/core/-/core-3.20.4.tgz" + integrity sha512-3i/DG89TFY/b34T5P+j35UcjYuB5d3+9K8u6qID+iUqNPiza015HPIZLuPfE5elNwVdV3EXIoPo0LLeBLgXXAg== + +"@tiptap/extension-blockquote@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.20.4.tgz" + integrity sha512-9sskyyhYj2oKat//lyZVXCp9YrPt4oJAZnGHYWXS0xlskjsLElrfKKlM4vpbhGss3VrhQRoEGqWLnIaJYPF1zw== + +"@tiptap/extension-bold@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.20.4.tgz" + integrity sha512-Md7/mNAeJCY+VLJc8JRGI+8XkVPKiOGB1NgqQPdh3aYtxXQDChQOZoJEQl6TuudDxZ85bLZB67NjZlx3jo8/0g== + +"@tiptap/extension-bubble-menu@^3.20.4": + version "3.24.0" + resolved "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.24.0.tgz" + integrity sha512-jRXD+JPu9ayvq78g8hsCxx4q/qUFtrdfIYirRSf5YUseuuUbtfrq83AsGabcygpUTefjJkMQoXNITkh6294Ggw== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@tiptap/extension-code@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.20.4.tgz" + integrity sha512-7j8Hi964bH1SZ9oLdZC1fkqWz27mliSDV7M8lmL/M14+Qw42D/VOAKS4Aw9OCFtHMlTsjLR6qsoVxL8Lpkt6NA== + +"@tiptap/extension-document@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.20.4.tgz" + integrity sha512-zF1CIFVLt8MfSpWWnPwtGyxPOsT0xYM2qJKcXf2yZcTG37wDKmUi6heG53vGigIavbQlLaAFvs+1mNdOu2x/0A== + +"@tiptap/extension-floating-menu@^3.20.4": + version "3.24.0" + resolved "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-3.24.0.tgz" + integrity sha512-7QEbf3mUzFAkejjQGX9f0L507oMtnOBRwHt2skUTR+9yXgudsN8zaDBSSRHLeMWGk9b7L293ZMA6zCRrZaHrfA== + +"@tiptap/extension-heading@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.20.4.tgz" + integrity sha512-xsnkmTGggJc5P2iCwS1lv8KFG31xC/GNPJKoi/3UH67j/lKDhA3AdtshsLeyv2FKtTtYDb8oV0IqzHB1MM6a7w== + +"@tiptap/extension-italic@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.20.4.tgz" + integrity sha512-4ZqiWr7cmqPFux8tj1ZLiYytyWf343IvQemNX6AvVWvscrJcrfj3YX4Le2BA0RW3A3M6RpLQXXozuF8vxYFDeQ== + +"@tiptap/extension-link@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.20.4.tgz" + integrity sha512-JNDSkWrVdb8NSvbQXwHWvK5tCMbTWwOHFOweknQZ1JPK4dei9FJVofYQaHyW4bJBdcCjds3NZSnXE8DM9iAWmg== + dependencies: + linkifyjs "^4.3.2" + +"@tiptap/extension-list@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.4.tgz" + integrity sha512-X+5plTKhOioNcQ4KsAFJJSb/3+zR8Xhdpow4HzXtoV1KcbdDey1fhZdpsfkbrzCL0s6/wAgwZuAchCK7HujurQ== + +"@tiptap/extension-paragraph@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.20.4.tgz" + integrity sha512-lm6fOScWuZAF/Sfp97igUwFd3L1QHIVLAWP5NVdh0DTLrEIt4rMBmsww+yOpMQRhvz2uTgMbMXynrimhzi/QVw== + +"@tiptap/extension-strike@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.20.4.tgz" + integrity sha512-It1Px9uDGTsVqyyg6cy7DigLoenljpQwqdI0jssM7QclZrHnsrye9fZxBBiiuCzzV1305MxKgHvratkHwqmVNA== + +"@tiptap/extension-text@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.4.tgz" + integrity sha512-jchJcBZixDEO2J66Zx5dchsI2mA6IYsROqF8P1poxL4ienH7RVQRCTsBNnSfIeOtREKKWeOU/tEs5fcpvvGwIQ== + +"@tiptap/extension-underline@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.20.4.tgz" + integrity sha512-0OjMc3FDujX16G+jhvqcY/mLot8SrNtDu8ggUwNLAfiI/QIvMVgk7giFD71DATC/4Nb8i/iwAEegTD8MxBIXCg== + +"@tiptap/extensions@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.4.tgz" + integrity sha512-8p6hVT65DjuQjtEdlH6ewX9SOJHlVQAOee3sWIJQmeJNRnZNvqPIBLleebUqDiljNTpxBv6s6QWkSTKgf3btwg== + +"@tiptap/pm@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.4.tgz" + integrity sha512-rCHYSBToilBEuI6PtjziHDdRkABH/XqwJ7dG4Amn/SD3yGiZKYCiEApQlTUS2zZeo8DsLeuqqqB4vEOeD4OEPg== + dependencies: + prosemirror-changeset "^2.3.0" + prosemirror-collab "^1.3.1" + prosemirror-commands "^1.6.2" + prosemirror-dropcursor "^1.8.1" + prosemirror-gapcursor "^1.3.2" + prosemirror-history "^1.4.1" + prosemirror-inputrules "^1.4.0" + prosemirror-keymap "^1.2.2" + prosemirror-markdown "^1.13.1" + prosemirror-menu "^1.2.4" + prosemirror-model "^1.24.1" + prosemirror-schema-basic "^1.2.3" + prosemirror-schema-list "^1.5.0" + prosemirror-state "^1.4.3" + prosemirror-tables "^1.6.4" + prosemirror-trailing-node "^3.0.0" + prosemirror-transform "^1.10.2" + prosemirror-view "^1.38.1" + +"@tiptap/react@3.20.4": + version "3.20.4" + resolved "https://registry.npmjs.org/@tiptap/react/-/react-3.20.4.tgz" + integrity sha512-1B8iWsHWwb5TeyVaUs8BRPzwWo4PsLQcl03urHaz0zTJ8DauopqvxzV3+lem1OkzRHn7wnrapDvwmIGoROCaQw== + dependencies: + "@types/use-sync-external-store" "^0.0.6" + fast-equals "^5.3.3" + use-sync-external-store "^1.4.0" + optionalDependencies: + "@tiptap/extension-bubble-menu" "^3.20.4" + "@tiptap/extension-floating-menu" "^3.20.4" + "@types/babel__core@^7.1.14": version "7.1.19" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" @@ -1733,11 +1878,29 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/linkify-it@^5": + version "5.0.0" + resolved "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz" + integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== + "@types/lodash@^4.14.184": version "4.14.185" resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.185.tgz" integrity sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA== +"@types/markdown-it@^14.0.0": + version "14.1.2" + resolved "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz" + integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog== + dependencies: + "@types/linkify-it" "^5" + "@types/mdurl" "^2" + +"@types/mdurl@^2": + version "2.0.0" + resolved "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz" + integrity sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg== + "@types/node@*": version "18.7.18" resolved "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz" @@ -1795,6 +1958,11 @@ resolved "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz" integrity sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg== +"@types/use-sync-external-store@^0.0.6": + version "0.0.6" + resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz" + integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== + "@types/ws@^8.18.1": version "8.18.1" resolved "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz" @@ -1933,6 +2101,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" @@ -2612,6 +2785,11 @@ cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +crelt@^1.0.0: + version "1.0.6" + resolved "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" @@ -2901,6 +3079,11 @@ entities@^3.0.1: resolved "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz" integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + envinfo@^7.7.2: version "7.14.0" resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz" @@ -2948,6 +3131,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" @@ -2968,11 +3156,6 @@ event-target-shim@^5.0.0, event-target-shim@^5.0.1: resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@^5.0.1: - version "5.0.4" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz" - integrity sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw== - execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" @@ -3074,10 +3257,10 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-diff@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== +fast-equals@^5.3.3: + version "5.4.0" + resolved "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz" + integrity sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw== fast-glob@^2.0.2: version "2.2.7" @@ -3108,7 +3291,7 @@ fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== "fastcomments-sdk@file:../fastcomments-sdk-js": - version "3.2.2" + version "3.2.3" resolved "file:../fastcomments-sdk-js" fastcomments-typescript@^3.0.0: @@ -4500,6 +4683,18 @@ lines-and-columns@^1.1.6: resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz" + integrity sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg== + dependencies: + uc.micro "^2.0.0" + +linkifyjs@^4.3.2: + version "4.3.3" + resolved "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.3.tgz" + integrity sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg== + load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz" @@ -4540,26 +4735,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash-es@^4.17.21: - version "4.18.1" - resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz" - integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A== - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" - integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - lodash.memoize@4.x: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" @@ -4663,6 +4843,23 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-it@^14.0.0: + version "14.2.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz" + integrity sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.1" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + memoize-one@^5.0.0: version "5.2.1" resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz" @@ -5444,6 +5641,11 @@ ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" +orderedmap@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz" + integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g== + os-tmpdir@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" @@ -5527,11 +5729,6 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -parchment@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz" - integrity sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" @@ -5757,6 +5954,160 @@ prop-types@^15.5.7: object-assign "^4.1.1" react-is "^16.13.1" +prosemirror-changeset@^2.3.0: + version "2.4.1" + resolved "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz" + integrity sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw== + dependencies: + prosemirror-transform "^1.0.0" + +prosemirror-collab@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz" + integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ== + dependencies: + prosemirror-state "^1.0.0" + +prosemirror-commands@^1.0.0, prosemirror-commands@^1.6.2: + version "1.7.1" + resolved "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz" + integrity sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.10.2" + +prosemirror-dropcursor@^1.8.1: + version "1.8.2" + resolved "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz" + integrity sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.3.2: + version "1.4.1" + resolved "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz" + integrity sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.0.0, prosemirror-history@^1.4.1: + version "1.5.0" + resolved "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz" + integrity sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg== + dependencies: + prosemirror-state "^1.2.2" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.31.0" + rope-sequence "^1.3.0" + +prosemirror-inputrules@^1.4.0: + version "1.5.1" + resolved "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz" + integrity sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.2.2, prosemirror-keymap@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz" + integrity sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw== + dependencies: + prosemirror-state "^1.0.0" + w3c-keyname "^2.2.0" + +prosemirror-markdown@^1.13.1: + version "1.13.4" + resolved "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz" + integrity sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw== + dependencies: + "@types/markdown-it" "^14.0.0" + markdown-it "^14.0.0" + prosemirror-model "^1.25.0" + +prosemirror-menu@^1.2.4: + version "1.3.2" + resolved "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.2.tgz" + integrity sha512-6VgUJTYod0nMBlCaYJGhXGLu7Gt4AvcwcOq0YfJCY/6Uh+3S7UsWhpy6rJFCBFOmonq1hD8KyWOtZhkppd4YPg== + dependencies: + crelt "^1.0.0" + prosemirror-commands "^1.0.0" + prosemirror-history "^1.0.0" + prosemirror-state "^1.0.0" + +prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.24.1, prosemirror-model@^1.25.0, prosemirror-model@^1.25.4: + version "1.25.7" + resolved "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.7.tgz" + integrity sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug== + dependencies: + orderedmap "^2.0.0" + +prosemirror-schema-basic@^1.2.3: + version "1.2.4" + resolved "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz" + integrity sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ== + dependencies: + prosemirror-model "^1.25.0" + +prosemirror-schema-list@^1.5.0: + version "1.5.1" + resolved "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz" + integrity sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.7.3" + +prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3, prosemirror-state@^1.4.4: + version "1.4.4" + resolved "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz" + integrity sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.27.0" + +prosemirror-tables@^1.6.4: + version "1.8.5" + resolved "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz" + integrity sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw== + dependencies: + prosemirror-keymap "^1.2.3" + prosemirror-model "^1.25.4" + prosemirror-state "^1.4.4" + prosemirror-transform "^1.10.5" + prosemirror-view "^1.41.4" + +prosemirror-trailing-node@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz" + integrity sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ== + dependencies: + "@remirror/core-constants" "3.0.0" + escape-string-regexp "^4.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.10.2, prosemirror-transform@^1.10.5, prosemirror-transform@^1.7.3: + version "1.12.0" + resolved "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz" + integrity sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w== + dependencies: + prosemirror-model "^1.21.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.38.1, prosemirror-view@^1.41.4: + version "1.41.8" + resolved "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz" + integrity sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA== + dependencies: + prosemirror-model "^1.20.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + pump@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" @@ -5765,6 +6116,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" @@ -5775,25 +6131,6 @@ quick-lru@^1.0.0: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz" integrity sha512-tRS7sTgyxMXtLum8L65daJnHUhfDUgboRdcWW2bR9vBfrj2+O5HSMbQOJfJJjIVSPFqbBCF37FpwWXGitDc5tA== -quill-delta@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz" - integrity sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA== - dependencies: - fast-diff "^1.3.0" - lodash.clonedeep "^4.5.0" - lodash.isequal "^4.5.0" - -quill@^2.0.3, quill@~2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz" - integrity sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw== - dependencies: - eventemitter3 "^5.0.1" - lodash-es "^4.17.21" - parchment "^3.0.0" - quill-delta "^5.1.0" - ramda@^0.27.2: version "0.27.2" resolved "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz" @@ -5869,10 +6206,27 @@ react-native-codegen@^0.69.2: jscodeshift "^0.13.1" nullthrows "^1.1.1" -react-native-enriched@^0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.5.2.tgz" - integrity sha512-9texMnu5+CXLCuVJv987UmzgB70F8Q3okOm2zqZ8jYSEz8IGyd7kbJdZ4J1rW99x3hYaeV+u+cSECzrCj7F4EA== +react-native-enriched@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/react-native-enriched/-/react-native-enriched-0.7.0.tgz" + integrity sha512-WrhaRUMM8HaV+6XwESS1k7i1/QxZb4K2lpELIxLTiXXMdUP5b9207AjXp6d8Op0XulvFNC8HJdDdanQZUUI6Zg== + dependencies: + "@tiptap/core" "3.20.4" + "@tiptap/extension-blockquote" "3.20.4" + "@tiptap/extension-bold" "3.20.4" + "@tiptap/extension-code" "3.20.4" + "@tiptap/extension-document" "3.20.4" + "@tiptap/extension-heading" "3.20.4" + "@tiptap/extension-italic" "3.20.4" + "@tiptap/extension-link" "3.20.4" + "@tiptap/extension-list" "3.20.4" + "@tiptap/extension-paragraph" "3.20.4" + "@tiptap/extension-strike" "3.20.4" + "@tiptap/extension-text" "3.20.4" + "@tiptap/extension-underline" "3.20.4" + "@tiptap/extensions" "3.20.4" + "@tiptap/pm" "3.20.4" + "@tiptap/react" "3.20.4" react-native-gradle-plugin@^0.0.7: version "0.0.7" @@ -5933,14 +6287,6 @@ react-native@^0.69.4: whatwg-fetch "^3.0.0" ws "^6.1.4" -react-quill-new@^3.8.3: - version "3.8.3" - resolved "https://registry.npmjs.org/react-quill-new/-/react-quill-new-3.8.3.tgz" - integrity sha512-c96PYqFTo0pI4R3e79B3rH9LUIce1kIQbmTBu/imJQZk8305ogyLyBqKKjG2UoInDlquXqePSzmBo2aVia3ttw== - dependencies: - lodash-es "^4.17.21" - quill "~2.0.3" - react-refresh@^0.4.0: version "0.4.3" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz" @@ -6201,6 +6547,11 @@ rimraf@~2.6.2: dependencies: glob "^7.1.3" +rope-sequence@^1.3.0: + version "1.3.4" + resolved "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz" + integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -6852,6 +7203,11 @@ typescript@^4.7.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz" integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + uglify-es@^3.1.9: version "3.3.10" resolved "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.10.tgz" @@ -6939,10 +7295,10 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== -use-sync-external-store@^1.0.0: - version "1.2.0" - resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +use-sync-external-store@^1.0.0, use-sync-external-store@^1.4.0: + version "1.6.0" + resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz" + integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== use@^3.1.0: version "3.1.1" @@ -6986,6 +7342,11 @@ vlq@^1.0.0: resolved "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== +w3c-keyname@^2.2.0: + version "2.2.8" + resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz"