From 846e11cc2f4512825f813d56ecdb55127cae2eee Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 2 Jun 2026 00:44:30 -0700
Subject: [PATCH 1/6] Migrate web editor from Quill to react-native-enriched
Unify the comment composer on react-native-enriched across all platforms.
Previously native used react-native-enriched (0.5.2) while web used Quill
(react-quill-new); now that react-native-enriched 0.7.0 ships experimental
web support via package `exports` conditions, both platforms share a single
implementation.
- Bump react-native-enriched 0.5.2 -> 0.7.0 (web support); make it a
required (non-optional) peer at >=0.7.0.
- Drop quill / react-quill-new from dev and peer dependencies.
- Collapse comment-text-area.native.tsx + comment-text-area.web.tsx into a
single comment-text-area.tsx. The same EnrichedTextInput API resolves to
the native build on Metro and the web build on web bundlers, so web now
gets the @mention popup that the Quill path was missing, plus inline-code
formatting (toggleInlineCode) on both platforms.
- example-web: pre-bundle react-native-enriched instead of quill, and add an
exact-match react-native -> react-native-web alias so the enriched web
build's bare `react-native` import (processColor) resolves during the
production build.
- Update the stale README (it still referenced the long-removed 10tap editor
and react-native-webview) and the tests-ui enriched mock.
---
README.md | 6 +-
example-web/vite.config.ts | 11 +-
package-lock.json | 1459 ++++++++++++++---
package.json | 15 +-
...-area.native.tsx => comment-text-area.tsx} | 13 +-
src/components/comment-text-area.web.tsx | 379 -----
.../framework/mocks/react-native-enriched.tsx | 3 +
yarn.lock | 491 +++++-
8 files changed, 1731 insertions(+), 646 deletions(-)
rename src/components/{comment-text-area.native.tsx => comment-text-area.tsx} (95%)
delete mode 100644 src/components/comment-text-area.web.tsx
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/vite.config.ts b/example-web/vite.config.ts
index 5110473..af4d36e 100644
--- a/example-web/vite.config.ts
+++ b/example-web/vite.config.ts
@@ -54,6 +54,14 @@ 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')) },
],
extensions: ['.web.tsx', '.web.ts', '.web.jsx', '.web.js', '.tsx', '.ts', '.jsx', '.js', '.json'],
mainFields: ['module', 'browser', 'main'],
@@ -83,8 +91,7 @@ export default defineConfig({
'react-native-web > postcss-value-parser',
'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 95%
rename from src/components/comment-text-area.native.tsx
rename to src/components/comment-text-area.tsx
index fc1e77e..29ab62e 100644
--- a/src/components/comment-text-area.native.tsx
+++ b/src/components/comment-text-area.tsx
@@ -66,6 +66,7 @@ type ActiveFormats = {
italic: boolean
underline: boolean
strikethrough: boolean
+ code: boolean
};
const defaultToolbarButtons: ToolbarButtonConfig = {
@@ -139,7 +140,7 @@ export function CommentTextArea({
const editorRef = useRef(null);
const htmlRef = useRef(value || '');
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);
const buttons = { ...defaultToolbarButtons, ...toolbarButtons };
@@ -199,6 +200,7 @@ export function CommentTextArea({
italic: !!s.italic?.isActive,
underline: !!s.underline?.isActive,
strikethrough: !!s.strikeThrough?.isActive,
+ code: !!s.inlineCode?.isActive,
});
}, []);
@@ -361,6 +363,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/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/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"
From ebc5db95f7e432c26669d545cc3a0f897331d830 Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 9 Jun 2026 21:19:08 -0700
Subject: [PATCH 2/6] example-web: run demo on React 19 + react-native-web 0.21
react-native-enriched 0.7.0's component reads `ref` as a prop (React 19
convention), so the web editor's imperative API never attached under the
demo's React 18 - the toolbar, focus, setValue and image insert all
no-op'd. Bump react/react-dom to 19 and react-native-web to 0.21 (0.19
calls the removed ReactDOM.findDOMNode under React 19; 0.20+ supports both).
Also fix the Vite dev setup the bump and the enriched web build surfaced:
- alias inline-style-prefixer's CJS `lib/*` deep paths to its ESM `es/*`
build, and pre-bundle the CJS sub-entries react-native-web imports
(styleq/transform-localize-style, fbjs/lib/invariant|warning,
react-dom/client) so the browser doesn't choke on missing ESM exports.
- dedupe react/react-dom so the SDK source (imported from ../src) shares
the single React 19 instance instead of pulling its own copy.
---
example-web/package-lock.json | 90 +++++++++++++----------------------
example-web/package.json | 10 ++--
example-web/vite.config.ts | 22 +++++++++
3 files changed, 61 insertions(+), 61 deletions(-)
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 af4d36e..67fb460 100644
--- a/example-web/vite.config.ts
+++ b/example-web/vite.config.ts
@@ -62,7 +62,18 @@ export default defineConfig({
// 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'],
},
@@ -89,6 +100,17 @@ 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-native-enriched',
From 354d675b3225ad45e7e419a95faebbfd71505495 Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 9 Jun 2026 21:19:18 -0700
Subject: [PATCH 3/6] fix(web): editor height, guest auth form, and @mention
detection
Three issues surfaced testing the enriched web editor:
- Editor only accepted clicks on the first line. tiptap's contenteditable
(.ProseMirror) auto-sizes to its content inside the .eti-editor wrapper
that gets our minHeight/flex, so the rest of the box was a dead div.
Inject a tiny web-only rule to make the editor fill its wrapper.
- Submitting a comment spun forever and made no request. submit()'s
validation early-return never reset isReplySaving, and the guest
name/email form never showed: needsAuth was `!currentUser &&
!!parentComment`, which only prompted on replies and treated the anon
session (present from connect, no username/email) as logged in. Mirror
the web widget: show the form when there's no authorized user or an anon
session still owes an email; reset the spinner on early return; default
the inputs to '' to avoid a controlled/uncontrolled warning.
- @mention popup never appeared. detectMentionQuery bailed on the trailing
newline that
produces in plain text, and the editor always wraps
content in ...
. Strip trailing newlines before detecting. Extract
detectMentionQuery/htmlToPlainText into a dependency-free module and add
unit tests covering the real block-wrapped editor output.
---
src/components/comment-text-area.tsx | 65 ++++++++-----------
src/components/reply-area.tsx | 32 +++++++--
.../__tests__/mention-detection.test.ts | 62 ++++++++++++++++++
src/services/mention-detection.ts | 48 ++++++++++++++
4 files changed, 165 insertions(+), 42 deletions(-)
create mode 100644 src/services/__tests__/mention-detection.test.ts
create mode 100644 src/services/mention-detection.ts
diff --git a/src/components/comment-text-area.tsx b/src/components/comment-text-area.tsx
index 29ab62e..6cc88bf 100644
--- a/src/components/comment-text-area.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 {
@@ -22,11 +23,30 @@ import {
import type { NativeSyntheticEvent } from 'react-native';
import { MentionPopup } from './mention-popup';
import { MentionUser } from '../services/mentions';
+import { detectMentionQuery, htmlToPlainText } 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
}
@@ -79,44 +99,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,
@@ -145,6 +130,10 @@ export function CommentTextArea({
const buttons = { ...defaultToolbarButtons, ...toolbarButtons };
+ useEffect(() => {
+ if (Platform.OS === 'web') ensureWebEditorFillStyles();
+ }, []);
+
useEffect(() => {
if (value !== undefined && value !== htmlRef.current) {
htmlRef.current = value;
diff --git a/src/components/reply-area.tsx b/src/components/reply-area.tsx
index f2ee755..1c1c57e 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;
}
@@ -368,7 +379,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 +433,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 +606,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 +631,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 +643,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/services/__tests__/mention-detection.test.ts b/src/services/__tests__/mention-detection.test.ts
new file mode 100644
index 0000000..2450c5d
--- /dev/null
+++ b/src/services/__tests__/mention-detection.test.ts
@@ -0,0 +1,62 @@
+import { detectMentionQuery, htmlToPlainText } from '../mention-detection';
+
+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();
+ });
+ });
+
+ // 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('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..78f65dd
--- /dev/null
+++ b/src/services/mention-detection.ts
@@ -0,0 +1,48 @@
+// 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.
+
+/**
+ * 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. A trailing space terminates
+ * the mention.
+ */
+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 `\n`-after-@ 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;
+ // internal newlines and trailing spaces are preserved so the rules still hold.
+ 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);
+ if (/\n/.test(after)) return undefined;
+ if (after.length > 0 && /\s$/.test(after)) return undefined;
+ return after;
+}
From 6d1d9cfcf6cef1b2be1df38a216e531eef1ad52b Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 9 Jun 2026 23:22:58 -0700
Subject: [PATCH 4/6] fix(web): center the initial loading indicator instead of
clipping it
The loading state early-returns only an absolutely-positioned overlay
(inset:0). With nothing in flow its container collapses to 0 height, and on
web (where the host #root is not always a flex container) a 0-height inset:0
box centers the large spinner on y=0 - i.e. half off the top of the screen.
Fill via normal flow (flex + a minHeight floor) so it cannot collapse, and
make the demo #root a flex container so the widget fills the viewport.
---
example-web/index.html | 3 +++
src/resources/styles.ts | 13 ++++++++-----
2 files changed, 11 insertions(+), 5 deletions(-)
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/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'
From 938916c0fecb06b85266e0e175d91fd1a9329faa Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 9 Jun 2026 23:23:07 -0700
Subject: [PATCH 5/6] fix(web): @mention popup overlay, keyboard nav, and
insertion
- Overlay the popup via a portal to document.body so it is not clipped by
the scrollable comment list or painted under later comment rows. The
composer lives inside react-native-web's virtualized list, whose
transformed ancestor traps even position:fixed, so a web-only portal
(mention-portal.web.tsx) is the reliable escape; native renders inline.
- Keyboard nav: arrow keys move the highlight, Enter/Tab select, Esc
dismisses. Intercepted on the editor wrapper in the capture phase because
the enriched web build forwards keydown but always returns false to
ProseMirror, so there is no supported way to cancel its handling.
- Insert mentions inline with replaceActiveMention (splice at the located
@query) rather than an end-anchored regex that missed block-wrapped HTML
and appended onto a new line ("@a\n@name").
- The query is a single token (any whitespace ends it) and mentions commit
with a non-breaking space, so typing past a completed mention no longer
reopens the popup with "no matches".
Detection/insertion live in a dependency-free mention-detection module with
unit tests covering the real block-wrapped editor output.
---
src/components/comment-text-area.tsx | 181 +++++++++++++-----
src/components/mention-popup.tsx | 51 ++++-
src/components/mention-portal.tsx | 10 +
src/components/mention-portal.web.tsx | 18 ++
.../__tests__/mention-detection.test.ts | 60 +++++-
src/services/mention-detection.ts | 44 ++++-
tests-ui/specs/mentions.test.tsx | 9 +-
7 files changed, 308 insertions(+), 65 deletions(-)
create mode 100644 src/components/mention-portal.tsx
create mode 100644 src/components/mention-portal.web.tsx
diff --git a/src/components/comment-text-area.tsx b/src/components/comment-text-area.tsx
index 6cc88bf..184fcee 100644
--- a/src/components/comment-text-area.tsx
+++ b/src/components/comment-text-area.tsx
@@ -21,9 +21,10 @@ 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 } from '../services/mention-detection';
+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
@@ -124,9 +125,23 @@ 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, 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 };
@@ -134,6 +149,70 @@ export function CommentTextArea({
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;
@@ -160,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);
@@ -261,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 && (
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/services/__tests__/mention-detection.test.ts b/src/services/__tests__/mention-detection.test.ts
index 2450c5d..a46c6b1 100644
--- a/src/services/__tests__/mention-detection.test.ts
+++ b/src/services/__tests__/mention-detection.test.ts
@@ -1,4 +1,8 @@
-import { detectMentionQuery, htmlToPlainText } from '../mention-detection';
+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)', () => {
@@ -22,6 +26,27 @@ describe('detectMentionQuery', () => {
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
@@ -54,6 +79,39 @@ describe('detectMentionQuery', () => {
});
});
+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');
diff --git a/src/services/mention-detection.ts b/src/services/mention-detection.ts
index 78f65dd..661de04 100644
--- a/src/services/mention-detection.ts
+++ b/src/services/mention-detection.ts
@@ -2,6 +2,12 @@
// 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
@@ -24,16 +30,15 @@ export function htmlToPlainText(html: string): string {
/**
* 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.
+ * 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 `\n`-after-@ guard below
+ // 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;
- // internal newlines and trailing spaces are preserved so the rules still hold.
+ // 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;
@@ -42,7 +47,32 @@ export function detectMentionQuery(value: string): string | undefined {
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;
+ // 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/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',
From 8d527266b9520c182629e3c50e50d0092ab3246d Mon Sep 17 00:00:00 2001
From: winrid
Date: Tue, 9 Jun 2026 23:23:18 -0700
Subject: [PATCH 6/6] fix(web): keep the authenticated user after a guest
submit
On a successful post the API returns an authorized user carrying the
email/username the guest entered. A second update block then re-applied a
stale pre-merge snapshot, reverting currentUser to the anonymous session -
so the name/email form stayed visible and the top bar never updated. Merge
response.user into the session (matching the web widget) and read fresh
store state when applying the sessionId so it no longer clobbers the merge.
---
src/components/reply-area.tsx | 40 ++++++++++++++++++++++-------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/components/reply-area.tsx b/src/components/reply-area.tsx
index 1c1c57e..ce1b900 100644
--- a/src/components/reply-area.tsx
+++ b/src/components/reply-area.tsx
@@ -271,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);
}
@@ -290,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 =