From 512d6424a7e037c1a6a73c0af4780e1f69408b3e Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 31 Jul 2024 22:49:58 +0700 Subject: [PATCH 01/22] feat(editor): add pasteDropFile extention --- package-lock.json | 108 ++++++++++++------ package.json | 8 +- .../FloatingMenu/UploadImageButton.tsx | 3 + .../Editor/Article/extensions/captionLimit.ts | 2 +- .../extensions/figureEmbedLinkInput/Input.tsx | 4 +- .../extensions/figureEmbedLinkInput/index.ts | 2 +- .../figureImageUploader/Uploader.tsx | 91 +++++++++++++++ .../extensions/figureImageUploader/index.ts | 62 ++++++++++ .../figureImageUploader/styles.module.css | 13 +++ .../Article/extensions/figurePlaceholder.ts | 30 ++--- .../Editor/Article/extensions/index.ts | 2 + .../Article/extensions/pasteDropFile.ts | 65 +++++++++++ src/components/Editor/Article/index.tsx | 36 +++++- .../Editor/Article/styles.module.css | 17 ++- 14 files changed, 377 insertions(+), 66 deletions(-) create mode 100644 src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx create mode 100644 src/components/Editor/Article/extensions/figureImageUploader/index.ts create mode 100644 src/components/Editor/Article/extensions/figureImageUploader/styles.module.css create mode 100644 src/components/Editor/Article/extensions/pasteDropFile.ts diff --git a/package-lock.json b/package-lock.json index d576a9012b..51bab452a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,10 +25,10 @@ "@stripe/react-stripe-js": "^2.1.1", "@stripe/stripe-js": "^1.54.1", "@tippyjs/react": "^4.2.6", - "@tiptap/extension-bubble-menu": "^2.4.0", - "@tiptap/extension-floating-menu": "^2.4.0", - "@tiptap/extension-placeholder": "^2.4.0", - "@tiptap/suggestion": "^2.4.0", + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@tiptap/extension-placeholder": "^2.5.8", + "@tiptap/suggestion": "^2.5.8", "@use-gesture/react": "^10.3.1", "apollo-cache-inmemory": "^1.6.6", "apollo-client": "^2.6.10", @@ -7330,6 +7330,32 @@ "react-dom": ">=17.0.0" } }, + "node_modules/@matters/matters-editor/node_modules/@tiptap/extension-placeholder": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", + "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@matters/matters-editor/node_modules/@tiptap/suggestion": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", + "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, "node_modules/@matters/matters-editor/node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -14339,9 +14365,9 @@ } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.4.0.tgz", - "integrity": "sha512-s99HmttUtpW3rScWq8rqk4+CGCwergNZbHLTkF6Rp6TSboMwfp+rwL5Q/JkcAG9KGLso1vGyXKbt1xHOvm8zMw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.5.8.tgz", + "integrity": "sha512-COmd1Azudu7i281emZFIESECe7FnvWiRoBoQBVjjWSyq5PVzwJaA3PAlnU7GyNZKtVXMZ4xbrckdyNQfDeVQDA==", "dependencies": { "tippy.js": "^6.3.7" }, @@ -14350,8 +14376,8 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-bullet-list": { @@ -14404,9 +14430,9 @@ } }, "node_modules/@tiptap/extension-floating-menu": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.4.0.tgz", - "integrity": "sha512-vLb9v+htbHhXyty0oaXjT3VC8St4xuGSHWUB9GuAJAQ+NajIO6rBPbLUmm9qM0Eh2zico5mpSD1Qtn5FM6xYzg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.5.8.tgz", + "integrity": "sha512-qsM6tCyRlXnI/gADrkO/2p0Tldu5aY96CnsXpZMaflMgsO577qhcXD0ReGg17uLXBzJa5xmV8qOik0Ptq3WEWg==", "dependencies": { "tippy.js": "^6.3.7" }, @@ -14415,8 +14441,8 @@ "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-gapcursor": { @@ -14519,16 +14545,16 @@ } }, "node_modules/@tiptap/extension-placeholder": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", - "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.5.8.tgz", + "integrity": "sha512-mvRl73OM5jBXVtDRLSTvp8/4+0mS2J2+ZcuiAHjABwEsZRCfJsiqty5NisOxSuy/AQtm8TK2kyt6ZCXQ2VRGig==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-strike": { @@ -14604,16 +14630,16 @@ } }, "node_modules/@tiptap/suggestion": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", - "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.5.8.tgz", + "integrity": "sha512-u0emCyGpzSshKR5mIJVwPwycKikP05137fnD0RFI3+nftO6n/2h54rs2yU6BYA8dc01VZRB00cJ/zHO6DsZWEA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tokenizer/token": { @@ -51519,6 +51545,16 @@ "zeed-dom": "^0.13.3" }, "dependencies": { + "@tiptap/extension-placeholder": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", + "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==" + }, + "@tiptap/suggestion": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", + "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==" + }, "@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -56095,9 +56131,9 @@ "integrity": "sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==" }, "@tiptap/extension-bubble-menu": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.4.0.tgz", - "integrity": "sha512-s99HmttUtpW3rScWq8rqk4+CGCwergNZbHLTkF6Rp6TSboMwfp+rwL5Q/JkcAG9KGLso1vGyXKbt1xHOvm8zMw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.5.8.tgz", + "integrity": "sha512-COmd1Azudu7i281emZFIESECe7FnvWiRoBoQBVjjWSyq5PVzwJaA3PAlnU7GyNZKtVXMZ4xbrckdyNQfDeVQDA==", "requires": { "tippy.js": "^6.3.7" } @@ -56123,9 +56159,9 @@ "integrity": "sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==" }, "@tiptap/extension-floating-menu": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.4.0.tgz", - "integrity": "sha512-vLb9v+htbHhXyty0oaXjT3VC8St4xuGSHWUB9GuAJAQ+NajIO6rBPbLUmm9qM0Eh2zico5mpSD1Qtn5FM6xYzg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.5.8.tgz", + "integrity": "sha512-qsM6tCyRlXnI/gADrkO/2p0Tldu5aY96CnsXpZMaflMgsO577qhcXD0ReGg17uLXBzJa5xmV8qOik0Ptq3WEWg==", "requires": { "tippy.js": "^6.3.7" } @@ -56171,9 +56207,9 @@ "integrity": "sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==" }, "@tiptap/extension-placeholder": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", - "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.5.8.tgz", + "integrity": "sha512-mvRl73OM5jBXVtDRLSTvp8/4+0mS2J2+ZcuiAHjABwEsZRCfJsiqty5NisOxSuy/AQtm8TK2kyt6ZCXQ2VRGig==" }, "@tiptap/extension-strike": { "version": "2.4.0", @@ -56220,9 +56256,9 @@ } }, "@tiptap/suggestion": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", - "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.5.8.tgz", + "integrity": "sha512-u0emCyGpzSshKR5mIJVwPwycKikP05137fnD0RFI3+nftO6n/2h54rs2yU6BYA8dc01VZRB00cJ/zHO6DsZWEA==" }, "@tokenizer/token": { "version": "0.3.0", diff --git a/package.json b/package.json index 219a8c3967..9e3d647f0d 100644 --- a/package.json +++ b/package.json @@ -55,10 +55,10 @@ "@stripe/react-stripe-js": "^2.1.1", "@stripe/stripe-js": "^1.54.1", "@tippyjs/react": "^4.2.6", - "@tiptap/extension-bubble-menu": "^2.4.0", - "@tiptap/extension-floating-menu": "^2.4.0", - "@tiptap/extension-placeholder": "^2.4.0", - "@tiptap/suggestion": "^2.4.0", + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@tiptap/extension-placeholder": "^2.5.8", + "@tiptap/suggestion": "^2.5.8", "@use-gesture/react": "^10.3.1", "apollo-cache-inmemory": "^1.6.6", "apollo-client": "^2.6.10", diff --git a/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx b/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx index 30c68bc313..2b53524d3e 100644 --- a/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx +++ b/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx @@ -46,6 +46,7 @@ const UploadImageButton: React.FC = ({ const hasInvalidImage = await Promise.all( Array.from(files).map((file) => validateImage(file)) ).then((results) => results.some((result) => !result)) + if (hasInvalidImage) { event.target.value = '' return @@ -57,7 +58,9 @@ const UploadImageButton: React.FC = ({ for (const file of files) { const mime = (await getFileType(file))!.mime const { path } = await upload({ file, type: ASSET_TYPE.embed, mime }) + editor.chain().focus().setFigureImage({ src: path }).run() + toast.success({ message: ( diff --git a/src/components/Editor/Article/extensions/captionLimit.ts b/src/components/Editor/Article/extensions/captionLimit.ts index 96e3634bb6..0c90c21ad9 100644 --- a/src/components/Editor/Article/extensions/captionLimit.ts +++ b/src/components/Editor/Article/extensions/captionLimit.ts @@ -25,7 +25,7 @@ export const CaptionLimit = Node.create({ addProseMirrorPlugins() { return [ new Plugin({ - key: new PluginKey('captionLimit'), + key: new PluginKey(pluginName), filterTransaction: (transaction, state) => { // Nothing has changed, ignore it. if (!transaction.docChanged || !this.options.maxCaptionLength) { diff --git a/src/components/Editor/Article/extensions/figureEmbedLinkInput/Input.tsx b/src/components/Editor/Article/extensions/figureEmbedLinkInput/Input.tsx index 9172403d6c..377deeedb1 100644 --- a/src/components/Editor/Article/extensions/figureEmbedLinkInput/Input.tsx +++ b/src/components/Editor/Article/extensions/figureEmbedLinkInput/Input.tsx @@ -21,9 +21,7 @@ const Input: React.FC = (props) => { // restore paragraph node if (isRestoreParagraph) { props.editor.commands.insertContentAt(props.editor.state.selection.to, [ - { - type: 'paragraph', - }, + { type: 'paragraph' }, ]) } diff --git a/src/components/Editor/Article/extensions/figureEmbedLinkInput/index.ts b/src/components/Editor/Article/extensions/figureEmbedLinkInput/index.ts index 3f33185119..fbc70f36c2 100644 --- a/src/components/Editor/Article/extensions/figureEmbedLinkInput/index.ts +++ b/src/components/Editor/Article/extensions/figureEmbedLinkInput/index.ts @@ -37,7 +37,7 @@ export const FigureEmbedLinkInput = Node.create({ return { placeholder: { default: null, - parseHTML: (element) => element.getAttribute('data-placeholder'), + // parseHTML: (element) => element.getAttribute('data-placeholder'), }, } }, diff --git a/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx b/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx new file mode 100644 index 0000000000..ba38fb7930 --- /dev/null +++ b/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx @@ -0,0 +1,91 @@ +import { NodeViewProps, NodeViewWrapper } from '@tiptap/react' +import { useEffect, useState } from 'react' +import { FormattedMessage } from 'react-intl' + +import { ASSET_TYPE } from '~/common/enums' +import { validateImage } from '~/common/utils' +import { toast } from '~/components' + +import styles from './styles.module.css' + +export type UploaderProps = { + previewSrc: string + file: File + upload: (input: { + file?: File + url?: string + type?: ASSET_TYPE.embed | ASSET_TYPE.embedaudio + mime?: string + }) => Promise<{ + id: string + path: string + }> +} + +const Uploader: React.FC = (props) => { + const { editor, node, deleteNode, getPos } = props + const { previewSrc, file, upload } = node.attrs as UploaderProps + const [progress, setProgress] = useState(0) + const duration = 3000 // 3 seconds + const intervalTime = 100 // Update every 100ms + const maxProgress = 99 + + const uploadAndReplace = async (file: File) => { + const mime = await validateImage(file) + + if (!mime) return + + try { + const { path } = await upload({ file, type: ASSET_TYPE.embed, mime }) + + return editor + .chain() + .insertContentAt({ from: getPos(), to: getPos() + 1 }, [ + { type: 'figureImage', attrs: { src: path } }, + ]) + .run() + } catch (e) { + toast.error({ + message: ( + + ), + }) + + deleteNode() + } + } + + // Simulate upload progress + useEffect(() => { + const increment = (maxProgress / duration) * intervalTime + const intervalId = setInterval(() => { + setProgress((prevProgress) => { + const newProgress = Math.floor(prevProgress + increment) + if (newProgress >= maxProgress) { + clearInterval(intervalId) + return maxProgress + } + return newProgress + }) + }, intervalTime) + + return () => clearInterval(intervalId) + }, []) + + // Upload image + useEffect(() => { + uploadAndReplace(file) + }, []) + + return ( + + Uploading... + {progress}% + + ) +} + +export default Uploader diff --git a/src/components/Editor/Article/extensions/figureImageUploader/index.ts b/src/components/Editor/Article/extensions/figureImageUploader/index.ts new file mode 100644 index 0000000000..da60d20a1e --- /dev/null +++ b/src/components/Editor/Article/extensions/figureImageUploader/index.ts @@ -0,0 +1,62 @@ +import { mergeAttributes, ReactNodeViewRenderer } from '@matters/matters-editor' +import { Node } from '@tiptap/core' + +import Uploader, { UploaderProps } from './Uploader' + +/** + * FigureImageUploader is a extension to upload image and replace with FigureImage node after upload. + */ + +declare module '@tiptap/core' { + interface Commands { + figureImageUploader: { + addFigureImageUploader: ( + options: UploaderProps & { pos?: number } + ) => ReturnType + } + } +} + +const pluginName = 'figureImageUploader' + +export const FigureImageUploader = Node.create({ + name: pluginName, + group: 'block', + atom: true, + + addAttributes() { + return { + previewSrc: { default: null }, + file: { default: null }, + upload: { default: null }, + } + }, + + parseHTML() { + return [{ tag: 'figure-image-uploader' }] + }, + + renderHTML({ HTMLAttributes }) { + return ['figure-image-uploader', mergeAttributes(HTMLAttributes)] + }, + + addNodeView() { + return ReactNodeViewRenderer(Uploader) + }, + + addCommands() { + return { + addFigureImageUploader: + (attrs) => + ({ chain }) => { + const content = [{ type: this.name, attrs, content: [] }] + + if (!attrs.pos) { + return chain().insertContent(content).run() + } + + return chain().insertContentAt(attrs.pos, content).run() + }, + } + }, +}) diff --git a/src/components/Editor/Article/extensions/figureImageUploader/styles.module.css b/src/components/Editor/Article/extensions/figureImageUploader/styles.module.css new file mode 100644 index 0000000000..76161055ee --- /dev/null +++ b/src/components/Editor/Article/extensions/figureImageUploader/styles.module.css @@ -0,0 +1,13 @@ +.progressIndicator { + position: absolute; + right: var(--sp12); + bottom: var(--sp12); + padding: var(--sp2) var(--sp12); + font-size: var(--text12); + font-weight: var(--font-normal); + line-height: 1.125rem; + color: var(--color-white); + content: attr(data-upload-progress); + background: rgb(0 0 0 / 40%); + border-radius: 4px; +} diff --git a/src/components/Editor/Article/extensions/figurePlaceholder.ts b/src/components/Editor/Article/extensions/figurePlaceholder.ts index b5fe57889c..0ec09cbbdc 100644 --- a/src/components/Editor/Article/extensions/figurePlaceholder.ts +++ b/src/components/Editor/Article/extensions/figurePlaceholder.ts @@ -15,8 +15,10 @@ export interface PlaceholderOptions { placeholder: string } +const pluginName = 'figurePlaceholder' + export const FigurePlaceholder = Extension.create({ - name: 'figurePlaceholder', + name: pluginName, addOptions() { return { @@ -28,30 +30,28 @@ export const FigurePlaceholder = Extension.create({ addProseMirrorPlugins() { return [ new Plugin({ - key: new PluginKey('figurePlaceholder'), + key: new PluginKey(pluginName), props: { decorations: ({ doc, selection }) => { const decorations: Decoration[] = [] doc.descendants((node, pos) => { - const isEmpty = !node.isLeaf && !node.childCount const isFigure = node.type.name.startsWith('figure') + if (!isFigure) return - if (isEmpty && isFigure) { - const isAtFigcaption = selection.$anchor.pos === pos + 1 - if (isAtFigcaption) { - return false - } + const isEmpty = !node.isLeaf && !node.childCount + if (!isEmpty) return - const decoration = Decoration.node(pos, pos + node.nodeSize, { - class: this.options.emptyNodeClass, - 'data-figure-placeholder': this.options.placeholder, - }) + // focus on the figcaption node + const isAtFigcaption = selection.$anchor.pos === pos + 1 + if (isAtFigcaption) return - decorations.push(decoration) - } + const decoration = Decoration.node(pos, pos + node.nodeSize, { + class: this.options.emptyNodeClass, + 'data-figure-placeholder': this.options.placeholder, + }) - return false + decorations.push(decoration) }) return DecorationSet.create(doc, decorations) diff --git a/src/components/Editor/Article/extensions/index.ts b/src/components/Editor/Article/extensions/index.ts index 149c7b3fa5..641d37010f 100644 --- a/src/components/Editor/Article/extensions/index.ts +++ b/src/components/Editor/Article/extensions/index.ts @@ -1,5 +1,7 @@ export * from './captionLimit' export * from './figureEmbedLinkInput' +export * from './figureImageUploader' export * from './figurePlaceholder' export * from './mention' +export * from './pasteDropFile' export * from './smartLink' diff --git a/src/components/Editor/Article/extensions/pasteDropFile.ts b/src/components/Editor/Article/extensions/pasteDropFile.ts new file mode 100644 index 0000000000..2ef0d4864b --- /dev/null +++ b/src/components/Editor/Article/extensions/pasteDropFile.ts @@ -0,0 +1,65 @@ +import { Editor } from '@matters/matters-editor' +import { Node } from '@tiptap/core' +import { Plugin, PluginKey } from '@tiptap/pm/state' + +/** + * A extension to handle paste and drop image events. + */ + +type PasteDropFileOptions = { + onPaste: (editor: Editor, files: File[]) => void + onDrop: (editor: Editor, files: File[], pos: number) => void + mimeTypes: string[] +} + +const pluginName = 'pasteDropFile' + +const makePlugin = ({ + editor, + onDrop, + onPaste, + mimeTypes, +}: PasteDropFileOptions & { editor: Editor }) => { + return new Plugin({ + key: new PluginKey(pluginName), + props: { + handleDrop(view, event, slice, moved) { + const files = Array.from(event.dataTransfer?.files || []).filter( + (file) => mimeTypes.includes(file.type) + ) + + if (files.length <= 0) return + + const position = view.posAtCoords({ + left: event.clientX, + top: event.clientY, + }) + + event.stopPropagation() + onDrop(editor, files, position?.pos || 0) + + return true + }, + handlePaste(view, event, slice) { + const files = Array.from(event.clipboardData?.files || []).filter( + (file) => mimeTypes.includes(file.type) + ) + + if (files.length <= 0) return + + event.stopPropagation() + onPaste(editor, files) + + return true + }, + }, + }) +} + +export const PasteDropFile = Node.create({ + name: pluginName, + + addProseMirrorPlugins() { + return [makePlugin({ ...this.options, editor: this.editor as Editor })] + }, +}) diff --git a/src/components/Editor/Article/index.tsx b/src/components/Editor/Article/index.tsx index e1e9e923aa..34f43b1150 100644 --- a/src/components/Editor/Article/index.tsx +++ b/src/components/Editor/Article/index.tsx @@ -3,15 +3,17 @@ import { EditorContent, useArticleEdtor } from '@matters/matters-editor' import { useIntl } from 'react-intl' import { useDebouncedCallback } from 'use-debounce' -import { INPUT_DEBOUNCE } from '~/common/enums' +import { ACCEPTED_UPLOAD_IMAGE_TYPES, INPUT_DEBOUNCE } from '~/common/enums' import { EditorDraftFragment } from '~/gql/graphql' import { BubbleMenu } from './BubbleMenu' import { CaptionLimit, FigureEmbedLinkInput, + FigureImageUploader, FigurePlaceholder, makeMentionSuggestion, + PasteDropFile, SmartLink, } from './extensions' import { makeSmartLinkOptions } from './extensions/smartLink/utils' @@ -71,6 +73,38 @@ export const ArticleEditor: React.FC = ({ maxCaptionLength: 100, }), SmartLink.configure(makeSmartLinkOptions({ client })), + // FileUploadIndicator, + FigureImageUploader, + PasteDropFile.configure({ + onDrop: async (editor, files, pos) => { + let chain = editor.chain() + + Array.from(files).forEach((file) => { + chain.addFigureImageUploader({ + upload, + previewSrc: URL.createObjectURL(file), + file, + pos, + }) + }) + + chain.run() + }, + onPaste: async (editor, files) => { + let chain = editor.chain() + + Array.from(files).forEach((file) => { + chain.addFigureImageUploader({ + upload, + previewSrc: URL.createObjectURL(file), + file, + }) + }) + + chain.run() + }, + mimeTypes: ACCEPTED_UPLOAD_IMAGE_TYPES, + }), ], }) diff --git a/src/components/Editor/Article/styles.module.css b/src/components/Editor/Article/styles.module.css index d7299e6335..398438a878 100644 --- a/src/components/Editor/Article/styles.module.css +++ b/src/components/Editor/Article/styles.module.css @@ -27,6 +27,11 @@ outline: none; } + /* disable interactive elements */ + & a { + pointer-events: none; + } + /* horizontal rule */ & :global(hr.ProseMirror-selectednode) { &::before { @@ -69,11 +74,7 @@ content: attr(data-figure-placeholder); } - /* disable interactive */ - & a { - pointer-events: none; - } - + /* link input */ & :global(.figure-embed-link-input) { & input { display: block; @@ -87,6 +88,12 @@ } } } + + /* image uploader */ + & :global(.figure-image-uploader) { + position: relative; + margin: var(--ar17-200) 0; + } } &.revisedMode { From 82a42a6bd000911e72583e34402704efd0ca7af5 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:48:50 +0700 Subject: [PATCH 02/22] feat(editor): move PasteDropFile to @matters/matters-editor --- package-lock.json | 622 +++++++++--------- package.json | 6 +- .../Editor/Article/extensions/index.ts | 1 - .../Article/extensions/pasteDropFile.ts | 65 -- src/components/Editor/Article/index.tsx | 30 +- src/components/Editor/Comment/index.tsx | 20 +- 6 files changed, 345 insertions(+), 399 deletions(-) delete mode 100644 src/components/Editor/Article/extensions/pasteDropFile.ts diff --git a/package-lock.json b/package-lock.json index 51bab452a3..2d698d1b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@artsy/fresnel": "^6.1.0", "@ensdomains/content-hash": "^2.5.7", "@matters/apollo-upload-client": "^11.1.0", - "@matters/matters-editor": "^0.2.5-alpha.6", + "@matters/matters-editor": "^0.3.0-alpha.0", "@next/bundle-analyzer": "^13.4.9", "@reach/alert": "^0.18.0", "@reach/dialog": "^0.18.0", @@ -25,10 +25,6 @@ "@stripe/react-stripe-js": "^2.1.1", "@stripe/stripe-js": "^1.54.1", "@tippyjs/react": "^4.2.6", - "@tiptap/extension-bubble-menu": "^2.5.8", - "@tiptap/extension-floating-menu": "^2.5.8", - "@tiptap/extension-placeholder": "^2.5.8", - "@tiptap/suggestion": "^2.5.8", "@use-gesture/react": "^10.3.1", "apollo-cache-inmemory": "^1.6.6", "apollo-client": "^2.6.10", @@ -7275,34 +7271,36 @@ } }, "node_modules/@matters/matters-editor": { - "version": "0.2.5-alpha.6", - "resolved": "https://registry.npmjs.org/@matters/matters-editor/-/matters-editor-0.2.5-alpha.6.tgz", - "integrity": "sha512-074GixLcKTQeUH0e9+NEKaiPy8uXAlckQkASOpUj2V8VslEA/v4xC3BJzANeFZpuNAnYleSzn7DdM10RyEUBHw==", - "dependencies": { - "@tiptap/core": "2.4.0", - "@tiptap/extension-blockquote": "2.4.0", - "@tiptap/extension-bullet-list": "2.4.0", - "@tiptap/extension-code": "2.4.0", - "@tiptap/extension-code-block": "2.4.0", - "@tiptap/extension-document": "2.4.0", - "@tiptap/extension-gapcursor": "2.4.0", - "@tiptap/extension-hard-break": "2.4.0", - "@tiptap/extension-heading": "2.4.0", - "@tiptap/extension-history": "2.4.0", - "@tiptap/extension-horizontal-rule": "2.4.0", - "@tiptap/extension-list-item": "2.4.0", - "@tiptap/extension-ordered-list": "2.4.0", - "@tiptap/extension-paragraph": "2.4.0", - "@tiptap/extension-placeholder": "2.4.0", - "@tiptap/extension-strike": "2.4.0", - "@tiptap/extension-text": "2.4.0", - "@tiptap/pm": "2.4.0", - "@tiptap/react": "2.4.0", - "@tiptap/suggestion": "2.4.0", + "version": "0.3.0-alpha.0", + "resolved": "https://registry.npmjs.org/@matters/matters-editor/-/matters-editor-0.3.0-alpha.0.tgz", + "integrity": "sha512-Z50sR7sw0Jlp28xS0JavUNT5EqBdLhG3qk5Nh9x4+Q/d5fbD3/X28mffB1wrlvUbSVIkYDAGAoWqaKFhFeoHSg==", + "dependencies": { + "@tiptap/core": "2.5.8", + "@tiptap/extension-blockquote": "2.5.8", + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-bullet-list": "2.5.8", + "@tiptap/extension-code-block": "2.5.8", + "@tiptap/extension-document": "2.5.8", + "@tiptap/extension-dropcursor": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@tiptap/extension-gapcursor": "2.5.8", + "@tiptap/extension-hard-break": "2.5.8", + "@tiptap/extension-heading": "2.5.8", + "@tiptap/extension-history": "2.5.8", + "@tiptap/extension-horizontal-rule": "2.5.8", + "@tiptap/extension-list-item": "2.5.8", + "@tiptap/extension-ordered-list": "2.5.8", + "@tiptap/extension-paragraph": "2.5.8", + "@tiptap/extension-placeholder": "2.5.8", + "@tiptap/extension-strike": "2.5.8", + "@tiptap/extension-text": "2.5.8", + "@tiptap/pm": "2.5.8", + "@tiptap/react": "2.5.8", + "@tiptap/suggestion": "2.5.8", "hast-util-to-html": "^9.0.1", "linkifyjs": "^4.1.3", "mdast-util-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.1.0", "micromark-util-combine-extensions": "^2.0.0", "rehype-external-links": "^3.0.0", "rehype-format": "^5.0.0", @@ -7318,7 +7316,7 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.0", "remark-stringify": "^11.0.0", - "unified": "^11.0.4", + "unified": "^11.0.5", "validator": "^13.12.0", "zeed-dom": "^0.13.3" }, @@ -7330,32 +7328,6 @@ "react-dom": ">=17.0.0" } }, - "node_modules/@matters/matters-editor/node_modules/@tiptap/extension-placeholder": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", - "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" - } - }, - "node_modules/@matters/matters-editor/node_modules/@tiptap/suggestion": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", - "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" - } - }, "node_modules/@matters/matters-editor/node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -7553,9 +7525,9 @@ } }, "node_modules/@matters/matters-editor/node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -7960,9 +7932,9 @@ } }, "node_modules/@matters/matters-editor/node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -14341,27 +14313,27 @@ } }, "node_modules/@tiptap/core": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.4.0.tgz", - "integrity": "sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.5.8.tgz", + "integrity": "sha512-lkWCKyoAoMTxM137MoEsorG7tZ5MZU6O3wMRuZ0P9fcTRY5vd1NWncWuPzuGSJIpL20gwBQOsS6PaQSfR3xjlA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^2.0.0" + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-blockquote": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.4.0.tgz", - "integrity": "sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.5.8.tgz", + "integrity": "sha512-P8vDiagtRrUfIewfCKrJe0ddDSjPgOTKzqoM1UXKS+MenT8C/wT4bjiwopAoWP6zMoV0TfHWXah9emllmCfXFA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-bubble-menu": { @@ -14381,52 +14353,53 @@ } }, "node_modules/@tiptap/extension-bullet-list": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.4.0.tgz", - "integrity": "sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.5.8.tgz", + "integrity": "sha512-Wvf0HWBI0ulssoCsCOguxJB1Ntmj9PtE8b/ieFwFvrNptP+sf25XiWgjMs7H1KQrtmpngBu/Bhh5jJRgAmAgeQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, - "node_modules/@tiptap/extension-code": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.4.0.tgz", - "integrity": "sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA==", + "node_modules/@tiptap/extension-code-block": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.5.8.tgz", + "integrity": "sha512-atMtT1Ddc4hv9+OiH/UCLfQ6Ooo45xpPaaOhqs1Ab509YyqxoyEbfNSOth/yx9DFb8VOenRWE1WV3Z3C0ial0Q==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, - "node_modules/@tiptap/extension-code-block": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.4.0.tgz", - "integrity": "sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg==", + "node_modules/@tiptap/extension-document": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.5.8.tgz", + "integrity": "sha512-r3rP4ihCJAdp3VRIeqd80etHx7jttzZaKNFX8hkQShHK6eTHwrR92VL0jDE4K+NOE3bxjMsOlYizJYWV042BtA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, - "node_modules/@tiptap/extension-document": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.4.0.tgz", - "integrity": "sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==", + "node_modules/@tiptap/extension-dropcursor": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.5.8.tgz", + "integrity": "sha512-xPmIfTYqurFF8RukCPlHd8mT8I7hDinWrgq7CQTRROxcJ3DNw8PooWrKWaBYs9HXHe1pbiQ5EK0uOsNvQ1bcDg==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-floating-menu": { @@ -14446,102 +14419,102 @@ } }, "node_modules/@tiptap/extension-gapcursor": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.4.0.tgz", - "integrity": "sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.5.8.tgz", + "integrity": "sha512-nR7AUOE4xWdp0sDbLbe4uwAhQ/xq+MTLVafvffMLT81U/Hl9R+w0Ap2XF0+c6/JTQwVjZiOalAmg4dobx7rJUQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-hard-break": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.4.0.tgz", - "integrity": "sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.5.8.tgz", + "integrity": "sha512-samZEL0EXzHSmMQ7KyLnfSxdDv3qSjia0JzelfCnFZS6LLcbwjrIjV8ZPxEhJ7UlZqroQdFxPegllkLHZj/MdQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-heading": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.4.0.tgz", - "integrity": "sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.5.8.tgz", + "integrity": "sha512-fDQoUkTLN+U8MNQ8PI+syKyshS9qFHlKihxzMLf/+tRisJvP47gzHDur99nffTSbXFDnASDqhavhKjI/2xTWlQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-history": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.4.0.tgz", - "integrity": "sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.5.8.tgz", + "integrity": "sha512-5IrZZfp2Rg9Tov/08aYTKhwoiqdun8v3j3vleuqyW5RB7LU/NKLR19EtSSMh9mVkFZVbhab2zDOFmn5ilsEOhw==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-horizontal-rule": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.4.0.tgz", - "integrity": "sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.5.8.tgz", + "integrity": "sha512-L8Is73WGaP6VNdKrIry+lCIM9W1KaL/Tw2Z6DGMVMU5mr1lLx0xq7nWEStqD7e4zh+n4+3PV15cZSA2F34DZrg==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0" + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8" } }, "node_modules/@tiptap/extension-list-item": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.4.0.tgz", - "integrity": "sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.5.8.tgz", + "integrity": "sha512-RFIIzHxxXdPmdf7BL0zhE4VPHoR6BTWtfi3JCTftmNqKoH7o+mLKT0RHMGvF1CGNn2HewHzXAF0iXfKCwmEgHQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-ordered-list": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.4.0.tgz", - "integrity": "sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.8.tgz", + "integrity": "sha512-84gWdWhc8rUCCssn8+6Z1rFKdG7/yIe+gwYkU6WqAtDrcluJdt5jRHrcMOLxb2dbY8ww9pa72EYV/bwOisZlFQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-paragraph": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.4.0.tgz", - "integrity": "sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.5.8.tgz", + "integrity": "sha512-AMfD3lfGSiomfkSE2tUourUjVahLtIfWUQew13NTPuWoxAXaSyoCGO0ULkiou/lO3JVUUUmF9+KJrAHWGIARdA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-placeholder": { @@ -14558,52 +14531,52 @@ } }, "node_modules/@tiptap/extension-strike": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.4.0.tgz", - "integrity": "sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.5.8.tgz", + "integrity": "sha512-uiHhBIEqawX9Up2ofklotVQ5XpGIjwRL6wprZF38s1le3XpsgyhVV7oDnqDkC7ujCsGkOJJfXZtv3LsO3R2nzQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/extension-text": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.4.0.tgz", - "integrity": "sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.5.8.tgz", + "integrity": "sha512-CNkD51jRMdcYCqFVOkrnebqBQ6pCD3ZD5z9kO5bOC5UPZKZBkLsWdlrHGAVwosxcGxdJACbqJ0Nj+fMgIw4tNA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0" + "@tiptap/core": "^2.5.8" } }, "node_modules/@tiptap/pm": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.4.0.tgz", - "integrity": "sha512-B1HMEqGS4MzIVXnpgRZDLm30mxDWj51LkBT/if1XD+hj5gm8B9Q0c84bhvODX6KIs+c6z+zsY9VkVu8w9Yfgxg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.5.8.tgz", + "integrity": "sha512-CVhHaTG4QNHSkvuh6HHsUR4hE+nbUnk7z+VMUedaqPU8tNqkTwWGCMbiyTc+PCsz0T9Mni7vvBR+EXgEQ3+w4g==", "dependencies": { "prosemirror-changeset": "^2.2.1", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.5.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", - "prosemirror-history": "^1.3.2", - "prosemirror-inputrules": "^1.3.0", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-markdown": "^1.12.0", + "prosemirror-markdown": "^1.13.0", "prosemirror-menu": "^1.2.4", - "prosemirror-model": "^1.19.4", - "prosemirror-schema-basic": "^1.2.2", - "prosemirror-schema-list": "^1.3.0", + "prosemirror-model": "^1.22.2", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.4.1", "prosemirror-state": "^1.4.3", - "prosemirror-tables": "^1.3.5", - "prosemirror-trailing-node": "^2.0.7", - "prosemirror-transform": "^1.8.0", - "prosemirror-view": "^1.32.7" + "prosemirror-tables": "^1.4.0", + "prosemirror-trailing-node": "^2.0.9", + "prosemirror-transform": "^1.9.0", + "prosemirror-view": "^1.33.9" }, "funding": { "type": "github", @@ -14611,24 +14584,34 @@ } }, "node_modules/@tiptap/react": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.4.0.tgz", - "integrity": "sha512-baxnIr6Dy+5iGagOEIKFeHzdl1ZRa6Cg+SJ3GDL/BVLpO6KiCM3Mm5ymB726UKP1w7icrBiQD2fGY3Bx8KaiSA==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.5.8.tgz", + "integrity": "sha512-twUMm8HV7scUgR/E1hYS9N6JDtKPl7cgDiPjxTynNHc5S5f5Ecv4ns/BZRq3TMZ/JDrp4rghLvgq+ImQsLvPOA==", "dependencies": { - "@tiptap/extension-bubble-menu": "^2.4.0", - "@tiptap/extension-floating-menu": "^2.4.0" + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.2.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^2.0.0", - "@tiptap/pm": "^2.0.0", + "@tiptap/core": "^2.5.8", + "@tiptap/pm": "^2.5.8", "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0" } }, + "node_modules/@tiptap/react/node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@tiptap/suggestion": { "version": "2.5.8", "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.5.8.tgz", @@ -15691,6 +15674,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" }, + "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==" + }, "node_modules/@types/uuid": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", @@ -36994,9 +36982,9 @@ } }, "node_modules/prosemirror-commands": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", - "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.0.tgz", + "integrity": "sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==", "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -37025,9 +37013,9 @@ } }, "node_modules/prosemirror-history": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.0.tgz", - "integrity": "sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", "dependencies": { "prosemirror-state": "^1.2.2", "prosemirror-transform": "^1.0.0", @@ -37074,25 +37062,25 @@ } }, "node_modules/prosemirror-model": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.1.tgz", - "integrity": "sha512-IVBAuMqOfltTr7yPypwpfdGT+6rGAteVOw2FO6GEvCGGa1ZwxLseqC1Eax/EChDvG/xGquB2d/hLdgh3THpsYg==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.2.tgz", + "integrity": "sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==", "dependencies": { "orderedmap": "^2.0.0" } }, "node_modules/prosemirror-schema-basic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz", - "integrity": "sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz", + "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==", "dependencies": { "prosemirror-model": "^1.19.0" } }, "node_modules/prosemirror-schema-list": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz", - "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz", + "integrity": "sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==", "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -37110,9 +37098,9 @@ } }, "node_modules/prosemirror-tables": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz", - "integrity": "sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.4.0.tgz", + "integrity": "sha512-fxryZZkQG12fSCNuZDrYx6Xvo2rLYZTbKLRd8rglOPgNJGMKIS8uvTt6gGC38m7UCu/ENnXIP9pEz5uDaPc+cA==", "dependencies": { "prosemirror-keymap": "^1.1.2", "prosemirror-model": "^1.8.1", @@ -37122,17 +37110,17 @@ } }, "node_modules/prosemirror-trailing-node": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz", - "integrity": "sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.9.tgz", + "integrity": "sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==", "dependencies": { "@remirror/core-constants": "^2.0.2", "escape-string-regexp": "^4.0.0" }, "peerDependencies": { - "prosemirror-model": "^1.19.0", + "prosemirror-model": "^1.22.1", "prosemirror-state": "^1.4.2", - "prosemirror-view": "^1.31.2" + "prosemirror-view": "^1.33.8" } }, "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": { @@ -37155,9 +37143,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.33.7", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.7.tgz", - "integrity": "sha512-jo6eMQCtPRwcrA2jISBCnm0Dd2B+szS08BU1Ay+XGiozHo5EZMHfLQE8R5nO4vb1spTH2RW1woZIYXRiQsuP8g==", + "version": "1.33.9", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.9.tgz", + "integrity": "sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==", "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -51497,34 +51485,36 @@ } }, "@matters/matters-editor": { - "version": "0.2.5-alpha.6", - "resolved": "https://registry.npmjs.org/@matters/matters-editor/-/matters-editor-0.2.5-alpha.6.tgz", - "integrity": "sha512-074GixLcKTQeUH0e9+NEKaiPy8uXAlckQkASOpUj2V8VslEA/v4xC3BJzANeFZpuNAnYleSzn7DdM10RyEUBHw==", - "requires": { - "@tiptap/core": "2.4.0", - "@tiptap/extension-blockquote": "2.4.0", - "@tiptap/extension-bullet-list": "2.4.0", - "@tiptap/extension-code": "2.4.0", - "@tiptap/extension-code-block": "2.4.0", - "@tiptap/extension-document": "2.4.0", - "@tiptap/extension-gapcursor": "2.4.0", - "@tiptap/extension-hard-break": "2.4.0", - "@tiptap/extension-heading": "2.4.0", - "@tiptap/extension-history": "2.4.0", - "@tiptap/extension-horizontal-rule": "2.4.0", - "@tiptap/extension-list-item": "2.4.0", - "@tiptap/extension-ordered-list": "2.4.0", - "@tiptap/extension-paragraph": "2.4.0", - "@tiptap/extension-placeholder": "2.4.0", - "@tiptap/extension-strike": "2.4.0", - "@tiptap/extension-text": "2.4.0", - "@tiptap/pm": "2.4.0", - "@tiptap/react": "2.4.0", - "@tiptap/suggestion": "2.4.0", + "version": "0.3.0-alpha.0", + "resolved": "https://registry.npmjs.org/@matters/matters-editor/-/matters-editor-0.3.0-alpha.0.tgz", + "integrity": "sha512-Z50sR7sw0Jlp28xS0JavUNT5EqBdLhG3qk5Nh9x4+Q/d5fbD3/X28mffB1wrlvUbSVIkYDAGAoWqaKFhFeoHSg==", + "requires": { + "@tiptap/core": "2.5.8", + "@tiptap/extension-blockquote": "2.5.8", + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-bullet-list": "2.5.8", + "@tiptap/extension-code-block": "2.5.8", + "@tiptap/extension-document": "2.5.8", + "@tiptap/extension-dropcursor": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@tiptap/extension-gapcursor": "2.5.8", + "@tiptap/extension-hard-break": "2.5.8", + "@tiptap/extension-heading": "2.5.8", + "@tiptap/extension-history": "2.5.8", + "@tiptap/extension-horizontal-rule": "2.5.8", + "@tiptap/extension-list-item": "2.5.8", + "@tiptap/extension-ordered-list": "2.5.8", + "@tiptap/extension-paragraph": "2.5.8", + "@tiptap/extension-placeholder": "2.5.8", + "@tiptap/extension-strike": "2.5.8", + "@tiptap/extension-text": "2.5.8", + "@tiptap/pm": "2.5.8", + "@tiptap/react": "2.5.8", + "@tiptap/suggestion": "2.5.8", "hast-util-to-html": "^9.0.1", "linkifyjs": "^4.1.3", "mdast-util-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.1.0", "micromark-util-combine-extensions": "^2.0.0", "rehype-external-links": "^3.0.0", "rehype-format": "^5.0.0", @@ -51540,21 +51530,11 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.0", "remark-stringify": "^11.0.0", - "unified": "^11.0.4", + "unified": "^11.0.5", "validator": "^13.12.0", "zeed-dom": "^0.13.3" }, "dependencies": { - "@tiptap/extension-placeholder": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.4.0.tgz", - "integrity": "sha512-SmWOjgWpmhFt0BPOnL65abCUH0wS5yksUJgtANn5bQoHF4HFSsyl7ETRmgf0ykxdjc7tzOg31FfpWVH4wzKSYg==" - }, - "@tiptap/suggestion": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.4.0.tgz", - "integrity": "sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==" - }, "@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -51698,9 +51678,9 @@ } }, "micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "requires": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -51903,9 +51883,9 @@ } }, "unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "requires": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -56121,14 +56101,14 @@ } }, "@tiptap/core": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.4.0.tgz", - "integrity": "sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.5.8.tgz", + "integrity": "sha512-lkWCKyoAoMTxM137MoEsorG7tZ5MZU6O3wMRuZ0P9fcTRY5vd1NWncWuPzuGSJIpL20gwBQOsS6PaQSfR3xjlA==" }, "@tiptap/extension-blockquote": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.4.0.tgz", - "integrity": "sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.5.8.tgz", + "integrity": "sha512-P8vDiagtRrUfIewfCKrJe0ddDSjPgOTKzqoM1UXKS+MenT8C/wT4bjiwopAoWP6zMoV0TfHWXah9emllmCfXFA==" }, "@tiptap/extension-bubble-menu": { "version": "2.5.8", @@ -56139,24 +56119,24 @@ } }, "@tiptap/extension-bullet-list": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.4.0.tgz", - "integrity": "sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw==" - }, - "@tiptap/extension-code": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.4.0.tgz", - "integrity": "sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.5.8.tgz", + "integrity": "sha512-Wvf0HWBI0ulssoCsCOguxJB1Ntmj9PtE8b/ieFwFvrNptP+sf25XiWgjMs7H1KQrtmpngBu/Bhh5jJRgAmAgeQ==" }, "@tiptap/extension-code-block": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.4.0.tgz", - "integrity": "sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.5.8.tgz", + "integrity": "sha512-atMtT1Ddc4hv9+OiH/UCLfQ6Ooo45xpPaaOhqs1Ab509YyqxoyEbfNSOth/yx9DFb8VOenRWE1WV3Z3C0ial0Q==" }, "@tiptap/extension-document": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.4.0.tgz", - "integrity": "sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.5.8.tgz", + "integrity": "sha512-r3rP4ihCJAdp3VRIeqd80etHx7jttzZaKNFX8hkQShHK6eTHwrR92VL0jDE4K+NOE3bxjMsOlYizJYWV042BtA==" + }, + "@tiptap/extension-dropcursor": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.5.8.tgz", + "integrity": "sha512-xPmIfTYqurFF8RukCPlHd8mT8I7hDinWrgq7CQTRROxcJ3DNw8PooWrKWaBYs9HXHe1pbiQ5EK0uOsNvQ1bcDg==" }, "@tiptap/extension-floating-menu": { "version": "2.5.8", @@ -56167,44 +56147,44 @@ } }, "@tiptap/extension-gapcursor": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.4.0.tgz", - "integrity": "sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.5.8.tgz", + "integrity": "sha512-nR7AUOE4xWdp0sDbLbe4uwAhQ/xq+MTLVafvffMLT81U/Hl9R+w0Ap2XF0+c6/JTQwVjZiOalAmg4dobx7rJUQ==" }, "@tiptap/extension-hard-break": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.4.0.tgz", - "integrity": "sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.5.8.tgz", + "integrity": "sha512-samZEL0EXzHSmMQ7KyLnfSxdDv3qSjia0JzelfCnFZS6LLcbwjrIjV8ZPxEhJ7UlZqroQdFxPegllkLHZj/MdQ==" }, "@tiptap/extension-heading": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.4.0.tgz", - "integrity": "sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.5.8.tgz", + "integrity": "sha512-fDQoUkTLN+U8MNQ8PI+syKyshS9qFHlKihxzMLf/+tRisJvP47gzHDur99nffTSbXFDnASDqhavhKjI/2xTWlQ==" }, "@tiptap/extension-history": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.4.0.tgz", - "integrity": "sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.5.8.tgz", + "integrity": "sha512-5IrZZfp2Rg9Tov/08aYTKhwoiqdun8v3j3vleuqyW5RB7LU/NKLR19EtSSMh9mVkFZVbhab2zDOFmn5ilsEOhw==" }, "@tiptap/extension-horizontal-rule": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.4.0.tgz", - "integrity": "sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.5.8.tgz", + "integrity": "sha512-L8Is73WGaP6VNdKrIry+lCIM9W1KaL/Tw2Z6DGMVMU5mr1lLx0xq7nWEStqD7e4zh+n4+3PV15cZSA2F34DZrg==" }, "@tiptap/extension-list-item": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.4.0.tgz", - "integrity": "sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.5.8.tgz", + "integrity": "sha512-RFIIzHxxXdPmdf7BL0zhE4VPHoR6BTWtfi3JCTftmNqKoH7o+mLKT0RHMGvF1CGNn2HewHzXAF0iXfKCwmEgHQ==" }, "@tiptap/extension-ordered-list": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.4.0.tgz", - "integrity": "sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.5.8.tgz", + "integrity": "sha512-84gWdWhc8rUCCssn8+6Z1rFKdG7/yIe+gwYkU6WqAtDrcluJdt5jRHrcMOLxb2dbY8ww9pa72EYV/bwOisZlFQ==" }, "@tiptap/extension-paragraph": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.4.0.tgz", - "integrity": "sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.5.8.tgz", + "integrity": "sha512-AMfD3lfGSiomfkSE2tUourUjVahLtIfWUQew13NTPuWoxAXaSyoCGO0ULkiou/lO3JVUUUmF9+KJrAHWGIARdA==" }, "@tiptap/extension-placeholder": { "version": "2.5.8", @@ -56212,47 +56192,56 @@ "integrity": "sha512-mvRl73OM5jBXVtDRLSTvp8/4+0mS2J2+ZcuiAHjABwEsZRCfJsiqty5NisOxSuy/AQtm8TK2kyt6ZCXQ2VRGig==" }, "@tiptap/extension-strike": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.4.0.tgz", - "integrity": "sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.5.8.tgz", + "integrity": "sha512-uiHhBIEqawX9Up2ofklotVQ5XpGIjwRL6wprZF38s1le3XpsgyhVV7oDnqDkC7ujCsGkOJJfXZtv3LsO3R2nzQ==" }, "@tiptap/extension-text": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.4.0.tgz", - "integrity": "sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg==" + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.5.8.tgz", + "integrity": "sha512-CNkD51jRMdcYCqFVOkrnebqBQ6pCD3ZD5z9kO5bOC5UPZKZBkLsWdlrHGAVwosxcGxdJACbqJ0Nj+fMgIw4tNA==" }, "@tiptap/pm": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.4.0.tgz", - "integrity": "sha512-B1HMEqGS4MzIVXnpgRZDLm30mxDWj51LkBT/if1XD+hj5gm8B9Q0c84bhvODX6KIs+c6z+zsY9VkVu8w9Yfgxg==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.5.8.tgz", + "integrity": "sha512-CVhHaTG4QNHSkvuh6HHsUR4hE+nbUnk7z+VMUedaqPU8tNqkTwWGCMbiyTc+PCsz0T9Mni7vvBR+EXgEQ3+w4g==", "requires": { "prosemirror-changeset": "^2.2.1", "prosemirror-collab": "^1.3.1", "prosemirror-commands": "^1.5.2", "prosemirror-dropcursor": "^1.8.1", "prosemirror-gapcursor": "^1.3.2", - "prosemirror-history": "^1.3.2", - "prosemirror-inputrules": "^1.3.0", + "prosemirror-history": "^1.4.1", + "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", - "prosemirror-markdown": "^1.12.0", + "prosemirror-markdown": "^1.13.0", "prosemirror-menu": "^1.2.4", - "prosemirror-model": "^1.19.4", - "prosemirror-schema-basic": "^1.2.2", - "prosemirror-schema-list": "^1.3.0", + "prosemirror-model": "^1.22.2", + "prosemirror-schema-basic": "^1.2.3", + "prosemirror-schema-list": "^1.4.1", "prosemirror-state": "^1.4.3", - "prosemirror-tables": "^1.3.5", - "prosemirror-trailing-node": "^2.0.7", - "prosemirror-transform": "^1.8.0", - "prosemirror-view": "^1.32.7" + "prosemirror-tables": "^1.4.0", + "prosemirror-trailing-node": "^2.0.9", + "prosemirror-transform": "^1.9.0", + "prosemirror-view": "^1.33.9" } }, "@tiptap/react": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.4.0.tgz", - "integrity": "sha512-baxnIr6Dy+5iGagOEIKFeHzdl1ZRa6Cg+SJ3GDL/BVLpO6KiCM3Mm5ymB726UKP1w7icrBiQD2fGY3Bx8KaiSA==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.5.8.tgz", + "integrity": "sha512-twUMm8HV7scUgR/E1hYS9N6JDtKPl7cgDiPjxTynNHc5S5f5Ecv4ns/BZRq3TMZ/JDrp4rghLvgq+ImQsLvPOA==", "requires": { - "@tiptap/extension-bubble-menu": "^2.4.0", - "@tiptap/extension-floating-menu": "^2.4.0" + "@tiptap/extension-bubble-menu": "^2.5.8", + "@tiptap/extension-floating-menu": "^2.5.8", + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.2.2" + }, + "dependencies": { + "use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==" + } } }, "@tiptap/suggestion": { @@ -57282,6 +57271,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" }, + "@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==" + }, "@types/uuid": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz", @@ -73287,9 +73281,9 @@ } }, "prosemirror-commands": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", - "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.0.tgz", + "integrity": "sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==", "requires": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -73318,9 +73312,9 @@ } }, "prosemirror-history": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.0.tgz", - "integrity": "sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", "requires": { "prosemirror-state": "^1.2.2", "prosemirror-transform": "^1.0.0", @@ -73367,25 +73361,25 @@ } }, "prosemirror-model": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.1.tgz", - "integrity": "sha512-IVBAuMqOfltTr7yPypwpfdGT+6rGAteVOw2FO6GEvCGGa1ZwxLseqC1Eax/EChDvG/xGquB2d/hLdgh3THpsYg==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.2.tgz", + "integrity": "sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==", "requires": { "orderedmap": "^2.0.0" } }, "prosemirror-schema-basic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz", - "integrity": "sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz", + "integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==", "requires": { "prosemirror-model": "^1.19.0" } }, "prosemirror-schema-list": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz", - "integrity": "sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz", + "integrity": "sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==", "requires": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -73403,9 +73397,9 @@ } }, "prosemirror-tables": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz", - "integrity": "sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.4.0.tgz", + "integrity": "sha512-fxryZZkQG12fSCNuZDrYx6Xvo2rLYZTbKLRd8rglOPgNJGMKIS8uvTt6gGC38m7UCu/ENnXIP9pEz5uDaPc+cA==", "requires": { "prosemirror-keymap": "^1.1.2", "prosemirror-model": "^1.8.1", @@ -73415,9 +73409,9 @@ } }, "prosemirror-trailing-node": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz", - "integrity": "sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.9.tgz", + "integrity": "sha512-YvyIn3/UaLFlFKrlJB6cObvUhmwFNZVhy1Q8OpW/avoTbD/Y7H5EcjK4AZFKhmuS6/N6WkGgt7gWtBWDnmFvHg==", "requires": { "@remirror/core-constants": "^2.0.2", "escape-string-regexp": "^4.0.0" @@ -73439,9 +73433,9 @@ } }, "prosemirror-view": { - "version": "1.33.7", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.7.tgz", - "integrity": "sha512-jo6eMQCtPRwcrA2jISBCnm0Dd2B+szS08BU1Ay+XGiozHo5EZMHfLQE8R5nO4vb1spTH2RW1woZIYXRiQsuP8g==", + "version": "1.33.9", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.9.tgz", + "integrity": "sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==", "requires": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", diff --git a/package.json b/package.json index 9e3d647f0d..e37381513b 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@artsy/fresnel": "^6.1.0", "@ensdomains/content-hash": "^2.5.7", "@matters/apollo-upload-client": "^11.1.0", - "@matters/matters-editor": "^0.2.5-alpha.6", + "@matters/matters-editor": "^0.3.0-alpha.0", "@next/bundle-analyzer": "^13.4.9", "@reach/alert": "^0.18.0", "@reach/dialog": "^0.18.0", @@ -55,10 +55,6 @@ "@stripe/react-stripe-js": "^2.1.1", "@stripe/stripe-js": "^1.54.1", "@tippyjs/react": "^4.2.6", - "@tiptap/extension-bubble-menu": "^2.5.8", - "@tiptap/extension-floating-menu": "^2.5.8", - "@tiptap/extension-placeholder": "^2.5.8", - "@tiptap/suggestion": "^2.5.8", "@use-gesture/react": "^10.3.1", "apollo-cache-inmemory": "^1.6.6", "apollo-client": "^2.6.10", diff --git a/src/components/Editor/Article/extensions/index.ts b/src/components/Editor/Article/extensions/index.ts index 641d37010f..9e836bde17 100644 --- a/src/components/Editor/Article/extensions/index.ts +++ b/src/components/Editor/Article/extensions/index.ts @@ -3,5 +3,4 @@ export * from './figureEmbedLinkInput' export * from './figureImageUploader' export * from './figurePlaceholder' export * from './mention' -export * from './pasteDropFile' export * from './smartLink' diff --git a/src/components/Editor/Article/extensions/pasteDropFile.ts b/src/components/Editor/Article/extensions/pasteDropFile.ts deleted file mode 100644 index 2ef0d4864b..0000000000 --- a/src/components/Editor/Article/extensions/pasteDropFile.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Editor } from '@matters/matters-editor' -import { Node } from '@tiptap/core' -import { Plugin, PluginKey } from '@tiptap/pm/state' - -/** - * A extension to handle paste and drop image events. - */ - -type PasteDropFileOptions = { - onPaste: (editor: Editor, files: File[]) => void - onDrop: (editor: Editor, files: File[], pos: number) => void - mimeTypes: string[] -} - -const pluginName = 'pasteDropFile' - -const makePlugin = ({ - editor, - onDrop, - onPaste, - mimeTypes, -}: PasteDropFileOptions & { editor: Editor }) => { - return new Plugin({ - key: new PluginKey(pluginName), - props: { - handleDrop(view, event, slice, moved) { - const files = Array.from(event.dataTransfer?.files || []).filter( - (file) => mimeTypes.includes(file.type) - ) - - if (files.length <= 0) return - - const position = view.posAtCoords({ - left: event.clientX, - top: event.clientY, - }) - - event.stopPropagation() - onDrop(editor, files, position?.pos || 0) - - return true - }, - handlePaste(view, event, slice) { - const files = Array.from(event.clipboardData?.files || []).filter( - (file) => mimeTypes.includes(file.type) - ) - - if (files.length <= 0) return - - event.stopPropagation() - onPaste(editor, files) - - return true - }, - }, - }) -} - -export const PasteDropFile = Node.create({ - name: pluginName, - - addProseMirrorPlugins() { - return [makePlugin({ ...this.options, editor: this.editor as Editor })] - }, -}) diff --git a/src/components/Editor/Article/index.tsx b/src/components/Editor/Article/index.tsx index 34f43b1150..5eb162dd36 100644 --- a/src/components/Editor/Article/index.tsx +++ b/src/components/Editor/Article/index.tsx @@ -1,5 +1,13 @@ import { useApolloClient } from '@apollo/react-hooks' -import { EditorContent, useArticleEdtor } from '@matters/matters-editor' +import { + articleEditorExtensions, + Dropcursor, + EditorContent, + Mention, + PasteDropFile, + Placeholder, + useEditor, +} from '@matters/matters-editor' import { useIntl } from 'react-intl' import { useDebouncedCallback } from 'use-debounce' @@ -13,7 +21,6 @@ import { FigureImageUploader, FigurePlaceholder, makeMentionSuggestion, - PasteDropFile, SmartLink, } from './extensions' import { makeSmartLinkOptions } from './extensions/smartLink/utils' @@ -49,19 +56,23 @@ export const ArticleEditor: React.FC = ({ update(c) }, INPUT_DEBOUNCE) - const editor = useArticleEdtor({ + const editor = useEditor({ editable: !isReadOnly, - placeholder: intl.formatMessage({ - defaultMessage: 'Enter content…', - id: 'yCTXXb', - }), content: content || '', onUpdate: async ({ editor, transaction }) => { const content = editor.getHTML() debouncedUpdate({ content }) }, - mentionSuggestion: makeMentionSuggestion({ client }), extensions: [ + Placeholder.configure({ + placeholder: intl.formatMessage({ + defaultMessage: 'Enter content…', + id: 'yCTXXb', + }), + }), + Mention.configure({ + suggestion: makeMentionSuggestion({ client }), + }), FigureEmbedLinkInput, FigurePlaceholder.configure({ placeholder: intl.formatMessage({ @@ -73,8 +84,8 @@ export const ArticleEditor: React.FC = ({ maxCaptionLength: 100, }), SmartLink.configure(makeSmartLinkOptions({ client })), - // FileUploadIndicator, FigureImageUploader, + Dropcursor.configure(), PasteDropFile.configure({ onDrop: async (editor, files, pos) => { let chain = editor.chain() @@ -105,6 +116,7 @@ export const ArticleEditor: React.FC = ({ }, mimeTypes: ACCEPTED_UPLOAD_IMAGE_TYPES, }), + ...articleEditorExtensions, ], }) diff --git a/src/components/Editor/Comment/index.tsx b/src/components/Editor/Comment/index.tsx index 948767f3bc..d259226ec8 100644 --- a/src/components/Editor/Comment/index.tsx +++ b/src/components/Editor/Comment/index.tsx @@ -1,8 +1,11 @@ import { useApolloClient } from '@apollo/react-hooks' import { + commentEditorExtensions, Editor, EditorContent, - useCommentEditor, + Mention, + Placeholder, + useEditor, } from '@matters/matters-editor' import { useEffect } from 'react' import { useIntl } from 'react-intl' @@ -40,8 +43,7 @@ const CommentEditor: React.FC = ({ defaultMessage: 'Any thoughts? Leave a kind comment~', }) - const editor = useCommentEditor({ - placeholder, + const editor = useEditor({ content: content || '', onUpdate: async ({ editor, transaction }) => { const content = editor.getHTML() @@ -56,8 +58,16 @@ const CommentEditor: React.FC = ({ onDestroy: () => { window.dispatchEvent(new CustomEvent(ENBABLE_SCROLL_LOCK)) }, - mentionSuggestion: makeMentionSuggestion({ client }), - extensions: [SmartLink.configure(makeSmartLinkOptions({ client }))], + extensions: [ + Placeholder.configure({ + placeholder, + }), + Mention.configure({ + suggestion: makeMentionSuggestion({ client }), + }), + SmartLink.configure(makeSmartLinkOptions({ client })), + ...commentEditorExtensions, + ], }) useEffect(() => { From 80ba2ab53b093e2b33d2e44aef5b20f07e54970b Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:28:04 +0700 Subject: [PATCH 03/22] feat(editor): cache previous upload --- .../figureImageUploader/Uploader.tsx | 25 ++++++++++++++++--- .../extensions/figureImageUploader/index.ts | 10 +++++++- .../Article/extensions/smartLink/index.ts | 6 ----- src/components/Editor/Article/index.tsx | 6 +---- .../Editor/Article/styles.module.css | 10 +++++++- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx b/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx index ba38fb7930..8c65342bd6 100644 --- a/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx +++ b/src/components/Editor/Article/extensions/figureImageUploader/Uploader.tsx @@ -36,11 +36,30 @@ const Uploader: React.FC = (props) => { if (!mime) return try { - const { path } = await upload({ file, type: ASSET_TYPE.embed, mime }) + // read from storage cache to prevent duplicate upload + // when redo and undo + const assets = editor.storage.figureImageUploader.assets as { + [key: string]: string + } + let path = assets[previewSrc] + + // upload and update cache + if (!path) { + path = (await upload({ file, type: ASSET_TYPE.embed, mime })).path + editor.storage.figureImageUploader.assets = { + ...assets, + [previewSrc]: path, + } + } + + const pos = getPos() + if (!getPos()) { + return + } return editor .chain() - .insertContentAt({ from: getPos(), to: getPos() + 1 }, [ + .insertContentAt({ from: pos, to: pos + 1 }, [ { type: 'figureImage', attrs: { src: path } }, ]) .run() @@ -81,7 +100,7 @@ const Uploader: React.FC = (props) => { }, []) return ( - + Uploading... {progress}% diff --git a/src/components/Editor/Article/extensions/figureImageUploader/index.ts b/src/components/Editor/Article/extensions/figureImageUploader/index.ts index da60d20a1e..1504c09497 100644 --- a/src/components/Editor/Article/extensions/figureImageUploader/index.ts +++ b/src/components/Editor/Article/extensions/figureImageUploader/index.ts @@ -32,6 +32,12 @@ export const FigureImageUploader = Node.create({ } }, + addStorage() { + return { + assets: {}, + } + }, + parseHTML() { return [{ tag: 'figure-image-uploader' }] }, @@ -41,7 +47,9 @@ export const FigureImageUploader = Node.create({ }, addNodeView() { - return ReactNodeViewRenderer(Uploader) + return ReactNodeViewRenderer(Uploader, { + className: 'figure-image-uploader', + }) }, addCommands() { diff --git a/src/components/Editor/Article/extensions/smartLink/index.ts b/src/components/Editor/Article/extensions/smartLink/index.ts index 3d7455cffb..99a9a82f9b 100644 --- a/src/components/Editor/Article/extensions/smartLink/index.ts +++ b/src/components/Editor/Article/extensions/smartLink/index.ts @@ -123,12 +123,6 @@ const findAndSearch = _debounce( export const SmartLink = Extension.create({ name: 'smartLink', - addStorage() { - return { - results: [], - } - }, - onUpdate() { // regexp must contains a named group `key` if (this.options.findRule.toString().indexOf('?') === -1) { diff --git a/src/components/Editor/Article/index.tsx b/src/components/Editor/Article/index.tsx index 5eb162dd36..a281b58951 100644 --- a/src/components/Editor/Article/index.tsx +++ b/src/components/Editor/Article/index.tsx @@ -102,17 +102,13 @@ export const ArticleEditor: React.FC = ({ chain.run() }, onPaste: async (editor, files) => { - let chain = editor.chain() - Array.from(files).forEach((file) => { - chain.addFigureImageUploader({ + editor.commands.addFigureImageUploader({ upload, previewSrc: URL.createObjectURL(file), file, }) }) - - chain.run() }, mimeTypes: ACCEPTED_UPLOAD_IMAGE_TYPES, }), diff --git a/src/components/Editor/Article/styles.module.css b/src/components/Editor/Article/styles.module.css index 398438a878..e94cd9490b 100644 --- a/src/components/Editor/Article/styles.module.css +++ b/src/components/Editor/Article/styles.module.css @@ -90,9 +90,17 @@ } /* image uploader */ - & :global(.figure-image-uploader) { + & :global(.figure-image-uploader), + & :global(figure), + /* gapcursor will sit between two figure */ + & :global(.ProseMirror-gapcursor) { position: relative; margin: var(--ar17-200) 0; + + & + :global(.figure-image-uploader), + & + :global(figure) { + margin-top: calc(var(--ar17-200) * 2); + } } } From e7428e708399d63f29efb981bb017d229381ceda Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:55:10 +0700 Subject: [PATCH 04/22] feat(editor): use figureImageUploader in UploadImageButton --- .../FloatingMenu/UploadImageButton.tsx | 60 ++++--------------- 1 file changed, 11 insertions(+), 49 deletions(-) diff --git a/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx b/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx index 2b53524d3e..86103351df 100644 --- a/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx +++ b/src/components/Editor/Article/FloatingMenu/UploadImageButton.tsx @@ -1,13 +1,10 @@ import { Editor } from '@matters/matters-editor' import { VisuallyHidden } from '@reach/visually-hidden' -import classNames from 'classnames' -import { useState } from 'react' -import { FormattedMessage, useIntl } from 'react-intl' +import { useIntl } from 'react-intl' import { ReactComponent as IconEditorImage } from '@/public/static/icons/editor-image.svg' import { ACCEPTED_UPLOAD_IMAGE_TYPES, ASSET_TYPE } from '~/common/enums' -import { getFileType, validateImage } from '~/common/utils' -import { Icon, toast } from '~/components' +import { Icon } from '~/components' import styles from './styles.module.css' @@ -29,7 +26,6 @@ const UploadImageButton: React.FC = ({ upload, }) => { const intl = useIntl() - const [uploading, setUploading] = useState(false) const acceptTypes = ACCEPTED_UPLOAD_IMAGE_TYPES.join(',') const fieldId = 'editor-image-upload-form' @@ -37,59 +33,26 @@ const UploadImageButton: React.FC = ({ const handleChange = async (event: React.ChangeEvent) => { event.stopPropagation() - if (!upload || !event.target || !event.target.files) { - return - } - - const files = event.target.files + const files = event.target?.files - const hasInvalidImage = await Promise.all( - Array.from(files).map((file) => validateImage(file)) - ).then((results) => results.some((result) => !result)) - - if (hasInvalidImage) { - event.target.value = '' + if (!upload || !files) { return } - try { - setUploading(true) - - for (const file of files) { - const mime = (await getFileType(file))!.mime - const { path } = await upload({ file, type: ASSET_TYPE.embed, mime }) - - editor.chain().focus().setFigureImage({ src: path }).run() - - toast.success({ - message: ( - - ), - }) - } - } catch (e) { - toast.error({ - message: ( - - ), + Array.from(files).forEach((file) => { + editor.commands.addFigureImageUploader({ + previewSrc: URL.createObjectURL(file), + file, + upload, }) - } + }) event.target.value = '' - setUploading(false) } - const labelClasses = classNames({ - [styles.uploadButton]: true, - 'u-area-disable': uploading, - }) - return (