From 1e288ab08a953c3f0cab762e69ffc4ec1b53ccf9 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 17 Jul 2025 17:23:30 +0700 Subject: [PATCH] feat: fix editor --- apps/frontend/src/app/global.scss | 19 ++ .../launches/general.preview.component.tsx | 2 +- .../launches/helpers/linkedin.component.tsx | 57 +---- .../launches/helpers/new.image.component.tsx | 89 -------- .../src/components/new-launch/editor.tsx | 205 +++++++++++------- .../new-launch/heading.component.tsx | 73 +++++++ .../components/new-launch/manage.modal.tsx | 1 - .../providers/devto/devto.provider.tsx | 45 ---- .../providers/hashnode/hashnode.provider.tsx | 46 ---- .../providers/medium/medium.provider.tsx | 32 --- .../providers/reddit/reddit.provider.tsx | 13 +- .../post-url-selector/post.url.selector.tsx | 49 ----- .../src/utils/strip.html.validation.ts | 20 +- package.json | 1 + pnpm-lock.yaml | 13 +- 15 files changed, 249 insertions(+), 416 deletions(-) delete mode 100644 apps/frontend/src/components/launches/helpers/new.image.component.tsx create mode 100644 apps/frontend/src/components/new-launch/heading.component.tsx diff --git a/apps/frontend/src/app/global.scss b/apps/frontend/src/app/global.scss index 2047d477..8b304d79 100644 --- a/apps/frontend/src/app/global.scss +++ b/apps/frontend/src/app/global.scss @@ -552,4 +552,23 @@ html[dir='rtl'] [dir='ltr'] { .preview ul, .preview li { white-space: nowrap; +} + +.ProseMirror h1, .preview h1 { + font-size: 24px; + font-weight: bold; +} + +.ProseMirror h2, .preview h2 { + font-size: 20px; + font-weight: bold; +} + +.ProseMirror h3, .preview h3 { + font-size: 18px; + font-weight: bold; +} + +.preview p { + min-height: 24px; } \ No newline at end of file diff --git a/apps/frontend/src/components/launches/general.preview.component.tsx b/apps/frontend/src/components/launches/general.preview.component.tsx index 301a13a5..5014b20b 100644 --- a/apps/frontend/src/components/launches/general.preview.component.tsx +++ b/apps/frontend/src/components/launches/general.preview.component.tsx @@ -17,7 +17,7 @@ export const GeneralPreviewComponent: FC<{ const mediaDir = useMediaDirectory(); const renderContent = topValue.map((p) => { - const newContent = stripHtmlValidation('normal', p.content, true) + const newContent = stripHtmlValidation('plain', p.content, true) .replace(/(@.+?)(\s)/gi, (match, match1, match2) => { return `${match1.trim()}${match2}`; }) diff --git a/apps/frontend/src/components/launches/helpers/linkedin.component.tsx b/apps/frontend/src/components/launches/helpers/linkedin.component.tsx index e5a979d2..73cd83d2 100644 --- a/apps/frontend/src/components/launches/helpers/linkedin.component.tsx +++ b/apps/frontend/src/components/launches/helpers/linkedin.component.tsx @@ -3,13 +3,6 @@ import { EventEmitter } from 'events'; import React, { FC, useCallback, useEffect, useState } from 'react'; import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component'; -import { - executeCommand, - ExecuteState, - ICommand, - selectWord, - TextAreaTextApi, -} from '@uiw/react-md-editor'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import { Input } from '@gitroom/react/form/input'; import { Button } from '@gitroom/react/form/button'; @@ -178,52 +171,4 @@ export const LinkedinCompany: FC<{ ); }; -export const linkedinCompany = (identifier: string, id: string): ICommand[] => { - if (identifier !== 'linkedin' && identifier !== 'linkedin-page') { - return []; - } - return [ - { - name: 'linkedinCompany', - keyCommand: 'linkedinCompany', - shortcuts: 'ctrlcmd+p', - prefix: '', - suffix: '', - buttonProps: { - 'aria-label': 'Add Post Url', - title: 'Add Post Url', - }, - icon: ( - - - - ), - execute: async (state: ExecuteState, api: TextAreaTextApi) => { - const newSelectionRange = selectWord({ - text: state.text, - selection: state.selection, - prefix: state.command.prefix!, - suffix: state.command.suffix, - }); - const state1 = api.setSelectionRange(newSelectionRange); - const media = await showPostSelector(id); - executeCommand({ - api, - selectedText: state1.selectedText, - selection: state.selection, - prefix: media, - suffix: '', - }); - }, - }, - ]; -}; + diff --git a/apps/frontend/src/components/launches/helpers/new.image.component.tsx b/apps/frontend/src/components/launches/helpers/new.image.component.tsx deleted file mode 100644 index 9efa89c8..00000000 --- a/apps/frontend/src/components/launches/helpers/new.image.component.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react'; -import { - executeCommand, - ExecuteState, - ICommand, - selectWord, - TextAreaTextApi, -} from '@uiw/react-md-editor'; -import { showMediaBox } from '@gitroom/frontend/components/media/media.component'; -import { loadVars } from '@gitroom/react/helpers/variable.context'; -export const newImage: ICommand = { - name: 'image', - keyCommand: 'image', - shortcuts: 'ctrlcmd+k', - prefix: '![image](', - suffix: ')', - buttonProps: { - 'aria-label': 'Add image (ctrl + k)', - title: 'Add image (ctrl + k)', - }, - icon: ( - - - - ), - execute: (state: ExecuteState, api: TextAreaTextApi) => { - const { uploadDirectory, backendUrl } = loadVars(); - let newSelectionRange = selectWord({ - text: state.text, - selection: state.selection, - prefix: state.command.prefix!, - suffix: state.command.suffix, - }); - let state1 = api.setSelectionRange(newSelectionRange); - if ( - state1.selectedText.includes('http') || - state1.selectedText.includes('www') || - state1.selectedText.includes('(post:') - ) { - executeCommand({ - api, - selectedText: state1.selectedText, - selection: state.selection, - prefix: state.command.prefix!, - suffix: state.command.suffix, - }); - return; - } - newSelectionRange = selectWord({ - text: state.text, - selection: state.selection, - prefix: '![', - suffix: ']()', - }); - state1 = api.setSelectionRange(newSelectionRange); - showMediaBox((media) => { - if (media) { - if (state1.selectedText.length > 0) { - executeCommand({ - api, - selectedText: state1.selectedText, - selection: state.selection, - prefix: '![', - suffix: `](${ - media.path.indexOf('http') === -1 - ? `${backendUrl}/${uploadDirectory}` - : `` - }${media.path})`, - }); - return; - } - executeCommand({ - api, - selectedText: state1.selectedText, - selection: state.selection, - prefix: '![image', - suffix: `](${ - media.path.indexOf('http') === -1 - ? `${backendUrl}/${uploadDirectory}` - : `` - }${media.path})`, - }); - } - }); - }, -}; diff --git a/apps/frontend/src/components/new-launch/editor.tsx b/apps/frontend/src/components/new-launch/editor.tsx index c35c6df3..17860ce3 100644 --- a/apps/frontend/src/components/new-launch/editor.tsx +++ b/apps/frontend/src/components/new-launch/editor.tsx @@ -8,11 +8,12 @@ import React, { useRef, useState, ClipboardEvent, + forwardRef, + useImperativeHandle, } from 'react'; import clsx from 'clsx'; import { useUser } from '@gitroom/frontend/components/layout/user.context'; import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; -import { Transforms } from 'slate'; import EmojiPicker from 'emoji-picker-react'; import { Theme } from 'emoji-picker-react'; import { BoldText } from '@gitroom/frontend/components/new-launch/bold.text'; @@ -47,6 +48,8 @@ import { stripHtmlValidation } from '@gitroom/helpers/utils/strip.html.validatio import { History } from '@tiptap/extension-history'; import { BulletList, ListItem } from '@tiptap/extension-list'; import { Bullets } from '@gitroom/frontend/components/new-launch/bullets.component'; +import Heading from '@tiptap/extension-heading'; +import { HeadingComponent } from '@gitroom/frontend/components/new-launch/heading.component'; const InterceptBoldShortcut = Extension.create({ name: 'preventBoldWithUnderline', @@ -179,7 +182,7 @@ export const EditorWrapper: FC<{ postComment: state.postComment, editor: state.editor, loadedState: state.loaded, - setLoadedState: state.setLoaded + setLoadedState: state.setLoaded, })) ); @@ -195,6 +198,13 @@ export const EditorWrapper: FC<{ setLoaded(true); }, [loaded, loadedState]); + useEffect(() => { + if (editor) { + setLoaded(false); + setLoadedState(false); + } + }, [editor]); + const canEdit = useMemo(() => { return current === 'global' || !!internal; }, [current, internal]); @@ -493,6 +503,7 @@ export const Editor: FC<{ const newRef = useRef(null); const [emojiPickerOpen, setEmojiPickerOpen] = useState(false); const t = useT(); + const editorRef = useRef(); const uppy = useUppyUploader({ onUploadSuccess: (result: any) => { @@ -534,94 +545,59 @@ export const Editor: FC<{ const { getRootProps, isDragActive } = useDropzone({ onDrop }); - const editorOptions = useMemo(() => { - if (editorType === 'normal') { - return []; - } - - const list = []; - - if ( - editorType === ('markdown' as const) || - editorType === ('html' as const) - ) { - list.push(BulletList, ListItem); - } - - return list; - }, [editorType]); - - const editor = useEditor({ - extensions: [ - Document, - Paragraph, - Text, - Underline, - Bold, - InterceptBoldShortcut, - InterceptUnderlineShortcut, - Span, - History.configure({ - depth: 100, // default is 100 - newGroupDelay: 100, // default is 500ms - }), - ...editorOptions, - ], - content: props.value || '', - shouldRerenderOnTransaction: true, - immediatelyRender: false, - // @ts-ignore - onPaste: paste, - onUpdate: (innerProps) => { - props?.onChange?.(innerProps.editor.getHTML()); - }, - }); - const valueWithoutHtml = useMemo(() => { - return stripHtmlValidation('normal', props.value || ''); + return stripHtmlValidation('normal', props.value || '', false, true); }, [props.value]); const addText = useCallback( (emoji: string) => { - editor?.commands.insertContent(emoji); - editor?.commands.focus(); + editorRef?.current?.editor.commands.insertContent(emoji); + editorRef?.current?.editor.commands.focus(); }, [props.value, id] ); - const addLinkedinTag = useCallback( - (text: string) => { - const id = text.split('(')[1].split(')')[0]; - const name = text.split('[')[1].split(']')[0]; + const addLinkedinTag = useCallback((text: string) => { + const id = text.split('(')[1].split(')')[0]; + const name = text.split('[')[1].split(']')[0]; - editor - ?.chain() - .focus() - .insertContent({ - type: 'mention', - attrs: { - linkedinId: id, - label: name, - }, - }) - .run(); - }, - [editor] - ); - - if (!editor) { - return null; - } + editorRef?.current?.editor + .chain() + .focus() + .insertContent({ + type: 'mention', + attrs: { + linkedinId: id, + label: name, + }, + }) + .run(); + }, []); return (
- - - + + + {(editorType === 'markdown' || editorType === 'html') && ( - + <> + + + )}
- +
{ - if (editor?.isFocused) { + if (editorRef?.current?.editor?.isFocused) { return; } - editor?.commands?.focus('end'); + editorRef?.current?.editor?.commands?.focus('end'); }} > { - if (editor?.isFocused) { + if (editorRef?.current?.editor?.isFocused) { return; } - editor?.commands?.focus('end'); + editorRef?.current?.editor?.commands?.focus('end'); }} > {setImages && ( @@ -732,3 +714,68 @@ export const Editor: FC<{
); }; + +export const OnlyEditor = forwardRef< + any, + { + editorType: 'normal' | 'markdown' | 'html'; + value: string; + onChange: (value: string) => void; + paste?: (event: ClipboardEvent | File[]) => void; + } +>(({ editorType, value, onChange, paste }, ref) => { + const editorOptions = useMemo(() => { + if (editorType === 'normal') { + return []; + } + + const list = []; + + if ( + editorType === ('markdown' as const) || + editorType === ('html' as const) + ) { + list.push( + BulletList, + ListItem, + Heading.configure({ + levels: [1, 2, 3], + }) + ); + } + + return list; + }, [editorType]); + + const editor = useEditor({ + extensions: [ + Document, + Paragraph, + Text, + Underline, + Bold, + InterceptBoldShortcut, + InterceptUnderlineShortcut, + Span, + History.configure({ + depth: 100, // default is 100 + newGroupDelay: 100, // default is 500ms + }), + ...editorOptions, + ], + content: value || '', + shouldRerenderOnTransaction: true, + immediatelyRender: false, + // @ts-ignore + onPaste: paste, + onUpdate: (innerProps) => { + onChange?.(innerProps.editor.getHTML()); + }, + }); + + useImperativeHandle(ref, () => ({ + editor, + })); + + return ; +}); diff --git a/apps/frontend/src/components/new-launch/heading.component.tsx b/apps/frontend/src/components/new-launch/heading.component.tsx new file mode 100644 index 00000000..d4204839 --- /dev/null +++ b/apps/frontend/src/components/new-launch/heading.component.tsx @@ -0,0 +1,73 @@ +'use client'; + +import { FC, useCallback } from 'react'; + +export const HeadingComponent: FC<{ + editor: any; + currentValue: string; +}> = ({ editor }) => { + const setHeading = useCallback((level: number) => () => { + editor.commands.toggleHeading({ level }) + }, []); + + return ( +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ ); +}; diff --git a/apps/frontend/src/components/new-launch/manage.modal.tsx b/apps/frontend/src/components/new-launch/manage.modal.tsx index 6102d4ad..87d07a5a 100644 --- a/apps/frontend/src/components/new-launch/manage.modal.tsx +++ b/apps/frontend/src/components/new-launch/manage.modal.tsx @@ -166,7 +166,6 @@ export const ManageModal: FC = (props) => { return; } - console.log(checkAllValid); for (const item of checkAllValid) { if (item.valid === false) { toaster.show('Some fields are not valid', 'warning'); diff --git a/apps/frontend/src/components/new-launch/providers/devto/devto.provider.tsx b/apps/frontend/src/components/new-launch/providers/devto/devto.provider.tsx index 0898a7b3..66c7e5e7 100644 --- a/apps/frontend/src/components/new-launch/providers/devto/devto.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/devto/devto.provider.tsx @@ -12,55 +12,10 @@ import { SelectOrganization } from '@gitroom/frontend/components/new-launch/prov import { DevtoTags } from '@gitroom/frontend/components/new-launch/providers/devto/devto.tags'; import { useMediaDirectory } from '@gitroom/react/helpers/use.media.directory'; import clsx from 'clsx'; -import MDEditor from '@uiw/react-md-editor'; import { Canonical } from '@gitroom/react/form/canonical'; import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration'; import { useSettings } from '@gitroom/frontend/components/launches/helpers/use.values'; -const DevtoPreview: FC = () => { - const { value } = useIntegration(); - const settings = useSettings(); - const image = useMediaDirectory(); - const [coverPicture, title, tags] = settings.watch([ - 'main_image', - 'title', - 'tags', - ]); - return ( -
- {!!coverPicture?.path && ( -
- cover_picture -
- )} -
-
{title}
-
- {tags?.map((p: any) => ( -
#{p.label}
- ))} -
-
-
- p.content).join('\n')} - /> -
-
- ); -}; const DevtoSettings: FC = () => { const form = useSettings(); const { date } = useIntegration(); diff --git a/apps/frontend/src/components/new-launch/providers/hashnode/hashnode.provider.tsx b/apps/frontend/src/components/new-launch/providers/hashnode/hashnode.provider.tsx index 432b3e4e..b4793ff2 100644 --- a/apps/frontend/src/components/new-launch/providers/hashnode/hashnode.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/hashnode/hashnode.provider.tsx @@ -13,55 +13,9 @@ import { HashnodeSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/provid import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration'; import { useMediaDirectory } from '@gitroom/react/helpers/use.media.directory'; import clsx from 'clsx'; -import MDEditor from '@uiw/react-md-editor'; import { MediaComponent } from '@gitroom/frontend/components/media/media.component'; import { Canonical } from '@gitroom/react/form/canonical'; -const HashnodePreview: FC = () => { - const { value } = useIntegration(); - const settings = useSettings(); - const image = useMediaDirectory(); - const [coverPicture, title, subtitle] = settings.watch([ - 'main_image', - 'title', - 'subtitle', - ]); - return ( -
- {!!coverPicture?.path && ( -
- cover_picture -
- )} -
-
- {title} -
-
- {subtitle} -
-
-
- p.content).join('\n')} - /> -
-
- ); -}; const HashnodeSettings: FC = () => { const form = useSettings(); const { date } = useIntegration(); diff --git a/apps/frontend/src/components/new-launch/providers/medium/medium.provider.tsx b/apps/frontend/src/components/new-launch/providers/medium/medium.provider.tsx index dbc32bf9..ee29ac51 100644 --- a/apps/frontend/src/components/new-launch/providers/medium/medium.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/medium/medium.provider.tsx @@ -11,40 +11,8 @@ import { MediumPublications } from '@gitroom/frontend/components/new-launch/prov import { MediumTags } from '@gitroom/frontend/components/new-launch/providers/medium/medium.tags'; import { MediumSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/medium.settings.dto'; import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration'; -import clsx from 'clsx'; -import MDEditor from '@uiw/react-md-editor'; import { Canonical } from '@gitroom/react/form/canonical'; -import interClass from '@gitroom/react/helpers/inter.font'; -const MediumPreview: FC = () => { - const { value } = useIntegration(); - const settings = useSettings(); - const [title, subtitle] = settings.watch(['title', 'subtitle']); - return ( -
-
-
{title}
-
- {subtitle} -
-
-
- p.content).join('\n')} - /> -
-
- ); -}; const MediumSettings: FC = () => { const form = useSettings(); const { date } = useIntegration(); diff --git a/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx b/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx index 98a66d20..e27754b8 100644 --- a/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/reddit/reddit.provider.tsx @@ -17,7 +17,6 @@ import { import clsx from 'clsx'; import { useMediaDirectory } from '@gitroom/react/helpers/use.media.directory'; import { deleteDialog } from '@gitroom/react/helpers/delete.dialog'; -import MDEditor from '@uiw/react-md-editor'; import interClass from '@gitroom/react/helpers/inter.font'; import Image from 'next/image'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; @@ -38,14 +37,12 @@ const RenderRedditComponent: FC<{ switch (type) { case 'self': return ( - ); case 'link': @@ -143,13 +140,11 @@ const RedditPreview: FC = (props) => {
{integration?.name}
-
diff --git a/apps/frontend/src/components/post-url-selector/post.url.selector.tsx b/apps/frontend/src/components/post-url-selector/post.url.selector.tsx index 899a7cd4..88cfefbb 100644 --- a/apps/frontend/src/components/post-url-selector/post.url.selector.tsx +++ b/apps/frontend/src/components/post-url-selector/post.url.selector.tsx @@ -3,13 +3,6 @@ import { EventEmitter } from 'events'; import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.title.component'; -import { - executeCommand, - ExecuteState, - ICommand, - selectWord, - TextAreaTextApi, -} from '@uiw/react-md-editor'; import dayjs from 'dayjs'; import useSWR from 'swr'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; @@ -211,45 +204,3 @@ export const PostSelector: FC<{ ); }; -export const postSelector = (date: dayjs.Dayjs): ICommand => ({ - name: 'postselector', - keyCommand: 'postselector', - shortcuts: 'ctrlcmd+p', - prefix: '(post:', - suffix: ')', - buttonProps: { - 'aria-label': 'Add Post Url', - title: 'Add Post Url', - }, - icon: ( - - - - ), - execute: async (state: ExecuteState, api: TextAreaTextApi) => { - const newSelectionRange = selectWord({ - text: state.text, - selection: state.selection, - prefix: state.command.prefix!, - suffix: state.command.suffix, - }); - const state1 = api.setSelectionRange(newSelectionRange); - const media = await showPostSelector(date); - executeCommand({ - api, - selectedText: state1.selectedText, - selection: state.selection, - prefix: media, - suffix: '', - }); - }, -}); diff --git a/libraries/helpers/src/utils/strip.html.validation.ts b/libraries/helpers/src/utils/strip.html.validation.ts index dd8c71b3..5e4d8e7e 100644 --- a/libraries/helpers/src/utils/strip.html.validation.ts +++ b/libraries/helpers/src/utils/strip.html.validation.ts @@ -132,15 +132,20 @@ const underlineMap = { }; export const stripHtmlValidation = ( - type: 'normal' | 'markdown' | 'html', + type: 'plain' | 'none' | 'normal' | 'markdown' | 'html', value: string, - replaceBold = false + replaceBold = false, + none = false ): string => { + if (type === 'plain') { + return value; + } + if (type === 'markdown') { return NodeHtmlMarkdown.translate(value); } - if (value.indexOf('

') === -1) { + if (value.indexOf('

') === -1 && !none) { return value; } @@ -150,15 +155,22 @@ export const stripHtmlValidation = ( .replace(/]*>/gi, '\n') .replace(/<\/p>/gi, ''); + if (none) { + return striptags(html); + } + if (replaceBold) { return striptags(convertLinkedinMention(convertToAscii(html)), [ 'ul', 'li', + 'h1', + 'h2', + 'h3', ]); } // Strip all other tags - return striptags(html, ['ul', 'li']); + return striptags(html, ['ul', 'li', 'h1', 'h2', 'h3']); }; export const convertLinkedinMention = (value: string) => { diff --git a/package.json b/package.json index 6b988745..ff995a76 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "@tailwindcss/postcss": "^4.1.7", "@tiptap/extension-bold": "^3.0.6", "@tiptap/extension-document": "^3.0.6", + "@tiptap/extension-heading": "^3.0.7", "@tiptap/extension-history": "^3.0.7", "@tiptap/extension-list": "^3.0.7", "@tiptap/extension-paragraph": "^3.0.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4f9dc81..44c8c053 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,6 +120,9 @@ importers: '@tiptap/extension-document': specifier: ^3.0.6 version: 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) + '@tiptap/extension-heading': + specifier: ^3.0.7 + version: 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) '@tiptap/extension-history': specifier: ^3.0.7 version: 3.0.7(@tiptap/extensions@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)) @@ -5493,10 +5496,10 @@ packages: peerDependencies: '@tiptap/core': ^3.0.6 - '@tiptap/extension-heading@3.0.6': - resolution: {integrity: sha512-umcsnc4IEacQjlnl7d/IaiFsVA5xG993VvnUG5fK08TOuy0yrliOqXsFGp4czGnRLBEh2zfXMMK+vnm2fuk5zw==} + '@tiptap/extension-heading@3.0.7': + resolution: {integrity: sha512-uS7fFcilFuzKEvhUgndELqlGweD+nZeLOb6oqUE5hM49vECjM7qVjVQnlhV+MH2W1w8eD08cn1lu6lDxaMOe5w==} peerDependencies: - '@tiptap/core': ^3.0.6 + '@tiptap/core': ^3.0.7 '@tiptap/extension-history@3.0.7': resolution: {integrity: sha512-F+zjS7Wz53sNCWh3KqSAug4/COgxs060tR9up0OXjw7iB3gJz6JMNpGaWmYF5WdOsLxph7FGRMb/Mr5keCqVDA==} @@ -21208,7 +21211,7 @@ snapshots: dependencies: '@tiptap/core': 3.0.6(@tiptap/pm@3.0.6) - '@tiptap/extension-heading@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))': + '@tiptap/extension-heading@3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))': dependencies: '@tiptap/core': 3.0.6(@tiptap/pm@3.0.6) @@ -21317,7 +21320,7 @@ snapshots: '@tiptap/extension-dropcursor': 3.0.6(@tiptap/extensions@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)) '@tiptap/extension-gapcursor': 3.0.6(@tiptap/extensions@3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)) '@tiptap/extension-hard-break': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) - '@tiptap/extension-heading': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) + '@tiptap/extension-heading': 3.0.7(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) '@tiptap/extension-horizontal-rule': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6) '@tiptap/extension-italic': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6)) '@tiptap/extension-link': 3.0.6(@tiptap/core@3.0.6(@tiptap/pm@3.0.6))(@tiptap/pm@3.0.6)