Change editor

This commit is contained in:
Oliver Walters 2026-05-26 09:57:32 +00:00
parent 50b67ffee9
commit 36bc444f90
3 changed files with 388 additions and 77 deletions

View File

@ -73,12 +73,19 @@
"@mantine/modals": "^9.2.1",
"@mantine/notifications": "^9.2.1",
"@mantine/spotlight": "^9.2.1",
"@mantine/tiptap": "^9.2.1",
"@mantine/utils": "^6.0.22",
"@mantine/vanilla-extract": "^9.2.1",
"@messageformat/date-skeleton": "^1.1.0",
"@sentry/react": "^10.43.0",
"@tabler/icons-react": "^3.17.0",
"@tanstack/react-query": "^5.56.2",
"@tiptap/core": "^3.23.6",
"@tiptap/extension-image": "^3.23.6",
"@tiptap/extension-link": "^3.23.6",
"@tiptap/pm": "^3.23.6",
"@tiptap/react": "^3.23.6",
"@tiptap/starter-kit": "^3.23.6",
"@uiw/codemirror-theme-vscode": "^4.25.8",
"@uiw/react-codemirror": "^4.25.8",
"@uiw/react-split": "^5.9.4",

View File

@ -1,9 +1,14 @@
import { t } from '@lingui/core/macro';
import { RichTextEditor } from '@mantine/tiptap';
import '@mantine/tiptap/styles.css';
import { useHotkeys } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { useQuery } from '@tanstack/react-query';
import Image from '@tiptap/extension-image';
import { useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import DOMPurify from 'dompurify';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
@ -11,12 +16,6 @@ import type { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import { useApi } from '../../contexts/ApiContext';
import '@blocknote/core/fonts/inter.css';
import { BlockNoteView } from '@blocknote/mantine';
import '@blocknote/mantine/style.css';
import * as BlockNoteLocales from '@blocknote/core/locales';
import { useCreateBlockNote } from '@blocknote/react';
import { identifierString } from '@lib/functions/Conversion';
import {
ActionIcon,
@ -24,6 +23,7 @@ import {
Badge,
Box,
Button,
FileButton,
Flex,
Group,
HoverCard,
@ -31,13 +31,13 @@ import {
Stack,
Tabs,
Text,
Tooltip,
useMantineColorScheme
Tooltip
} from '@mantine/core';
import {
IconCirclePlus,
IconDeviceFloppy,
IconInfoCircle,
IconPhoto,
IconReload,
IconStar
} from '@tabler/icons-react';
@ -97,8 +97,8 @@ function NoteInfoHover({ note }: { note: any }) {
export default function NotesEditor({
modelType,
modelId,
editable,
setDirtyCallback
editable: _editable,
setDirtyCallback: _setDirtyCallback
}: Readonly<{
modelType: ModelType;
modelId: number;
@ -107,21 +107,18 @@ export default function NotesEditor({
}>) {
const api = useApi();
const user = useUserState();
const [language] = useLocalState(useShallow((s) => [s.language]));
const { colorScheme } = useMantineColorScheme();
const [_language] = useLocalState(useShallow((s) => [s.language]));
const [searchParams, setSearchParams] = useSearchParams();
const [isDirty, setIsDirty] = useState(false);
// The ID of the selected note
const [selectedNoteId, setSelectedNoteId] = useState<number | undefined>(
undefined
);
// Callback to upload an image file against the currently selected note
// Returns the URL of the uploaded image on success, or throws an error on failure
const uploadFile = useCallback(
(file: File) => {
async (file: File): Promise<string> => {
const formData = new FormData();
formData.append('note', selectedNoteId?.toString() ?? '');
formData.append('image', file);
@ -135,12 +132,61 @@ export default function NotesEditor({
[selectedNoteId]
);
const editor = useCreateBlockNote({
dictionary:
BlockNoteLocales[language as keyof typeof BlockNoteLocales] ||
BlockNoteLocales.en,
uploadFile: async (file: File) => {
return uploadFile(file);
// Ref so editorProps handlers always call the latest uploadFile without stale closure
const uploadFileRef = useRef(uploadFile);
useEffect(() => {
uploadFileRef.current = uploadFile;
}, [uploadFile]);
const editor = useEditor({
extensions: [
StarterKit.configure({
link: { openOnClick: false }
}),
Image
],
content: '',
onUpdate: () => setIsDirty(true),
editorProps: {
handleDrop: (view, event) => {
const files = event.dataTransfer?.files;
if (!files?.length) return false;
const imageFiles = Array.from(files).filter((f) =>
f.type.startsWith('image/')
);
if (!imageFiles.length) return false;
event.preventDefault();
const coords = view.posAtCoords({
left: event.clientX,
top: event.clientY
});
imageFiles.forEach((file) => {
uploadFileRef.current(file).then((url) => {
if (!url || !coords) return;
const node = view.state.schema.nodes.image?.create({ src: url });
if (node) view.dispatch(view.state.tr.insert(coords.pos, node));
});
});
return true;
},
handlePaste: (view, event) => {
const files = event.clipboardData?.files;
if (!files?.length) return false;
const imageFiles = Array.from(files).filter((f) =>
f.type.startsWith('image/')
);
if (!imageFiles.length) return false;
imageFiles.forEach((file) => {
uploadFileRef.current(file).then((url) => {
if (!url) return;
const node = view.state.schema.nodes.image?.create({ src: url });
if (node) view.dispatch(view.state.tr.replaceSelectionWith(node));
});
});
return true;
}
}
});
@ -163,26 +209,19 @@ export default function NotesEditor({
enabled: !!modelId && !!modelType
});
useEffect(() => {
return editor.onChange(() => setIsDirty(true));
}, [editor]);
const [selectedNote, setSelectedNote] = useState<any>(undefined);
const loadNote = useCallback(
(noteId: number) => {
const note = notesQuery.data?.find((note: any) => note.pk === noteId);
setSelectedNote(note);
if (note) {
const blocks = editor.tryParseHTMLToBlocks(note.content ?? '');
if (blocks) {
editor.replaceBlocks(editor.document, blocks);
} else {
editor.replaceBlocks(editor.document, []);
}
if (editor) {
// Pass emitUpdate:false to avoid triggering dirty state when loading content
editor.commands.setContent(
note ? DOMPurify.sanitize(note.content ?? '') : '',
{ emitUpdate: false }
);
}
setIsDirty(false);
@ -228,6 +267,11 @@ export default function NotesEditor({
[user, modelType, notesQuery]
);
// Sync editor editable state when permissions change
useEffect(() => {
editor?.setEditable(canEdit);
}, [editor, canEdit]);
const hasNotes = useMemo(() => {
return notesQuery.data && notesQuery.data.length > 0;
}, [notesQuery.data]);
@ -242,7 +286,6 @@ export default function NotesEditor({
successMessage: null,
onFormSuccess: (response: any) => {
notesQuery.refetch().then(() => {
// Select the newly created note
setSelectedNoteId(response.pk);
});
}
@ -265,7 +308,6 @@ export default function NotesEditor({
pk: selectedNoteId,
onFormSuccess: (response: any) => {
notesQuery.refetch().then(() => {
// Select the updated note
setSelectedNoteId(response.pk);
});
}
@ -280,46 +322,58 @@ export default function NotesEditor({
return;
}
const blocks = editor.document;
const html = editor.blocksToHTMLLossy(blocks);
const cleanHtml = DOMPurify.sanitize(html);
const cleanHtml = DOMPurify.sanitize(editor.getHTML());
// Sanitize the HTML content before sending to the server (or ensure it's sanitized on the back-end)
const url = apiUrl(ApiEndpoints.note_list, selectedNoteId);
if (selectedNoteId) {
const url = apiUrl(ApiEndpoints.note_list, selectedNoteId);
notifications.hide('note-update-status');
notifications.hide('note-update-status');
api
.patch(url, { content: cleanHtml })
.then(() => {
setIsDirty(false);
notifications.show({
title: t`Success`,
message: t`Note updated`,
color: 'green',
id: 'note-update-status',
autoClose: 2000
});
})
.catch((error) => {
notifications.show({
title: t`Error`,
message: t`Failed to update note: ${error.message}`,
color: 'red',
id: 'note-update-status',
autoClose: 2000
});
})
.finally(() => {
notesQuery.refetch();
api
.patch(url, { content: cleanHtml })
.then(() => {
setIsDirty(false);
notifications.show({
title: t`Success`,
message: t`Note updated`,
color: 'green',
id: 'note-update-status',
autoClose: 2000
});
}
})
.catch((error) => {
notifications.show({
title: t`Error`,
message: t`Failed to update note: ${error.message}`,
color: 'red',
id: 'note-update-status',
autoClose: 2000
});
})
.finally(() => {
notesQuery.refetch();
});
}, [selectedNoteId, editor, setIsDirty]);
useHotkeys([['mod+s', saveNote]]);
const handleImageUpload = useCallback(
async (file: File | null) => {
if (!file || !editor) return;
try {
const url = await uploadFile(file);
editor.chain().focus().setImage({ src: url }).run();
} catch {
notifications.show({
title: t`Error`,
message: t`Failed to upload image`,
color: 'red',
autoClose: 2000
});
}
},
[editor, uploadFile]
);
return (
<>
{createNote.modal}
@ -392,14 +446,60 @@ export default function NotesEditor({
)}
<Paper p='xs' shadow='sm' withBorder>
{hasNotes ? (
<Stack gap='xs'>
<BlockNoteView
editor={editor}
editable={canEdit}
theme={colorScheme === 'dark' ? 'dark' : 'light'}
style={{ minHeight: '400px' }}
/>
</Stack>
<RichTextEditor editor={editor} style={{ minHeight: '400px' }}>
{canEdit && (
<RichTextEditor.Toolbar sticky>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Bold />
<RichTextEditor.Italic />
<RichTextEditor.Underline />
<RichTextEditor.Strikethrough />
<RichTextEditor.ClearFormatting />
<RichTextEditor.Code />
<RichTextEditor.CodeBlock />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.H1 />
<RichTextEditor.H2 />
<RichTextEditor.H3 />
<RichTextEditor.H4 />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Blockquote />
<RichTextEditor.Hr />
<RichTextEditor.BulletList />
<RichTextEditor.OrderedList />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Link />
<RichTextEditor.Unlink />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<RichTextEditor.Undo />
<RichTextEditor.Redo />
</RichTextEditor.ControlsGroup>
<RichTextEditor.ControlsGroup>
<FileButton
onChange={handleImageUpload}
accept='image/*'
>
{(props) => (
<Tooltip label={t`Upload Image`}>
<ActionIcon
variant='default'
size='sm'
{...props}
>
<IconPhoto size='0.9rem' />
</ActionIcon>
</Tooltip>
)}
</FileButton>
</RichTextEditor.ControlsGroup>
</RichTextEditor.Toolbar>
)}
<RichTextEditor.Content />
</RichTextEditor>
) : (
<Alert title={t`Notes`} icon={<IconInfoCircle />}>
{t`There are no notes yet for this item.`}

View File

@ -1318,6 +1318,11 @@
resolved "https://registry.yarnpkg.com/@mantine/store/-/store-9.2.1.tgz#27a3548c4cc1567baa2613490d7dcb9300b391ba"
integrity sha512-sBTHt9ilfSZAeXQlqFkm8nRm22RunhevxuOUtdSwS9HhuMuS8T27dRRgbdKH2oEFUbaccdQSy5bHbmGbEgVO8w==
"@mantine/tiptap@^9.2.1":
version "9.2.1"
resolved "https://registry.yarnpkg.com/@mantine/tiptap/-/tiptap-9.2.1.tgz#5bd0cbec540452571e1e8e86960fd0e069c634c4"
integrity sha512-UzztgwqIknJheF39cqG2AgPI1qEvXIa7jNFuij8iB6GLd0UMmCjKnW42Px0WAaHuNfMjweml9IyTLBTSvIK0uA==
"@mantine/utils@^6.0.22":
version "6.0.22"
resolved "https://registry.yarnpkg.com/@mantine/utils/-/utils-6.0.22.tgz#7eace697084e2bc5a831eb0fd7cbbc04cc1b0354"
@ -1944,11 +1949,26 @@
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.23.4.tgz#f0d6427375d41e69127664d50bd48c91909b63d9"
integrity sha512-ni2LWE52bVeSt3L2HVBSmbBw+elc32ATej9C68EyKzN/8vR5ILxFn6RCdDTKm4asmwZyq2jys12dKmBdWMr9QA==
"@tiptap/core@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-3.23.6.tgz#3925af02f6119f2610bb5796487bdcc6ec7e363e"
integrity sha512-MRB3pHz4Oxqmcawh0cQ5iOGdY5xtNYp/1CoK7hdTLzw5K0C6/gTC2VvanB1R4INaB6EpBkxG/GiWkVirDRnuXw==
"@tiptap/extension-blockquote@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-3.23.6.tgz#e15ecc13abd00d9f2b525972c276d9200fd3ac08"
integrity sha512-2RmnqNqTltZ2k1F7IfjoDNs935Uq4rRDR7d98mqkg3OlDktcQIyBpv0t9dTay6H5bkQeZUuS8ogK2S1E8Edjug==
"@tiptap/extension-bold@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.23.4.tgz#c39a61a2afb78fcad5302902510fc823844fd668"
integrity sha512-3L9tnZ12i+98u5df2nV2zGu/sc3rhI87E3ocn1YYAO8PJUAgZnMwdet8JawCrS1uut5sRKlxo3SXEmdNfRVm/w==
"@tiptap/extension-bold@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-3.23.6.tgz#a08f0bdac029caab4051d369e5c27966d2efe990"
integrity sha512-1LMhjnytdbbhWHSoOwnLxZAOQZWPkKyXVCNmaIk0Mhi4tLPUXptG4qKS5sVYTCveE5H6IBPFrbgBFi5dMI6krA==
"@tiptap/extension-bubble-menu@^3.23.4":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.23.4.tgz#9e2d5d892d6d4917e44c5ebfe87de68e44878ead"
@ -1956,51 +1976,170 @@
dependencies:
"@floating-ui/dom" "^1.0.0"
"@tiptap/extension-bubble-menu@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.23.6.tgz#c31f8dcaa821b9ac496b2b5e364ca5a9754b4e7b"
integrity sha512-Mwkyp9LkDHFbqmWRIkp63FinRxFu3ajC4qSb9t4mnHsb4kAdbNLLsGtbFg+le0SWk4CxGwAOwM7SzeJ+6UGqCA==
dependencies:
"@floating-ui/dom" "^1.0.0"
"@tiptap/extension-bullet-list@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.23.6.tgz#a91fcac15ea5a9605c34be61d40969d3af5b20f8"
integrity sha512-RMRgfXZykr/13X8UBOwvpgysVOo9KchwqMoEbvqQSj4YFfU56iIn59C8sbxiQ1sKfeltUf0wH4fPc0I4iwKqAA==
"@tiptap/extension-code-block@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-3.23.6.tgz#ebb5d57ebe819bd094926a6ba20008af3ae0b4b6"
integrity sha512-4kccgcn5yHThxrzsIhJny3EwfEZYIk+BjUCL4uIuzOyWvExtGhZ6JMHVCZeMhI8D1/bX1LNkkAKN5DXPzH4lXQ==
"@tiptap/extension-code@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-3.23.4.tgz#8afbc0a1dc132d1d05890cc652fc897a8f94d9e0"
integrity sha512-C0TeRipMycUEBnV+Mzx6eLp/yZb6Vi/waP3Tkb0lO5/ikg7LWLB7AlmMunjIXEUcR/pJHID/aEh5PfJFpysUDg==
"@tiptap/extension-code@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-3.23.6.tgz#1f7c8e9520c092c318d2842892afa7a1b56bf8cd"
integrity sha512-KG8KXFYyLrtYvT7AZ1WGV61ofx8pDe5g9pH658MERxqQGii+Pyfc6xkz04l7XeBts/7+571UQp/0O7i/z560TA==
"@tiptap/extension-document@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-3.23.6.tgz#a3b3d20edb0670cf1230d64ebb340541fd89b46e"
integrity sha512-XDAIgG9KcKumFM9KJWUEUhXPbFIhhl47bfy5GknareWTRKke85rcoj/oxKKO9ihLZr8JfpbXjqnS4SCm5yhYPw==
"@tiptap/extension-dropcursor@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.23.6.tgz#2b2ea76ab8bc4b14376f0f9cc4080ff4d2a7926a"
integrity sha512-+XWEoRKf3lXxi7Le1aOM2xU1XHwxICGpXjT3m4QaYqUgIpsq8gQEuso6kVg8DnTD7biKQs6+oIQ0o2b/gTW9WA==
"@tiptap/extension-floating-menu@^3.23.4":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.23.4.tgz#ae6dfc00182811decc43402106c29d704179b29b"
integrity sha512-eAc72bKM26yIPx0jsU8qdjE71vFNVu5R9jGbdItBMFc0SPLS4qY8g+8RJ+iWoLwbcSEpgooLS9D9sLfdAU+Tvw==
"@tiptap/extension-floating-menu@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.23.6.tgz#34a714fc8d58e624916d4bf335ecccab64dd018f"
integrity sha512-2kjuDcEq69lEcECl75xqY5MyzUSh2zcC5aLrpwP1WwhJz5bxsIFHiaps5AP6h9R4A+ZBj5b2haay2Y1wDUU3VA==
"@tiptap/extension-gapcursor@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.23.6.tgz#f382b00f788756c0a519e4b1eb0a9c7b3fa5a35a"
integrity sha512-wbKmxXsszxWacEkrHucRpSQbiKjz4fmOebD6OVyL9AcrmlbxNk8vcM3iyh/8cVeRy09XY+morM165t/u7/z4IQ==
"@tiptap/extension-hard-break@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-3.23.6.tgz#0aefb994338baaee76cc7877e15d27559c407129"
integrity sha512-KeUm+tkUfIVSX9QM9XOIhaay0Fn36sLKUo5NVYjN3uJaxFvaZXZmTlxdO85OTdgF2P5sqh9LomrIgliaFRGk4w==
"@tiptap/extension-heading@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-3.23.6.tgz#76c103cfa1ee6645676a8597a282eaadfa03dfe4"
integrity sha512-A/0jPhxnUh9THSZymlu0OGPZe1wdFdwHAXnRCmqvYUCwJjrG7LCC/ahzmcj1tcNzI9hgHyuYPSfev8RXYrNu/w==
"@tiptap/extension-horizontal-rule@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.23.4.tgz#c9a4e9bd2c881f04a0eae037c3f0b1b696fa76e6"
integrity sha512-EA4kK8ywZ4dQNOdxeZbplmDDs5T5LjMgHpqxRwukj9wwKiILOK5E3fcKm1fCKh9Q02w96jax6YVccHwmgJP3sQ==
"@tiptap/extension-horizontal-rule@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.23.6.tgz#1997dd36ddea754bfcb3d0bf271a78438099499d"
integrity sha512-hEUlz4H+I64r+TH6LCuNCRgO7JTHncXGmx9+WbU69EOfY8O0ZurcgeJc8HeiAKL+r9YuC1e5YHfFxgCaaC0jlg==
"@tiptap/extension-image@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-3.23.6.tgz#8f7e46c523b7e5b67ebd20b93389ea95cc58f9b5"
integrity sha512-vvNGxArvD2dW+XvV0KdYovRVUzCy8QVNulc2r5pV7umnG1E6cCmMkiHiif8J2ePJu2KtysAvJQe0iF+UqueGMw==
"@tiptap/extension-italic@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.23.4.tgz#70ff0badf85503bf5d5f887fdbf5c03d5802a8d0"
integrity sha512-jUAHi+HZlg47BzgVIy6y/UH5vev7vPQ95jddhB5K3hC122kvWFMXlken7UOnqzbxNcHs2+4Oi/ZJirYMpT4P5w==
"@tiptap/extension-italic@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-3.23.6.tgz#03edff818014bdcae3cf7cc7b351192842f27498"
integrity sha512-wol5KdwCPAvpiYhH9PLlvO8ZnJHwZtIboVevrfOGgBcKlXRA3dedR4OAMXHnUtkkzu9KtliLg1+TYzEx4JZG9Q==
"@tiptap/extension-link@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-3.23.6.tgz#709d1e63abdbf1c81b142d8131f9a1c811dcbf25"
integrity sha512-KNZz7z7P2/qbQsx5bPAbSPjrKDg1VHsedGlLHJCr8U2VRD5VgmDLkMpkouP1CsDg15qgyUKv/nDib5KgPpLNWA==
dependencies:
linkifyjs "^4.3.3"
"@tiptap/extension-list-item@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-3.23.6.tgz#01a573f5c395d99c5b63cd58d2d84c095bb6a2df"
integrity sha512-3zzyhdkUWcHVpXuvy6KiIwjh29rbH6gEDEqPQqHLrl1XGnO9pnShC7pSHctlCDjmcx3O4n9cd4QMtVBlUerbiA==
"@tiptap/extension-list-keymap@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.23.6.tgz#2bbb2427361c0fe191898bab83edd6660442726b"
integrity sha512-x8bPcLViGzg/RAmQM/XtmfqIwQ/Pv9Q8mkd+OgfUiTqjeJqKwVQmiqbLFNa7zw81+H61M+HDU+qGAaQ3vRIMjw==
"@tiptap/extension-list@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-list/-/extension-list-3.23.6.tgz#65f2573389baed413c8df3bbb5a037651d34c634"
integrity sha512-z6vj9+Qht2sjdQkyyHcUpsC/yCIZqTrQiyHDhs/HGKrfvoANyAZGpqdNeKf1wSyjIso+27tQuIH5NDfk8ygyNw==
"@tiptap/extension-ordered-list@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.23.6.tgz#fb38de6da6262c90d3098640eef1bbb32a5bbdbe"
integrity sha512-1m/wWB/ZtXcmG2vNdiUkCqsOgqv5vBjCv/mVaHhF9OvV+zQS8YDjoWE7zEuT/GgELdT77Xq8lHrn4nCDudB3/A==
"@tiptap/extension-paragraph@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.23.4.tgz#f27e6f66e663c9e5f3a660921e04a303b465030d"
integrity sha512-KbhXjCFzWphvFn5VU7E4dtmYDm+bssI1i0+CnXPWCXkjdaaX88ck68Xp1fKz8/bbI/CqlgiNDO/3TvqgtZ6woQ==
"@tiptap/extension-paragraph@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-3.23.6.tgz#4a6b3b945e3b0afdf5d8126a026b56aa7a72d3e2"
integrity sha512-+7m58LUSncodjrIyXks4RZ3tLNYrvgT77wRR4l3HnM5OABY3GDsDTqi7c1t1yI29NVOSk/DUacqy6UwYAj1DGg==
"@tiptap/extension-strike@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.4.tgz#9db6b0982e3f550e90e729e03e898cef23b711a3"
integrity sha512-Vnq5vW801zPbu1LtKeA5k4R241jY+hRjXeijYwIPxy15KzIiipY12518HiCf6/8kkRbMxgOfdYg9X4BRV3HV3g==
"@tiptap/extension-strike@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-3.23.6.tgz#b68e8df11c8c24c82d8c292ff94bc962f3cec871"
integrity sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==
"@tiptap/extension-text@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.4.tgz#1ab44d78d34c746f97100ff34cc28e0914231eaa"
integrity sha512-q9kxver/MR18p66aWZHSPycnr9hcBFyVGeGj8gf+BQCzn5hpvtSYTfLvk1nq8GFhygdQ9/e3f7B5ovrm/jnpvw==
"@tiptap/extension-text@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-3.23.6.tgz#e6154568e0869c6fcd81c4df84dc41134311b483"
integrity sha512-ipoC2TkIAIOTiF5ByiGgvQB1DqDyfP90wrUB3mohBcgvp7lQnwHszCDGv8dNnmcUek8uXV/uoLu2VXeVQlxjPA==
"@tiptap/extension-underline@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.23.4.tgz#f85d5b047d9f9f167c59099cb8244a1bca360d79"
integrity sha512-F1ocPT10LV+seky25R1TMCRdc/Iof99jLcDSYDGr6mNEDY4ct2RvOeSM8aDdYq6CkH+vXt3i3JDeRwV23KzswQ==
"@tiptap/extension-underline@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-3.23.6.tgz#2d88333cbdb8cf1154377d6014dba8ce768bb715"
integrity sha512-P55wGIZGYTVH92Fq0cgI4/O9AhLCaJC3hhxg15RSERP5/YegM9eJHDK/GQ1EE/DvYA+xpYGOV6agKwAUqfA/Iw==
"@tiptap/extensions@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.23.4.tgz#f57253d162cecbdf3ae835dfcc1422af926ec6ac"
integrity sha512-SlGPXauW8iKWG7wwuwC/0y/smLImp0h6GBIGgNnTBgIP/ThXQnjLMSZH0mW/REO87dQxkku01V3ARRywi+juhg==
"@tiptap/extensions@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/extensions/-/extensions-3.23.6.tgz#96fde5cae89459581c6d5356728444bd0299a8f2"
integrity sha512-X09/Db1teB+ifXzDGVVFmOeQRx7wTAayE9/280spxpsHkHZvJ5bHRvWIzUzviMIjbBz+NPDIKYPK7gMfh9iaig==
"@tiptap/pm@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.23.4.tgz#91eca287eb5a4e29bc155a702d10bcf9b56a117e"
@ -2019,6 +2158,24 @@
prosemirror-transform "^1.10.2"
prosemirror-view "^1.38.1"
"@tiptap/pm@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-3.23.6.tgz#714c7b38e16816591b0adc9e9a2c72161de40daf"
integrity sha512-in5CaMaWlJcH2A1q6GJKFtrodE8WLS3M9tIi/f89jPmIVHJShpodC0KZDNyJkrVBQomYk0DEh86Utm6ASXzQww==
dependencies:
prosemirror-changeset "^2.3.0"
prosemirror-commands "^1.6.2"
prosemirror-dropcursor "^1.8.1"
prosemirror-gapcursor "^1.3.2"
prosemirror-history "^1.4.1"
prosemirror-keymap "^1.2.2"
prosemirror-model "^1.24.1"
prosemirror-schema-list "^1.5.0"
prosemirror-state "^1.4.3"
prosemirror-tables "^1.6.4"
prosemirror-transform "^1.10.2"
prosemirror-view "^1.38.1"
"@tiptap/react@^3.13.0":
version "3.23.4"
resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-3.23.4.tgz#df7cf9d8a2d42a3b3eb9bc73e5569fb7ddf8fe3d"
@ -2031,6 +2188,48 @@
"@tiptap/extension-bubble-menu" "^3.23.4"
"@tiptap/extension-floating-menu" "^3.23.4"
"@tiptap/react@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-3.23.6.tgz#c62ef43af585f557c08cca4b2efd87121be5a986"
integrity sha512-Tw9KZkYqFMk3vaJAEQKqEYIO/iq3cSJe7OUEGBul4k4GaMQeLItLf5EYhUd0GIPXci1WVVPNntKJsHfX25M37w==
dependencies:
"@types/use-sync-external-store" "^0.0.6"
fast-equals "^5.3.3"
use-sync-external-store "^1.4.0"
optionalDependencies:
"@tiptap/extension-bubble-menu" "^3.23.6"
"@tiptap/extension-floating-menu" "^3.23.6"
"@tiptap/starter-kit@^3.23.6":
version "3.23.6"
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-3.23.6.tgz#0fa0c2d18424ef093a4345657c44b99299af3df6"
integrity sha512-gykwtGWrnWCmtql1hid3opac/KV8zQvOAnu3bTqIqcHrn1FusbUwKmNzavSbfGvcktHM3hFjb35W48JyVLyu/A==
dependencies:
"@tiptap/core" "^3.23.6"
"@tiptap/extension-blockquote" "^3.23.6"
"@tiptap/extension-bold" "^3.23.6"
"@tiptap/extension-bullet-list" "^3.23.6"
"@tiptap/extension-code" "^3.23.6"
"@tiptap/extension-code-block" "^3.23.6"
"@tiptap/extension-document" "^3.23.6"
"@tiptap/extension-dropcursor" "^3.23.6"
"@tiptap/extension-gapcursor" "^3.23.6"
"@tiptap/extension-hard-break" "^3.23.6"
"@tiptap/extension-heading" "^3.23.6"
"@tiptap/extension-horizontal-rule" "^3.23.6"
"@tiptap/extension-italic" "^3.23.6"
"@tiptap/extension-link" "^3.23.6"
"@tiptap/extension-list" "^3.23.6"
"@tiptap/extension-list-item" "^3.23.6"
"@tiptap/extension-list-keymap" "^3.23.6"
"@tiptap/extension-ordered-list" "^3.23.6"
"@tiptap/extension-paragraph" "^3.23.6"
"@tiptap/extension-strike" "^3.23.6"
"@tiptap/extension-text" "^3.23.6"
"@tiptap/extension-underline" "^3.23.6"
"@tiptap/extensions" "^3.23.6"
"@tiptap/pm" "^3.23.6"
"@types/argparse@1.0.38":
version "1.0.38"
resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
@ -3901,6 +4100,11 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
linkifyjs@^4.3.3:
version "4.3.3"
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.3.3.tgz#da08f0eeb4d89a24541d09591fbdcc211eb8fef0"
integrity sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==
local-pkg@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.2.tgz#c03d208787126445303f8161619dc701afa4abb5"