diff --git a/apps/live/package.json b/apps/live/package.json index 5373049f5..6dd9a92f4 100644 --- a/apps/live/package.json +++ b/apps/live/package.json @@ -29,8 +29,8 @@ "@plane/editor": "workspace:*", "@plane/logger": "workspace:*", "@plane/types": "workspace:*", - "@tiptap/core": "^2.22.3", - "@tiptap/html": "^2.22.3", + "@tiptap/core": "catalog:", + "@tiptap/html": "catalog:", "axios": "catalog:", "compression": "1.8.1", "cors": "^2.8.5", @@ -43,7 +43,8 @@ "pino-http": "^10.3.0", "pino-pretty": "^11.2.2", "uuid": "catalog:", - "y-prosemirror": "^1.2.15", + "ws": "^8.18.3", + "y-prosemirror": "^1.3.7", "y-protocols": "^1.0.6", "yjs": "^13.6.20", "zod": "^3.25.76" @@ -59,11 +60,7 @@ "@types/pino-http": "^5.8.4", "@types/uuid": "^9.0.1", "@types/ws": "^8.18.1", - "concurrently": "^9.0.1", - "nodemon": "^3.1.7", - "ts-node": "^10.9.2", "tsdown": "catalog:", - "typescript": "catalog:", - "ws": "^8.18.3" + "typescript": "catalog:" } } diff --git a/apps/web/ce/hooks/use-editor-flagging.ts b/apps/web/ce/hooks/use-editor-flagging.ts index 0fc8a6eb4..f8ced8363 100644 --- a/apps/web/ce/hooks/use-editor-flagging.ts +++ b/apps/web/ce/hooks/use-editor-flagging.ts @@ -25,7 +25,7 @@ export type TEditorFlaggingHookProps = { /** * @description extensions disabled in various editors */ -export const useEditorFlagging = (props: TEditorFlaggingHookProps): TEditorFlaggingHookReturnType => ({ +export const useEditorFlagging = (_props: TEditorFlaggingHookProps): TEditorFlaggingHookReturnType => ({ document: { disabled: ["ai", "collaboration-cursor"], flagged: [], diff --git a/packages/editor/package.json b/packages/editor/package.json index c83c8eec5..e7567711d 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -23,7 +23,7 @@ "./styles": "./dist/styles/index.css" }, "scripts": { - "build": "tsdown", + "build": "tsc && tsdown", "dev": "tsdown --watch", "check:lint": "eslint . --max-warnings 30", "check:types": "tsc --noEmit", @@ -46,25 +46,23 @@ "@plane/types": "workspace:*", "@plane/ui": "workspace:*", "@plane/utils": "workspace:*", - "@tiptap/core": "^2.22.3", - "@tiptap/extension-blockquote": "^2.22.3", - "@tiptap/extension-character-count": "^2.22.3", - "@tiptap/extension-collaboration": "^2.22.3", - "@tiptap/extension-emoji": "^2.22.3", - "@tiptap/extension-image": "^2.22.3", - "@tiptap/extension-list-item": "^2.22.3", - "@tiptap/extension-mention": "^2.22.3", - "@tiptap/extension-placeholder": "^2.22.3", - "@tiptap/extension-task-item": "^2.22.3", - "@tiptap/extension-task-list": "^2.22.3", - "@tiptap/extension-text-align": "^2.22.3", - "@tiptap/extension-text-style": "^2.22.3", - "@tiptap/extension-underline": "^2.22.3", - "@tiptap/html": "^2.22.3", - "@tiptap/pm": "^2.22.3", - "@tiptap/react": "^2.22.3", - "@tiptap/starter-kit": "^2.22.3", - "@tiptap/suggestion": "^2.22.3", + "@tiptap/core": "catalog:", + "@tiptap/extension-blockquote": "^3.5.3", + "@tiptap/extension-collaboration": "^3.5.3", + "@tiptap/extension-emoji": "^3.5.3", + "@tiptap/extension-image": "^3.5.3", + "@tiptap/extension-list-item": "^3.5.3", + "@tiptap/extension-mention": "^3.5.3", + "@tiptap/extension-task-item": "^3.5.3", + "@tiptap/extension-task-list": "^3.5.3", + "@tiptap/extension-text-align": "^3.5.3", + "@tiptap/extension-text-style": "^3.5.3", + "@tiptap/extensions": "^3.5.3", + "@tiptap/html": "catalog:", + "@tiptap/pm": "^3.5.3", + "@tiptap/react": "^3.5.3", + "@tiptap/starter-kit": "^3.5.3", + "@tiptap/suggestion": "^3.5.3", "emoji-regex": "^10.3.0", "highlight.js": "^11.8.0", "is-emoji-supported": "^0.0.5", @@ -74,7 +72,7 @@ "lucide-react": "catalog:", "prosemirror-codemark": "^0.4.2", "tippy.js": "^6.3.7", - "tiptap-markdown": "^0.8.10", + "tiptap-markdown": "^0.9.0", "uuid": "catalog:", "y-indexeddb": "^9.0.12", "y-prosemirror": "^1.2.15", @@ -88,6 +86,7 @@ "@types/node": "18.15.3", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@types/uuid": "^8.3.4", "postcss": "^8.4.38", "tsdown": "catalog:", "typescript": "catalog:" diff --git a/packages/editor/src/ce/constants/utility.ts b/packages/editor/src/ce/constants/utility.ts index 616838a62..eedffda97 100644 --- a/packages/editor/src/ce/constants/utility.ts +++ b/packages/editor/src/ce/constants/utility.ts @@ -1,14 +1,22 @@ -import { ExtensionFileSetStorageKey } from "@/plane-editor/types/storage"; +// plane imports +import { ADDITIONAL_EXTENSIONS, CORE_EXTENSIONS } from "@plane/utils"; +// plane editor imports +import type { ExtensionFileSetStorageKey } from "@/plane-editor/types/storage"; -export const NODE_FILE_MAP: { - [key: string]: { - fileSetName: ExtensionFileSetStorageKey; - }; -} = { - image: { +export type NodeFileMapType = Partial< + Record< + CORE_EXTENSIONS | ADDITIONAL_EXTENSIONS, + { + fileSetName: ExtensionFileSetStorageKey; + } + > +>; + +export const NODE_FILE_MAP: NodeFileMapType = { + [CORE_EXTENSIONS.IMAGE]: { fileSetName: "deletedImageSet", }, - imageComponent: { + [CORE_EXTENSIONS.CUSTOM_IMAGE]: { fileSetName: "deletedImageSet", }, }; diff --git a/packages/editor/src/ce/types/storage.ts b/packages/editor/src/ce/types/storage.ts index 666c13534..56a49da8c 100644 --- a/packages/editor/src/ce/types/storage.ts +++ b/packages/editor/src/ce/types/storage.ts @@ -1,22 +1,4 @@ -import { CharacterCountStorage } from "@tiptap/extension-character-count"; -// constants -import type { EmojiStorage } from "@tiptap/extension-emoji"; -import { CORE_EXTENSIONS } from "@/constants/extension"; // extensions -import type { HeadingExtensionStorage } from "@/extensions"; -import type { CustomImageExtensionStorage } from "@/extensions/custom-image/types"; -import type { CustomLinkStorage } from "@/extensions/custom-link"; import type { ImageExtensionStorage } from "@/extensions/image"; -import type { UtilityExtensionStorage } from "@/extensions/utility"; - -export type ExtensionStorageMap = { - [CORE_EXTENSIONS.CUSTOM_IMAGE]: CustomImageExtensionStorage; - [CORE_EXTENSIONS.IMAGE]: ImageExtensionStorage; - [CORE_EXTENSIONS.CUSTOM_LINK]: CustomLinkStorage; - [CORE_EXTENSIONS.HEADINGS_LIST]: HeadingExtensionStorage; - [CORE_EXTENSIONS.UTILITY]: UtilityExtensionStorage; - [CORE_EXTENSIONS.EMOJI]: EmojiStorage; - [CORE_EXTENSIONS.CHARACTER_COUNT]: CharacterCountStorage; -}; export type ExtensionFileSetStorageKey = Extract; diff --git a/packages/editor/src/core/components/editors/link-view-container.tsx b/packages/editor/src/core/components/editors/link-view-container.tsx index 5e839830e..3f7cc7f2a 100644 --- a/packages/editor/src/core/components/editors/link-view-container.tsx +++ b/packages/editor/src/core/components/editors/link-view-container.tsx @@ -4,9 +4,6 @@ import { FC, useCallback, useEffect, useRef, useState } from "react"; // components import { LinkView, LinkViewProps } from "@/components/links"; -import { CORE_EXTENSIONS } from "@/constants/extension"; -// components -import { getExtensionStorage } from "@/helpers/get-extension-storage"; type Props = { editor: Editor; @@ -22,7 +19,7 @@ export const LinkViewContainer: FC = ({ editor, containerRef }) => { const editorState = useEditorState({ editor, selector: ({ editor }: { editor: Editor }) => ({ - linkExtensionStorage: getExtensionStorage(editor, CORE_EXTENSIONS.CUSTOM_LINK), + linkExtensionStorage: editor.storage.link, }), }); diff --git a/packages/editor/src/core/components/menus/ai-menu.tsx b/packages/editor/src/core/components/menus/ai-menu.tsx index 968c7d469..e268aed05 100644 --- a/packages/editor/src/core/components/menus/ai-menu.tsx +++ b/packages/editor/src/core/components/menus/ai-menu.tsx @@ -1,9 +1,9 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import tippy, { Instance } from "tippy.js"; +import tippy, { type Instance } from "tippy.js"; // plane utils import { cn } from "@plane/utils"; // types -import { TAIHandler } from "@/types"; +import type { TAIHandler } from "@/types"; type Props = { menu: TAIHandler["menu"]; diff --git a/packages/editor/src/core/components/menus/block-menu.tsx b/packages/editor/src/core/components/menus/block-menu.tsx index 18a4b8273..63bf288ac 100644 --- a/packages/editor/src/core/components/menus/block-menu.tsx +++ b/packages/editor/src/core/components/menus/block-menu.tsx @@ -1,9 +1,9 @@ import { useFloating, + autoUpdate, offset, flip, shift, - autoUpdate, useDismiss, useInteractions, FloatingPortal, @@ -11,15 +11,16 @@ import { import type { Editor } from "@tiptap/react"; import { Copy, LucideIcon, Trash2 } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; -// constants import { cn } from "@plane/utils"; +// constants import { CORE_EXTENSIONS } from "@/constants/extension"; -import { IEditorProps } from "@/types"; +// types +import type { IEditorProps } from "@/types"; type Props = { + disabledExtensions?: IEditorProps["disabledExtensions"]; editor: Editor; flaggedExtensions?: IEditorProps["flaggedExtensions"]; - disabledExtensions?: IEditorProps["disabledExtensions"]; }; export const BlockMenu = (props: Props) => { @@ -74,15 +75,6 @@ export const BlockMenu = (props: Props) => { // Set the virtual reference as the reference element refs.setReference(virtualReferenceRef.current); - // Ensure the targeted block is selected - const rect = dragHandle.getBoundingClientRect(); - const coords = { left: rect.left + rect.width / 2, top: rect.top + rect.height / 2 }; - const posAtCoords = editor.view.posAtCoords(coords); - if (posAtCoords) { - const $pos = editor.state.doc.resolve(posAtCoords.pos); - const nodePos = $pos.before($pos.depth); - editor.chain().setNodeSelection(nodePos).run(); - } // Show the menu openBlockMenu(); return; @@ -93,9 +85,10 @@ export const BlockMenu = (props: Props) => { closeBlockMenu(); } }, - [editor, refs, openBlockMenu, closeBlockMenu] + [refs, openBlockMenu, closeBlockMenu] ); + // Set up event listeners useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { @@ -106,10 +99,11 @@ export const BlockMenu = (props: Props) => { const handleScroll = () => { closeBlockMenu(); }; + document.addEventListener("click", handleClickDragHandle); document.addEventListener("contextmenu", handleClickDragHandle); document.addEventListener("keydown", handleKeyDown); - document.addEventListener("scroll", handleScroll, true); // Using capture phase + document.addEventListener("scroll", handleScroll, true); return () => { document.removeEventListener("click", handleClickDragHandle); @@ -200,6 +194,7 @@ export const BlockMenu = (props: Props) => { if (!isOpen) { return null; } + return (
{ }} style={{ ...floatingStyles, - zIndex: 99, animationFillMode: "forwards", transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)", // Expo ease out }} @@ -218,13 +212,11 @@ export const BlockMenu = (props: Props) => { "transition-all duration-300 transform origin-top-right", isAnimatedIn ? "opacity-100 scale-100" : "opacity-0 scale-75" )} - data-prevent-outside-click {...getFloatingProps()} > {MENU_ITEMS.map((item) => { - if (item.isDisabled) { - return null; - } + if (item.isDisabled) return null; + return ( - {isOpen && ( -
-
-

Text colors

-
- {COLORS_LIST.map((color) => ( - -
+ className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity" + style={{ + backgroundColor: color.textColor, + }} + onClick={() => TextColorItem(editor).command({ color: color.key })} + /> + ))} +
-
-

Background colors

-
- {COLORS_LIST.map((color) => ( -
+
+

Background colors

+
+ {COLORS_LIST.map((color) => ( -
+ className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity" + style={{ + backgroundColor: color.backgroundColor, + }} + onClick={() => BackgroundColorItem(editor).command({ color: color.key })} + /> + ))} +
-
- )} -
+ + + ); }; diff --git a/packages/editor/src/core/components/menus/bubble-menu/index.ts b/packages/editor/src/core/components/menus/bubble-menu/index.ts index 526feed3d..f06aeab63 100644 --- a/packages/editor/src/core/components/menus/bubble-menu/index.ts +++ b/packages/editor/src/core/components/menus/bubble-menu/index.ts @@ -1,4 +1,3 @@ export * from "./color-selector"; -export * from "./link-selector"; export * from "./node-selector"; export * from "./root"; diff --git a/packages/editor/src/core/components/menus/bubble-menu/link-selector.tsx b/packages/editor/src/core/components/menus/bubble-menu/link-selector.tsx index 6f582f89c..a2e9c6bf2 100644 --- a/packages/editor/src/core/components/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/src/core/components/menus/bubble-menu/link-selector.tsx @@ -1,6 +1,6 @@ -import { Editor } from "@tiptap/core"; +import type { Editor } from "@tiptap/core"; import { Check, Link, Trash2 } from "lucide-react"; -import { Dispatch, FC, SetStateAction, useCallback, useRef, useState } from "react"; +import { FC, useCallback, useRef, useState } from "react"; // plane imports import { cn } from "@plane/utils"; // constants @@ -8,17 +8,20 @@ import { CORE_EXTENSIONS } from "@/constants/extension"; // helpers import { isValidHttpUrl } from "@/helpers/common"; import { setLinkEditor, unsetLinkEditor } from "@/helpers/editor-commands"; +import { FloatingMenuRoot } from "../floating-menu/root"; +import { useFloatingMenu } from "../floating-menu/use-floating-menu"; type Props = { editor: Editor; - isOpen: boolean; - setIsOpen: Dispatch>; }; export const BubbleMenuLinkSelector: FC = (props) => { - const { editor, isOpen, setIsOpen } = props; + const { editor } = props; // states const [error, setError] = useState(false); + // floating ui + const { options, getReferenceProps, getFloatingProps } = useFloatingMenu({}); + const { context } = options; // refs const inputRef = useRef(null); @@ -30,88 +33,89 @@ export const BubbleMenuLinkSelector: FC = (props) => { const { isValid, url: validatedUrl } = isValidHttpUrl(url); if (isValid) { setLinkEditor(editor, validatedUrl); - setIsOpen(false); + context.onOpenChange(false); setError(false); } else { setError(true); } - }, [editor, inputRef, setIsOpen]); + }, [editor, inputRef, context]); return ( -
- - {isOpen && ( -
-
- e.stopPropagation()} - className="flex-1 border-r border-custom-border-300 bg-custom-background-100 py-2 px-1.5 text-xs outline-none placeholder:text-custom-text-400 rounded" - defaultValue={editor.getAttributes("link").href || ""} - onKeyDown={(e) => { - setError(false); - if (e.key === "Enter") { - e.preventDefault(); - handleLinkSubmit(); - } + ), + }} + getFloatingProps={getFloatingProps} + getReferenceProps={getReferenceProps} + menuButton={ + <> + Link + + + } + options={options} + > +
+
+ e.stopPropagation()} + className="flex-1 border-r-[0.5px] border-custom-border-300 bg-custom-background-100 py-2 px-1.5 text-xs outline-none placeholder:text-custom-text-400 rounded" + defaultValue={editor.getAttributes("link").href || ""} + onKeyDown={(e) => { + setError(false); + if (e.key === "Enter") { + e.preventDefault(); + handleLinkSubmit(); + } + }} + onFocus={() => setError(false)} + autoFocus + /> + {editor.getAttributes("link").href ? ( + - ) : ( - - )} -
- {error && ( -

- Please enter a valid URL -

+ > + + + ) : ( + )}
- )} -
+ {error && ( +

+ Please enter a valid URL +

+ )} +
+ ); }; diff --git a/packages/editor/src/core/components/menus/bubble-menu/node-selector.tsx b/packages/editor/src/core/components/menus/bubble-menu/node-selector.tsx index 564f7d97c..a4c1dd8b1 100644 --- a/packages/editor/src/core/components/menus/bubble-menu/node-selector.tsx +++ b/packages/editor/src/core/components/menus/bubble-menu/node-selector.tsx @@ -1,6 +1,6 @@ import { Editor } from "@tiptap/react"; import { Check, ChevronDown } from "lucide-react"; -import { Dispatch, FC, SetStateAction } from "react"; +import { FC } from "react"; // plane utils import { cn } from "@plane/utils"; // components @@ -20,17 +20,20 @@ import { EditorMenuItem, } from "@/components/menus"; // types -import { TEditorCommands } from "@/types"; +import type { TEditorCommands } from "@/types"; +// local imports +import { FloatingMenuRoot } from "../floating-menu/root"; +import { useFloatingMenu } from "../floating-menu/use-floating-menu"; type Props = { editor: Editor; - isOpen: boolean; - setIsOpen: Dispatch>; }; export const BubbleMenuNodeSelector: FC = (props) => { - const { editor, isOpen, setIsOpen } = props; - + const { editor } = props; + // floating ui + const { options, getReferenceProps, getFloatingProps } = useFloatingMenu({}); + const { context } = options; const items: EditorMenuItem[] = [ TextItem(editor), HeadingOneItem(editor), @@ -44,52 +47,58 @@ export const BubbleMenuNodeSelector: FC = (props) => { TodoListItem(editor), QuoteItem(editor), CodeItem(editor), - ]; + ] as EditorMenuItem[]; const activeItem = items.filter((item) => item.isActive()).pop() ?? { name: "Multiple", }; return ( -
- - {isOpen && ( -
- {items.map((item) => ( - - ))} -
- )} -
+ + {activeItem?.name} + + + } + options={options} + getFloatingProps={getFloatingProps} + getReferenceProps={getReferenceProps} + > +
+ {items.map((item) => ( + + ))} +
+
); }; diff --git a/packages/editor/src/core/components/menus/bubble-menu/root.tsx b/packages/editor/src/core/components/menus/bubble-menu/root.tsx index 4f3fef2ac..588b43439 100644 --- a/packages/editor/src/core/components/menus/bubble-menu/root.tsx +++ b/packages/editor/src/core/components/menus/bubble-menu/root.tsx @@ -1,4 +1,6 @@ -import { BubbleMenu, BubbleMenuProps, Editor, isNodeSelection, useEditorState } from "@tiptap/react"; +import { type Editor, isNodeSelection } from "@tiptap/core"; +import { useEditorState } from "@tiptap/react"; +import { BubbleMenu, type BubbleMenuProps } from "@tiptap/react/menus"; import { FC, useEffect, useState, useRef } from "react"; // plane utils import { cn } from "@plane/utils"; @@ -7,7 +9,6 @@ import { BackgroundColorItem, BoldItem, BubbleMenuColorSelector, - BubbleMenuLinkSelector, BubbleMenuNodeSelector, CodeItem, EditorMenuItem, @@ -23,9 +24,10 @@ import { CORE_EXTENSIONS } from "@/constants/extension"; // extensions import { isCellSelection } from "@/extensions/table/table/utilities/helpers"; // types -import { TEditorCommands } from "@/types"; +import type { TEditorCommands } from "@/types"; // local imports import { TextAlignmentSelector } from "./alignment-selector"; +import { BubbleMenuLinkSelector } from "./link-selector"; type EditorBubbleMenuProps = Omit; @@ -38,7 +40,14 @@ export type EditorStateType = { left: boolean; right: boolean; center: boolean; - color: { key: string; label: string; textColor: string; backgroundColor: string } | undefined; + color: + | { + key: string; + label: string; + textColor: string; + backgroundColor: string; + } + | undefined; backgroundColor: | { key: string; @@ -49,27 +58,31 @@ export type EditorStateType = { | undefined; }; -export const EditorBubbleMenu: FC = (props: { editor: Editor }) => { - const menuRef = useRef(null); - const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false); - const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false); - const [isColorSelectorOpen, setIsColorSelectorOpen] = useState(false); +type Props = { + editor: Editor; +}; + +export const EditorBubbleMenu: FC = (props) => { + const { editor } = props; + // states const [isSelecting, setIsSelecting] = useState(false); + // refs + const menuRef = useRef(null); const formattingItems = { - code: CodeItem(props.editor), - bold: BoldItem(props.editor), - italic: ItalicItem(props.editor), - underline: UnderLineItem(props.editor), - strikethrough: StrikeThroughItem(props.editor), - "text-align": TextAlignItem(props.editor), + code: CodeItem(editor), + bold: BoldItem(editor), + italic: ItalicItem(editor), + underline: UnderLineItem(editor), + strikethrough: StrikeThroughItem(editor), + "text-align": TextAlignItem(editor), } satisfies { [K in TEditorCommands]?: EditorMenuItem; }; const editorState: EditorStateType = useEditorState({ - editor: props.editor, - selector: ({ editor }: { editor: Editor }) => ({ + editor, + selector: ({ editor }) => ({ code: formattingItems.code.isActive(), bold: formattingItems.bold.isActive(), italic: formattingItems.italic.isActive(), @@ -88,7 +101,7 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi : [formattingItems.bold, formattingItems.italic, formattingItems.underline, formattingItems.strikethrough]; const bubbleMenuProps: EditorBubbleMenuProps = { - ...props, + editor, shouldShow: ({ state, editor }) => { const { selection } = state; const { empty } = selection; @@ -106,20 +119,28 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi } return true; }, - tippyOptions: { - moveTransition: "transform 0.15s ease-out", - duration: [300, 0], - zIndex: 9, + options: { onShow: () => { - props.editor.storage.link.isBubbleMenuOpen = true; + if (editor.storage.link) { + editor.storage.link.isBubbleMenuOpen = true; + } + editor.commands.addActiveDropbarExtension("bubble-menu"); }, - onHidden: () => { - props.editor.storage.link.isBubbleMenuOpen = false; - setIsNodeSelectorOpen(false); - setIsLinkSelectorOpen(false); - setIsColorSelectorOpen(false); + onHide: () => { + if (editor.storage.link) { + editor.storage.link.isBubbleMenuOpen = false; + } + setTimeout(() => { + editor.commands.removeActiveDropbarExtension("bubble-menu"); + }, 0); }, }, + // TODO: Migrate these to floating UI options + // tippyOptions: { + // moveTransition: "transform 0.15s ease-out", + // duration: [300, 0], + // zIndex: 9, + // }, }; useEffect(() => { @@ -127,7 +148,7 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi if (menuRef.current?.contains(e.target as Node)) return; function handleMouseMove() { - if (!props.editor.state.selection.empty) { + if (!editor.state.selection.empty) { setIsSelecting(true); document.removeEventListener("mousemove", handleMouseMove); } @@ -148,7 +169,7 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi return () => { document.removeEventListener("mousedown", handleMouseDown); }; - }, [props.editor]); + }, [editor]); return ( @@ -158,41 +179,16 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi className="flex py-2 divide-x divide-custom-border-200 rounded-lg border border-custom-border-200 bg-custom-background-100 shadow-custom-shadow-rg overflow-x-scroll horizontal-scrollbar scrollbar-xs" >
- { - setIsNodeSelectorOpen((prev) => !prev); - setIsLinkSelectorOpen(false); - setIsColorSelectorOpen(false); - }} - /> +
{!editorState.code && (
- { - setIsLinkSelectorOpen((prev) => !prev); - setIsNodeSelectorOpen(false); - setIsColorSelectorOpen(false); - }} - /> +
)} {!editorState.code && (
- { - setIsColorSelectorOpen((prev) => !prev); - setIsNodeSelectorOpen(false); - setIsLinkSelectorOpen(false); - }} - /> +
)}
@@ -215,7 +211,7 @@ export const EditorBubbleMenu: FC = (props: { editor: Edi ))}
- +
)} diff --git a/packages/editor/src/core/components/menus/floating-menu/root.tsx b/packages/editor/src/core/components/menus/floating-menu/root.tsx new file mode 100644 index 000000000..a98ea3fea --- /dev/null +++ b/packages/editor/src/core/components/menus/floating-menu/root.tsx @@ -0,0 +1,65 @@ +import { + FloatingOverlay, + FloatingPortal, + type UseInteractionsReturn, + type UseFloatingReturn, +} from "@floating-ui/react"; + +type Props = { + children: React.ReactNode; + classNames?: { + buttonContainer?: string; + button?: string; + }; + getFloatingProps: UseInteractionsReturn["getFloatingProps"]; + getReferenceProps: UseInteractionsReturn["getReferenceProps"]; + menuButton: React.ReactNode; + onClick?: (e: React.MouseEvent) => void; + options: UseFloatingReturn; +}; + +export const FloatingMenuRoot: React.FC = (props) => { + const { children, classNames, getFloatingProps, getReferenceProps, menuButton, onClick, options } = props; + // derived values + const { refs, floatingStyles, context } = options; + + return ( + <> +
+ +
+ {context.open && ( + + {/* Backdrop */} + +
+ {children} +
+
+ )} + + ); +}; diff --git a/packages/editor/src/core/components/menus/floating-menu/use-floating-menu.ts b/packages/editor/src/core/components/menus/floating-menu/use-floating-menu.ts new file mode 100644 index 000000000..6c49f3b8c --- /dev/null +++ b/packages/editor/src/core/components/menus/floating-menu/use-floating-menu.ts @@ -0,0 +1,50 @@ +import { + shift, + flip, + useDismiss, + useFloating, + useInteractions, + autoUpdate, + useClick, + useRole, +} from "@floating-ui/react"; +import { useState } from "react"; + +type TArgs = { + handleOpenChange?: (open: boolean) => void; +}; + +export const useFloatingMenu = (args: TArgs) => { + const { handleOpenChange } = args; + // states + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + // floating ui + const options = useFloating({ + placement: "bottom-start", + middleware: [ + flip({ + fallbackPlacements: ["top-start", "bottom-start", "top-end", "bottom-end"], + }), + shift({ + padding: 8, + }), + ], + open: isDropdownOpen, + onOpenChange: (open) => { + setIsDropdownOpen(open); + handleOpenChange?.(open); + }, + whileElementsMounted: autoUpdate, + }); + const { context } = options; + const click = useClick(context); + const dismiss = useDismiss(context); + const role = useRole(context); + const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, click, role]); + + return { + options, + getReferenceProps, + getFloatingProps, + }; +}; diff --git a/packages/editor/src/core/components/menus/menu-items.ts b/packages/editor/src/core/components/menus/menu-items.ts index cfa1213c1..bba9f523f 100644 --- a/packages/editor/src/core/components/menus/menu-items.ts +++ b/packages/editor/src/core/components/menus/menu-items.ts @@ -1,4 +1,4 @@ -import { Editor } from "@tiptap/react"; +import type { Editor } from "@tiptap/react"; import { BoldIcon, Heading1, @@ -18,7 +18,7 @@ import { Heading5, Heading6, CaseSensitive, - LucideIcon, + type LucideIcon, MinusSquare, Palette, AlignCenter, @@ -70,7 +70,7 @@ export const TextItem = (editor: Editor): EditorMenuItem<"text"> => ({ icon: CaseSensitive, }); -type SupportedHeadingLevels = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; +type SupportedHeadingLevels = Extract; const HeadingItem = ( editor: Editor, @@ -274,5 +274,5 @@ export const getEditorMenuItems = (editor: Editor | null): EditorMenuItem[]; }; diff --git a/packages/editor/src/core/extensions/callout/block.tsx b/packages/editor/src/core/extensions/callout/block.tsx index 7f4a8503d..b4f0b7085 100644 --- a/packages/editor/src/core/extensions/callout/block.tsx +++ b/packages/editor/src/core/extensions/callout/block.tsx @@ -6,7 +6,7 @@ import { COLORS_LIST } from "@/constants/common"; import { CalloutBlockColorSelector } from "./color-selector"; import { CalloutBlockLogoSelector } from "./logo-selector"; // types -import { EAttributeNames, TCalloutBlockAttributes } from "./types"; +import { ECalloutAttributeNames, TCalloutBlockAttributes } from "./types"; // utils import { updateStoredBackgroundColor } from "./utils"; @@ -45,7 +45,7 @@ export const CustomCalloutBlock: React.FC = (props) toggleDropdown={() => setIsColorPickerOpen((prev) => !prev)} onSelect={(val) => { updateAttributes({ - [EAttributeNames.BACKGROUND]: val, + [ECalloutAttributeNames.BACKGROUND]: val, }); updateStoredBackgroundColor(val); }} diff --git a/packages/editor/src/core/extensions/callout/extension-config.ts b/packages/editor/src/core/extensions/callout/extension-config.ts index e52be72d6..2fac14316 100644 --- a/packages/editor/src/core/extensions/callout/extension-config.ts +++ b/packages/editor/src/core/extensions/callout/extension-config.ts @@ -1,14 +1,13 @@ import { Node, mergeAttributes } from "@tiptap/core"; import { MarkdownSerializerState } from "@tiptap/pm/markdown"; -import { Node as NodeType } from "@tiptap/pm/model"; +import type { Node as ProseMirrorNode } from "@tiptap/pm/model"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; // types -import { EAttributeNames, TCalloutBlockAttributes } from "./types"; +import { type CustomCalloutExtensionType, ECalloutAttributeNames, type TCalloutBlockAttributes } from "./types"; // utils import { DEFAULT_CALLOUT_BLOCK_ATTRIBUTES } from "./utils"; -// Extend Tiptap's Commands interface declare module "@tiptap/core" { interface Commands { [CORE_EXTENSIONS.CALLOUT]: { @@ -17,7 +16,7 @@ declare module "@tiptap/core" { } } -export const CustomCalloutExtensionConfig = Node.create({ +export const CustomCalloutExtensionConfig: CustomCalloutExtensionType = Node.create({ name: CORE_EXTENSIONS.CALLOUT, group: "block", content: "block+", @@ -25,20 +24,24 @@ export const CustomCalloutExtensionConfig = Node.create({ addAttributes() { const attributes = { // Reduce instead of map to accumulate the attributes directly into an object - ...Object.values(EAttributeNames).reduce((acc, value) => { - acc[value] = { - default: DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[value], - }; - return acc; - }, {}), + ...Object.values(ECalloutAttributeNames).reduce( + (acc, value) => { + acc[value] = { + default: DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[value], + }; + return acc; + }, + {} as Record + ), }; + return attributes; }, addStorage() { return { markdown: { - serialize(state: MarkdownSerializerState, node: NodeType) { + serialize(state: MarkdownSerializerState, node: ProseMirrorNode) { const attrs = node.attrs as TCalloutBlockAttributes; const logoInUse = attrs["data-logo-in-use"]; // add callout logo @@ -62,7 +65,7 @@ export const CustomCalloutExtensionConfig = Node.create({ parseHTML() { return [ { - tag: `div[${EAttributeNames.BLOCK_TYPE}="${DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[EAttributeNames.BLOCK_TYPE]}"]`, + tag: `div[${ECalloutAttributeNames.BLOCK_TYPE}="${DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.BLOCK_TYPE]}"]`, }, ]; }, diff --git a/packages/editor/src/core/extensions/callout/extension.tsx b/packages/editor/src/core/extensions/callout/extension.tsx index 9bc26df72..d6aaf2490 100644 --- a/packages/editor/src/core/extensions/callout/extension.tsx +++ b/packages/editor/src/core/extensions/callout/extension.tsx @@ -1,14 +1,18 @@ -import { findParentNodeClosestToPos, Predicate, ReactNodeViewRenderer } from "@tiptap/react"; -// extensions -import { CustomCalloutBlock, CustomCalloutNodeViewProps } from "@/extensions/callout/block"; +import { findParentNodeClosestToPos, type Predicate, ReactNodeViewRenderer } from "@tiptap/react"; +// constants +import { CORE_EXTENSIONS } from "@/constants/extension"; // helpers import { insertEmptyParagraphAtNodeBoundaries } from "@/helpers/insert-empty-paragraph-at-node-boundary"; -// config +// local imports +import { CustomCalloutBlock, type CustomCalloutNodeViewProps } from "./block"; import { CustomCalloutExtensionConfig } from "./extension-config"; -// utils +import type { CustomCalloutExtensionOptions, CustomCalloutExtensionStorage } from "./types"; import { getStoredBackgroundColor, getStoredLogo } from "./utils"; -export const CustomCalloutExtension = CustomCalloutExtensionConfig.extend({ +export const CustomCalloutExtension = CustomCalloutExtensionConfig.extend< + CustomCalloutExtensionOptions, + CustomCalloutExtensionStorage +>({ selectable: true, draggable: true, @@ -25,7 +29,7 @@ export const CustomCalloutExtension = CustomCalloutExtensionConfig.extend({ type: this.name, content: [ { - type: "paragraph", + type: CORE_EXTENSIONS.PARAGRAPH, }, ], attrs: { diff --git a/packages/editor/src/core/extensions/callout/types.ts b/packages/editor/src/core/extensions/callout/types.ts index 8e650d873..166297607 100644 --- a/packages/editor/src/core/extensions/callout/types.ts +++ b/packages/editor/src/core/extensions/callout/types.ts @@ -1,4 +1,6 @@ -export enum EAttributeNames { +import type { Node as ProseMirrorNode } from "@tiptap/core"; + +export enum ECalloutAttributeNames { ICON_COLOR = "data-icon-color", ICON_NAME = "data-icon-name", EMOJI_UNICODE = "data-emoji-unicode", @@ -9,18 +11,23 @@ export enum EAttributeNames { } export type TCalloutBlockIconAttributes = { - [EAttributeNames.ICON_COLOR]: string | undefined; - [EAttributeNames.ICON_NAME]: string | undefined; + [ECalloutAttributeNames.ICON_COLOR]: string | undefined; + [ECalloutAttributeNames.ICON_NAME]: string | undefined; }; export type TCalloutBlockEmojiAttributes = { - [EAttributeNames.EMOJI_UNICODE]: string | undefined; - [EAttributeNames.EMOJI_URL]: string | undefined; + [ECalloutAttributeNames.EMOJI_UNICODE]: string | undefined; + [ECalloutAttributeNames.EMOJI_URL]: string | undefined; }; export type TCalloutBlockAttributes = { - [EAttributeNames.LOGO_IN_USE]: "emoji" | "icon"; - [EAttributeNames.BACKGROUND]: string | undefined; - [EAttributeNames.BLOCK_TYPE]: "callout-component"; + [ECalloutAttributeNames.LOGO_IN_USE]: "emoji" | "icon"; + [ECalloutAttributeNames.BACKGROUND]: string | undefined; + [ECalloutAttributeNames.BLOCK_TYPE]: "callout-component"; } & TCalloutBlockIconAttributes & TCalloutBlockEmojiAttributes; + +export type CustomCalloutExtensionOptions = unknown; +export type CustomCalloutExtensionStorage = unknown; + +export type CustomCalloutExtensionType = ProseMirrorNode; diff --git a/packages/editor/src/core/extensions/callout/utils.ts b/packages/editor/src/core/extensions/callout/utils.ts index 3bf07f0a9..8c2cb8f65 100644 --- a/packages/editor/src/core/extensions/callout/utils.ts +++ b/packages/editor/src/core/extensions/callout/utils.ts @@ -1,33 +1,33 @@ // plane imports -import { TEmojiLogoProps } from "@plane/ui"; +import type { TEmojiLogoProps } from "@plane/ui"; import { sanitizeHTML } from "@plane/utils"; // types import { - EAttributeNames, + ECalloutAttributeNames, TCalloutBlockAttributes, TCalloutBlockEmojiAttributes, TCalloutBlockIconAttributes, } from "./types"; export const DEFAULT_CALLOUT_BLOCK_ATTRIBUTES: TCalloutBlockAttributes = { - "data-logo-in-use": "emoji", - "data-icon-color": undefined, - "data-icon-name": undefined, - "data-emoji-unicode": "128161", - "data-emoji-url": "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/1f4a1.png", - "data-background": undefined, - "data-block-type": "callout-component", + [ECalloutAttributeNames.LOGO_IN_USE]: "emoji", + [ECalloutAttributeNames.ICON_COLOR]: undefined, + [ECalloutAttributeNames.ICON_NAME]: undefined, + [ECalloutAttributeNames.EMOJI_UNICODE]: "128161", + [ECalloutAttributeNames.EMOJI_URL]: "https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/1f4a1.png", + [ECalloutAttributeNames.BACKGROUND]: undefined, + [ECalloutAttributeNames.BLOCK_TYPE]: "callout-component", }; -type TStoredLogoValue = Pick & +type TStoredLogoValue = Pick & (TCalloutBlockEmojiAttributes | TCalloutBlockIconAttributes); // function to get the stored logo from local storage export const getStoredLogo = (): TStoredLogoValue => { const fallBackValues: TStoredLogoValue = { - "data-logo-in-use": "emoji", - "data-emoji-unicode": DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-emoji-unicode"], - "data-emoji-url": DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-emoji-url"], + [ECalloutAttributeNames.LOGO_IN_USE]: "emoji", + [ECalloutAttributeNames.EMOJI_UNICODE]: DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.EMOJI_UNICODE], + [ECalloutAttributeNames.EMOJI_URL]: DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.EMOJI_URL], }; if (typeof window !== "undefined") { @@ -43,16 +43,20 @@ export const getStoredLogo = (): TStoredLogoValue => { } if (parsedData.in_use === "emoji" && parsedData.emoji?.value) { return { - "data-logo-in-use": "emoji", - "data-emoji-unicode": parsedData.emoji.value || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-emoji-unicode"], - "data-emoji-url": parsedData.emoji.url || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-emoji-url"], + [ECalloutAttributeNames.LOGO_IN_USE]: "emoji", + [ECalloutAttributeNames.EMOJI_UNICODE]: + parsedData.emoji.value || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.EMOJI_UNICODE], + [ECalloutAttributeNames.EMOJI_URL]: + parsedData.emoji.url || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.EMOJI_URL], }; } if (parsedData.in_use === "icon" && parsedData.icon?.name) { return { - "data-logo-in-use": "icon", - "data-icon-name": parsedData.icon.name || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-icon-name"], - "data-icon-color": parsedData.icon.color || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES["data-icon-color"], + [ECalloutAttributeNames.LOGO_IN_USE]: "icon", + [ECalloutAttributeNames.ICON_NAME]: + parsedData.icon.name || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.ICON_NAME], + [ECalloutAttributeNames.ICON_COLOR]: + parsedData.icon.color || DEFAULT_CALLOUT_BLOCK_ATTRIBUTES[ECalloutAttributeNames.ICON_COLOR], }; } } diff --git a/packages/editor/src/core/extensions/code/code-block-lowlight.ts b/packages/editor/src/core/extensions/code/code-block-lowlight.ts index cafad1f89..9c2dc14c3 100644 --- a/packages/editor/src/core/extensions/code/code-block-lowlight.ts +++ b/packages/editor/src/core/extensions/code/code-block-lowlight.ts @@ -11,7 +11,12 @@ type CodeBlockLowlightOptions = CodeBlockOptions & { export const CodeBlockLowlight = CodeBlock.extend({ addOptions() { return { - ...this.parent?.(), + ...(this.parent?.() ?? { + languageClassPrefix: "language-", + exitOnTripleEnter: true, + exitOnArrowDown: true, + HTMLAttributes: {}, + }), lowlight: {}, defaultLanguage: null, }; diff --git a/packages/editor/src/core/extensions/code/code-block-node-view.tsx b/packages/editor/src/core/extensions/code/code-block-node-view.tsx index 6e13924a1..0c53d82f9 100644 --- a/packages/editor/src/core/extensions/code/code-block-node-view.tsx +++ b/packages/editor/src/core/extensions/code/code-block-node-view.tsx @@ -56,7 +56,7 @@ export const CodeBlockComponent: React.FC = ({ node }) => {
-        
+         as="code" className="whitespace-pre-wrap" />
       
); diff --git a/packages/editor/src/core/extensions/core-without-props.ts b/packages/editor/src/core/extensions/core-without-props.ts index 421f48e0a..a5b2ea632 100644 --- a/packages/editor/src/core/extensions/core-without-props.ts +++ b/packages/editor/src/core/extensions/core-without-props.ts @@ -1,7 +1,6 @@ import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; -import TextStyle from "@tiptap/extension-text-style"; -import TiptapUnderline from "@tiptap/extension-underline"; +import { TextStyle } from "@tiptap/extension-text-style"; import StarterKit from "@tiptap/starter-kit"; // helpers import { isValidHttpUrl } from "@/helpers/common"; @@ -76,7 +75,6 @@ export const CoreEditorExtensionsWithoutProps = [ }), ImageExtensionConfig, CustomImageExtensionConfig, - TiptapUnderline, TextStyle, TaskList.configure({ HTMLAttributes: { diff --git a/packages/editor/src/core/extensions/custom-image/components/block.tsx b/packages/editor/src/core/extensions/custom-image/components/block.tsx index b2e88f3b1..8e069d577 100644 --- a/packages/editor/src/core/extensions/custom-image/components/block.tsx +++ b/packages/editor/src/core/extensions/custom-image/components/block.tsx @@ -2,10 +2,6 @@ import { NodeSelection } from "@tiptap/pm/state"; import React, { useRef, useState, useCallback, useLayoutEffect, useEffect } from "react"; // plane imports import { cn } from "@plane/utils"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // local imports import { Pixel, TCustomImageAttributes, TCustomImageSize } from "../types"; import { ensurePixelString, getImageBlockId } from "../utils"; @@ -62,7 +58,7 @@ export const CustomImageBlock: React.FC = (props) => { const [hasErroredOnFirstLoad, setHasErroredOnFirstLoad] = useState(false); const [hasTriedRestoringImageOnce, setHasTriedRestoringImageOnce] = useState(false); // extension options - const isTouchDevice = !!getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY).isTouchDevice; + const isTouchDevice = !!editor.storage.utility.isTouchDevice; const updateAttributesSafely = useCallback( (attributes: Partial, errorMessage: string) => { @@ -199,6 +195,7 @@ export const CustomImageBlock: React.FC = (props) => { editor.commands.blur(); } const pos = getPos(); + if (pos === undefined) return; const nodeSelection = NodeSelection.create(editor.state.doc, pos); editor.view.dispatch(editor.state.tr.setSelection(nodeSelection)); }, diff --git a/packages/editor/src/core/extensions/custom-image/components/node-view.tsx b/packages/editor/src/core/extensions/custom-image/components/node-view.tsx index 48a8ee5f7..07c2592c5 100644 --- a/packages/editor/src/core/extensions/custom-image/components/node-view.tsx +++ b/packages/editor/src/core/extensions/custom-image/components/node-view.tsx @@ -1,23 +1,16 @@ -import { Editor, NodeViewProps, NodeViewWrapper } from "@tiptap/react"; +import { type NodeViewProps, NodeViewWrapper } from "@tiptap/react"; import { useEffect, useRef, useState } from "react"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // local imports -import type { CustomImageExtension, TCustomImageAttributes } from "../types"; +import type { CustomImageExtensionType, TCustomImageAttributes } from "../types"; import { CustomImageBlock } from "./block"; import { CustomImageUploader } from "./uploader"; export type CustomImageNodeViewProps = Omit & { - extension: CustomImageExtension; - getPos: () => number; - editor: Editor; + extension: CustomImageExtensionType; node: NodeViewProps["node"] & { attrs: TCustomImageAttributes; }; updateAttributes: (attrs: Partial) => void; - selected: boolean; }; export const CustomImageNodeView: React.FC = (props) => { @@ -84,7 +77,7 @@ export const CustomImageNodeView: React.FC = (props) = diff --git a/packages/editor/src/core/extensions/custom-image/components/upload-status.tsx b/packages/editor/src/core/extensions/custom-image/components/upload-status.tsx index 466053650..83242732a 100644 --- a/packages/editor/src/core/extensions/custom-image/components/upload-status.tsx +++ b/packages/editor/src/core/extensions/custom-image/components/upload-status.tsx @@ -1,10 +1,6 @@ import { Editor } from "@tiptap/core"; import { useEditorState } from "@tiptap/react"; import { useEffect, useRef, useState } from "react"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; type Props = { editor: Editor; @@ -20,7 +16,7 @@ export const ImageUploadStatus: React.FC = (props) => { // subscribe to image upload status const uploadStatus: number | undefined = useEditorState({ editor, - selector: ({ editor }) => getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY)?.assetsUploadStatus?.[nodeId], + selector: ({ editor }) => editor.storage.utility?.assetsUploadStatus?.[nodeId], }); useEffect(() => { diff --git a/packages/editor/src/core/extensions/custom-image/components/uploader.tsx b/packages/editor/src/core/extensions/custom-image/components/uploader.tsx index 9902c3239..f784621ab 100644 --- a/packages/editor/src/core/extensions/custom-image/components/uploader.tsx +++ b/packages/editor/src/core/extensions/custom-image/components/uploader.tsx @@ -7,7 +7,6 @@ import { ACCEPTED_IMAGE_MIME_TYPES } from "@/constants/config"; import { CORE_EXTENSIONS } from "@/constants/extension"; // helpers import { EFileError } from "@/helpers/file"; -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // hooks import { useUploader, useDropZone, uploadFirstFileAndInsertRemaining } from "@/hooks/use-file-upload"; // local imports @@ -40,7 +39,7 @@ export const CustomImageUploader = (props: CustomImageUploaderProps) => { const { id: imageEntityId } = node.attrs; // derived values const imageComponentImageFileMap = useMemo(() => getImageComponentImageFileMap(editor), [editor]); - const isTouchDevice = !!getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY).isTouchDevice; + const isTouchDevice = !!editor.storage.utility.isTouchDevice; const onUpload = useCallback( (url: string) => { @@ -60,7 +59,12 @@ export const CustomImageUploader = (props: CustomImageUploaderProps) => { // only if the cursor is at the current image component, manipulate // the cursor position - if (currentNode && currentNode.type.name === node.type.name && currentNode.attrs.src === url) { + if ( + currentNode && + currentNode.type.name === node.type.name && + currentNode.attrs.src === url && + pos !== undefined + ) { // control cursor position after upload const nextNode = editor.state.doc.nodeAt(pos + 1); @@ -85,7 +89,7 @@ export const CustomImageUploader = (props: CustomImageUploaderProps) => { const handleProgressStatus = useCallback( (isUploading: boolean) => { - getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY).uploadInProgress = isUploading; + editor.storage.utility.uploadInProgress = isUploading; }, [editor] ); @@ -107,7 +111,7 @@ export const CustomImageUploader = (props: CustomImageUploaderProps) => { const { draggedInside, onDrop, onDragEnter, onDragLeave } = useDropZone({ editor, - pos: getPos(), + getPos, type: "image", uploader: uploadFile, }); @@ -139,13 +143,14 @@ export const CustomImageUploader = (props: CustomImageUploaderProps) => { async (e: ChangeEvent) => { e.preventDefault(); const filesList = e.target.files; - if (!filesList) { + const pos = getPos(); + if (!filesList || pos === undefined) { return; } await uploadFirstFileAndInsertRemaining({ editor, filesList, - pos: getPos(), + pos, type: "image", uploader: uploadFile, }); diff --git a/packages/editor/src/core/extensions/custom-image/extension-config.ts b/packages/editor/src/core/extensions/custom-image/extension-config.ts index 56714f533..1a75a3da9 100644 --- a/packages/editor/src/core/extensions/custom-image/extension-config.ts +++ b/packages/editor/src/core/extensions/custom-image/extension-config.ts @@ -3,7 +3,14 @@ import { Image as BaseImageExtension } from "@tiptap/extension-image"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; // local imports -import { type CustomImageExtension, ECustomImageAttributeNames, type InsertImageComponentProps } from "./types"; +import { + type CustomImageExtensionType, + type CustomImageExtensionStorage, + ECustomImageAttributeNames, + type InsertImageComponentProps, + CustomImageExtensionOptions, + TCustomImageAttributes, +} from "./types"; import { DEFAULT_CUSTOM_IMAGE_ATTRIBUTES } from "./utils"; declare module "@tiptap/core" { @@ -12,9 +19,15 @@ declare module "@tiptap/core" { insertImageComponent: ({ file, pos, event }: InsertImageComponentProps) => ReturnType; }; } + interface Storage { + [CORE_EXTENSIONS.CUSTOM_IMAGE]: CustomImageExtensionStorage; + } } -export const CustomImageExtensionConfig: CustomImageExtension = BaseImageExtension.extend({ +export const CustomImageExtensionConfig: CustomImageExtensionType = BaseImageExtension.extend< + CustomImageExtensionOptions, + CustomImageExtensionStorage +>({ name: CORE_EXTENSIONS.CUSTOM_IMAGE, group: "block", atom: true, @@ -22,12 +35,15 @@ export const CustomImageExtensionConfig: CustomImageExtension = BaseImageExtensi addAttributes() { const attributes = { ...this.parent?.(), - ...Object.values(ECustomImageAttributeNames).reduce((acc, value) => { - acc[value] = { - default: DEFAULT_CUSTOM_IMAGE_ATTRIBUTES[value], - }; - return acc; - }, {}), + ...Object.values(ECustomImageAttributeNames).reduce( + (acc, value) => { + acc[value] = { + default: DEFAULT_CUSTOM_IMAGE_ATTRIBUTES[value], + }; + return acc; + }, + {} as Record + ), }; return attributes; diff --git a/packages/editor/src/core/extensions/custom-image/extension.tsx b/packages/editor/src/core/extensions/custom-image/extension.tsx index 8aefd80d0..a97f50512 100644 --- a/packages/editor/src/core/extensions/custom-image/extension.tsx +++ b/packages/editor/src/core/extensions/custom-image/extension.tsx @@ -10,6 +10,7 @@ import type { TFileHandler } from "@/types"; // local imports import { CustomImageNodeView, CustomImageNodeViewProps } from "./components/node-view"; import { CustomImageExtensionConfig } from "./extension-config"; +import type { CustomImageExtensionOptions, CustomImageExtensionStorage } from "./types"; import { getImageComponentImageFileMap } from "./utils"; type Props = { @@ -22,7 +23,7 @@ export const CustomImageExtension = (props: Props) => { // derived values const { getAssetSrc, getAssetDownloadSrc, restore: restoreImageFn } = fileHandler; - return CustomImageExtensionConfig.extend({ + return CustomImageExtensionConfig.extend({ selectable: isEditable, draggable: isEditable, diff --git a/packages/editor/src/core/extensions/custom-image/types.ts b/packages/editor/src/core/extensions/custom-image/types.ts index 4ed5cd6ce..9d6f84d26 100644 --- a/packages/editor/src/core/extensions/custom-image/types.ts +++ b/packages/editor/src/core/extensions/custom-image/types.ts @@ -53,4 +53,4 @@ export type CustomImageExtensionStorage = { maxFileSize: number; }; -export type CustomImageExtension = Node; +export type CustomImageExtensionType = Node; diff --git a/packages/editor/src/core/extensions/custom-image/utils.ts b/packages/editor/src/core/extensions/custom-image/utils.ts index 10f2bb1e2..0ce1d4439 100644 --- a/packages/editor/src/core/extensions/custom-image/utils.ts +++ b/packages/editor/src/core/extensions/custom-image/utils.ts @@ -1,9 +1,5 @@ import type { Editor } from "@tiptap/core"; import { AlignCenter, AlignLeft, AlignRight, type LucideIcon } from "lucide-react"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // local imports import { ECustomImageAttributeNames, TCustomImageAlignment, type Pixel, type TCustomImageAttributes } from "./types"; @@ -16,8 +12,7 @@ export const DEFAULT_CUSTOM_IMAGE_ATTRIBUTES: TCustomImageAttributes = { [ECustomImageAttributeNames.ALIGNMENT]: "left", }; -export const getImageComponentImageFileMap = (editor: Editor) => - getExtensionStorage(editor, CORE_EXTENSIONS.CUSTOM_IMAGE)?.fileMap; +export const getImageComponentImageFileMap = (editor: Editor) => editor.storage.imageComponent?.fileMap; export const ensurePixelString = ( value: Pixel | TDefault | number | undefined | null, diff --git a/packages/editor/src/core/extensions/custom-link/extension.tsx b/packages/editor/src/core/extensions/custom-link/extension.tsx index f9ae0d561..432ff2f50 100644 --- a/packages/editor/src/core/extensions/custom-link/extension.tsx +++ b/packages/editor/src/core/extensions/custom-link/extension.tsx @@ -50,31 +50,8 @@ type LinkOptions = { }; declare module "@tiptap/core" { - interface Commands { - [CORE_EXTENSIONS.CUSTOM_LINK]: { - /** - * Set a link mark - */ - setLink: (attributes: { - href: string; - target?: string | null; - rel?: string | null; - class?: string | null; - }) => ReturnType; - /** - * Toggle a link mark - */ - toggleLink: (attributes: { - href: string; - target?: string | null; - rel?: string | null; - class?: string | null; - }) => ReturnType; - /** - * Unset a link mark - */ - unsetLink: () => ReturnType; - }; + interface Storage { + [CORE_EXTENSIONS.CUSTOM_LINK]: CustomLinkStorage; } } diff --git a/packages/editor/src/core/extensions/emoji/emoji.ts b/packages/editor/src/core/extensions/emoji/emoji.ts index e2fba3fef..2963b85d7 100644 --- a/packages/editor/src/core/extensions/emoji/emoji.ts +++ b/packages/editor/src/core/extensions/emoji/emoji.ts @@ -10,15 +10,13 @@ import { PasteRule, removeDuplicates, } from "@tiptap/core"; -import { emojis, emojiToShortcode, shortcodeToEmoji } from "@tiptap/extension-emoji"; +import { EmojiStorage, emojis, emojiToShortcode, shortcodeToEmoji } from "@tiptap/extension-emoji"; import { Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import Suggestion, { SuggestionOptions } from "@tiptap/suggestion"; import emojiRegex from "emoji-regex"; import { isEmojiSupported } from "is-emoji-supported"; // helpers -import { CORE_EXTENSIONS } from "@/constants/extension"; import { customFindSuggestionMatch } from "@/helpers/find-suggestion-match"; -import { getExtensionStorage } from "@/helpers/get-extension-storage"; declare module "@tiptap/core" { interface Commands { @@ -78,11 +76,6 @@ export type EmojiOptions = { suggestion: Omit; }; -export type EmojiStorage = { - emojis: EmojiItem[]; - isSupported: (item: EmojiItem) => boolean; -}; - export const EmojiSuggestionPluginKey = new PluginKey("emojiSuggestion"); export const inputRegex = /:([a-zA-Z0-9_+-]+):$/; @@ -344,7 +337,7 @@ export const Emoji = Node.create({ }, addProseMirrorPlugins() { - const isTouchDevice = !!getExtensionStorage(this.editor, CORE_EXTENSIONS.UTILITY).isTouchDevice; + const isTouchDevice = !!this.editor.storage.utility.isTouchDevice; if (isTouchDevice) { return []; } diff --git a/packages/editor/src/core/extensions/emoji/extension.ts b/packages/editor/src/core/extensions/emoji/extension.ts index e9f715b31..18ccfe992 100644 --- a/packages/editor/src/core/extensions/emoji/extension.ts +++ b/packages/editor/src/core/extensions/emoji/extension.ts @@ -7,11 +7,13 @@ import { emojiSuggestion } from "./suggestion"; export const EmojiExtension = Emoji.extend({ addStorage() { + const extensionOptions = this.options; + return { ...this.parent?.(), markdown: { serialize(state: MarkdownSerializerState, node: ProseMirrorNode) { - const emojiItem = shortcodeToEmoji(node.attrs.name, this.options.emojis); + const emojiItem = shortcodeToEmoji(node.attrs.name, extensionOptions.emojis); if (emojiItem?.emoji) { state.write(emojiItem?.emoji); } else if (emojiItem?.fallbackImage) { diff --git a/packages/editor/src/core/extensions/emoji/suggestion.ts b/packages/editor/src/core/extensions/emoji/suggestion.ts index ca0ab49ac..909f44d01 100644 --- a/packages/editor/src/core/extensions/emoji/suggestion.ts +++ b/packages/editor/src/core/extensions/emoji/suggestion.ts @@ -1,19 +1,16 @@ import type { EmojiOptions } from "@tiptap/extension-emoji"; -import { ReactRenderer, Editor } from "@tiptap/react"; -import { SuggestionProps, SuggestionKeyDownProps } from "@tiptap/suggestion"; +import { ReactRenderer, type Editor } from "@tiptap/react"; +import type { SuggestionProps, SuggestionKeyDownProps } from "@tiptap/suggestion"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // local imports -import { EmojiItem, EmojiList, EmojiListRef } from "./components/emojis-list"; +import { type EmojiItem, EmojiList, type EmojiListRef } from "./components/emojis-list"; const DEFAULT_EMOJIS = ["+1", "-1", "smile", "orange_heart", "eyes"]; export const emojiSuggestion: EmojiOptions["suggestion"] = { items: ({ editor, query }: { editor: Editor; query: string }): EmojiItem[] => { - const { emojis } = getExtensionStorage(editor, CORE_EXTENSIONS.EMOJI); - const { isSupported } = getExtensionStorage(editor, CORE_EXTENSIONS.EMOJI); + const { emojis, isSupported } = editor.storage.emoji; const filteredEmojis = emojis.filter((emoji) => { const hasEmoji = !!emoji?.emoji; const hasFallbackImage = !!emoji?.fallbackImage; @@ -27,7 +24,7 @@ export const emojiSuggestion: EmojiOptions["suggestion"] = { if (query.trim() === "") { const defaultEmojis = DEFAULT_EMOJIS.map((name) => - filteredEmojis.find((emoji: EmojiItem) => emoji.shortcodes.includes(name) || emoji.name === name) + filteredEmojis.find((emoji) => emoji.shortcodes.includes(name) || emoji.name === name) ) .filter(Boolean) .slice(0, 5); @@ -57,7 +54,7 @@ export const emojiSuggestion: EmojiOptions["suggestion"] = { editor = props.editor; // Track active dropdown - getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY).activeDropbarExtensions.push(CORE_EXTENSIONS.EMOJI); + editor.storage.utility.activeDropbarExtensions.push(CORE_EXTENSIONS.EMOJI); component = new ReactRenderer(EmojiList, { props: { @@ -101,10 +98,10 @@ export const emojiSuggestion: EmojiOptions["suggestion"] = { onExit: (): void => { // Remove from active dropdowns if (editor) { - const utilityStorage = getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY); - const index = utilityStorage.activeDropbarExtensions.indexOf(CORE_EXTENSIONS.EMOJI); + const { activeDropbarExtensions } = editor.storage.utility; + const index = activeDropbarExtensions.indexOf(CORE_EXTENSIONS.EMOJI); if (index > -1) { - utilityStorage.activeDropbarExtensions.splice(index, 1); + activeDropbarExtensions.splice(index, 1); } } diff --git a/packages/editor/src/core/extensions/enter-key.ts b/packages/editor/src/core/extensions/enter-key.ts index e36adde3c..854a70813 100644 --- a/packages/editor/src/core/extensions/enter-key.ts +++ b/packages/editor/src/core/extensions/enter-key.ts @@ -1,8 +1,6 @@ import { Extension } from "@tiptap/core"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; export const EnterKeyExtension = (onEnterKeyPress?: () => void) => Extension.create({ @@ -11,7 +9,7 @@ export const EnterKeyExtension = (onEnterKeyPress?: () => void) => addKeyboardShortcuts(this) { return { Enter: () => { - const { activeDropbarExtensions } = getExtensionStorage(this.editor, CORE_EXTENSIONS.UTILITY); + const { activeDropbarExtensions } = this.editor.storage.utility; if (activeDropbarExtensions.length === 0) { onEnterKeyPress?.(); diff --git a/packages/editor/src/core/extensions/extensions.ts b/packages/editor/src/core/extensions/extensions.ts index b7df5f733..5be0645df 100644 --- a/packages/editor/src/core/extensions/extensions.ts +++ b/packages/editor/src/core/extensions/extensions.ts @@ -1,9 +1,8 @@ import { Extensions } from "@tiptap/core"; -import CharacterCount from "@tiptap/extension-character-count"; import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; -import TextStyle from "@tiptap/extension-text-style"; -import TiptapUnderline from "@tiptap/extension-underline"; +import { TextStyle } from "@tiptap/extension-text-style"; +import { CharacterCount } from "@tiptap/extensions"; import { Markdown } from "tiptap-markdown"; // extensions import { @@ -76,7 +75,6 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { ListKeymap({ tabIndex }), CustomLinkExtension, CustomTypographyExtension, - TiptapUnderline, TextStyle, TaskList.configure({ HTMLAttributes: { diff --git a/packages/editor/src/core/extensions/headings-list.ts b/packages/editor/src/core/extensions/headings-list.ts index 323478cb1..5dc46c1c0 100644 --- a/packages/editor/src/core/extensions/headings-list.ts +++ b/packages/editor/src/core/extensions/headings-list.ts @@ -9,6 +9,12 @@ export type HeadingExtensionStorage = { headings: IMarking[]; }; +declare module "@tiptap/core" { + interface Storage { + [CORE_EXTENSIONS.HEADINGS_LIST]: HeadingExtensionStorage; + } +} + export const HeadingListExtension = Extension.create({ name: CORE_EXTENSIONS.HEADINGS_LIST, @@ -43,7 +49,11 @@ export const HeadingListExtension = Extension.create; }; diff --git a/packages/editor/src/core/extensions/mentions/extension-config.ts b/packages/editor/src/core/extensions/mentions/extension-config.ts index e7b6dbe2a..6c8f1f904 100644 --- a/packages/editor/src/core/extensions/mentions/extension-config.ts +++ b/packages/editor/src/core/extensions/mentions/extension-config.ts @@ -39,10 +39,6 @@ export const CustomMentionExtensionConfig = Mention.extend { const { searchCallback } = props; let component: ReactRenderer | null = null; - let popup: Instance | null = null; return { - onStart: (props: { editor: Editor; clientRect: DOMRect }) => { + onStart: ({ clientRect, editor }) => { if (!searchCallback) return; - if (!props.clientRect) return; + if (!clientRect) return; component = new ReactRenderer(MentionsListDropdown, { props: { ...props, searchCallback, }, - editor: props.editor, - }); - getExtensionStorage(props.editor, CORE_EXTENSIONS.UTILITY).activeDropbarExtensions.push( - CORE_EXTENSIONS.MENTION - ); - // @ts-expect-error - Tippy types are incorrect - popup = tippy("body", { - getReferenceClientRect: props.clientRect, - appendTo: () => - document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'), - content: component.element, - showOnCreate: true, - interactive: true, - trigger: "manual", - placement: "bottom-start", + editor: editor, }); + editor.commands.addActiveDropbarExtension(CORE_EXTENSIONS.MENTION); + const element = component.element as HTMLElement; + element.style.position = "absolute"; + document.body.appendChild(element); + updateFloatingUIFloaterPosition(editor, element); }, - onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => { + onUpdate: ({ clientRect, editor }) => { component?.updateProps(props); - popup?.[0]?.setProps({ - getReferenceClientRect: props.clientRect, - }); + if (!clientRect) return; + if (component?.element) { + updateFloatingUIFloaterPosition(editor, component?.element as HTMLElement); + } }, - onKeyDown: (props: { event: KeyboardEvent }) => { - if (props.event.key === "Escape") { - popup?.[0]?.hide(); + onKeyDown: ({ event }) => { + if (event.key === "Escape") { + component?.destroy(); return true; } const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"]; - if (navigationKeys.includes(props.event.key)) { - props.event?.stopPropagation(); - if (component?.ref?.onKeyDown(props)) { - return true; - } + if (navigationKeys.includes(event.key)) { + event?.stopPropagation(); + return component?.ref?.onKeyDown({ event }); } - return false; + return component?.ref?.onKeyDown({ event }); }, - onExit: (props: { editor: Editor; event: KeyboardEvent }) => { - const utilityStorage = getExtensionStorage(props.editor, CORE_EXTENSIONS.UTILITY); - const index = utilityStorage.activeDropbarExtensions.indexOf(CORE_EXTENSIONS.MENTION); - if (index > -1) { - utilityStorage.activeDropbarExtensions.splice(index, 1); - } - popup?.[0]?.destroy(); + onExit: ({ editor }) => { + editor.commands.removeActiveDropbarExtension(CORE_EXTENSIONS.MENTION); + component?.element.remove(); component?.destroy(); }, }; diff --git a/packages/editor/src/core/extensions/placeholder.ts b/packages/editor/src/core/extensions/placeholder.ts index 9e23792a2..b3d70fc7e 100644 --- a/packages/editor/src/core/extensions/placeholder.ts +++ b/packages/editor/src/core/extensions/placeholder.ts @@ -1,8 +1,6 @@ -import Placeholder from "@tiptap/extension-placeholder"; +import { Placeholder } from "@tiptap/extensions"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; -// helpers -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // types import type { IEditorProps } from "@/types"; @@ -19,7 +17,7 @@ export const CustomPlaceholderExtension = (args: TArgs) => { if (node.type.name === CORE_EXTENSIONS.HEADING) return `Heading ${node.attrs.level}`; - const isUploadInProgress = getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY)?.uploadInProgress; + const isUploadInProgress = editor.storage.utility?.uploadInProgress; if (isUploadInProgress) return ""; diff --git a/packages/editor/src/core/extensions/slash-commands/root.tsx b/packages/editor/src/core/extensions/slash-commands/root.tsx index 971c4da56..1e5900ae9 100644 --- a/packages/editor/src/core/extensions/slash-commands/root.tsx +++ b/packages/editor/src/core/extensions/slash-commands/root.tsx @@ -1,10 +1,10 @@ -import { Editor, Range, Extension } from "@tiptap/core"; +import { type Editor, type Range, Extension } from "@tiptap/core"; import { ReactRenderer } from "@tiptap/react"; -import Suggestion, { SuggestionOptions } from "@tiptap/suggestion"; -import tippy, { Instance } from "tippy.js"; +import Suggestion, { type SuggestionOptions } from "@tiptap/suggestion"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; // helpers +import { updateFloatingUIFloaterPosition } from "@/helpers/floating-ui"; import { CommandListInstance } from "@/helpers/tippy"; // types import { IEditorProps, ISlashCommandItem, TEditorCommands, TSlashCommandSectionKeys } from "@/types"; @@ -32,7 +32,6 @@ const Command = Extension.create({ }, allow({ editor }: { editor: Editor }) { const { selection } = editor.state; - const parentNode = selection.$from.node(selection.$from.depth); const blockType = parentNode.type.name; @@ -49,64 +48,63 @@ const Command = Extension.create({ return [ Suggestion({ editor: this.editor, + render: () => { + let component: ReactRenderer | null = null; + + return { + onStart: (props) => { + component = new ReactRenderer(SlashCommandsMenu, { + props, + editor: props.editor, + }); + + if (!props.clientRect) { + return; + } + + const element = component.element as HTMLElement; + element.style.position = "absolute"; + element.style.zIndex = "100"; + (props.editor.options.element || document.body).appendChild(element); + + updateFloatingUIFloaterPosition(props.editor, element); + }, + + onUpdate: (props) => { + if (!component || !component.element) return; + + component.updateProps(props); + + if (!props.clientRect) { + return; + } + + const element = component.element as HTMLElement; + updateFloatingUIFloaterPosition(props.editor, element); + }, + + onKeyDown: (props) => { + if (props.event.key === "Escape") { + component?.destroy(); + component = null; + return true; + } + + return component?.ref?.onKeyDown(props) ?? false; + }, + + onExit: () => { + component?.destroy(); + component = null; + }, + }; + }, ...this.options.suggestion, }), ]; }, }); -const renderItems: SuggestionOptions["render"] = () => { - let component: ReactRenderer | null = null; - let popup: Instance | null = null; - return { - onStart: (props) => { - // Track active dropdown - props.editor.commands.addActiveDropbarExtension(CORE_EXTENSIONS.SLASH_COMMANDS); - - component = new ReactRenderer(SlashCommandsMenu, { - props, - editor: props.editor, - }); - - const tippyContainer = - document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'); - // @ts-expect-error - Tippy types are incorrect - popup = tippy("body", { - getReferenceClientRect: props.clientRect, - appendTo: tippyContainer, - content: component.element, - showOnCreate: true, - interactive: true, - trigger: "manual", - placement: "bottom-start", - }); - }, - onUpdate: (props) => { - component?.updateProps(props); - - popup?.[0]?.setProps({ - getReferenceClientRect: props.clientRect, - }); - }, - onKeyDown: (props) => { - if (props.event.key === "Escape") { - popup?.[0].hide(); - return true; - } - if (component?.ref?.onKeyDown(props)) { - return true; - } - return false; - }, - onExit: ({ editor }) => { - // Remove from active dropdowns - editor?.commands.removeActiveDropbarExtension(CORE_EXTENSIONS.SLASH_COMMANDS); - popup?.[0].destroy(); - component?.destroy(); - }, - }; -}; - export type TExtensionProps = Pick & { additionalOptions?: TSlashCommandAdditionalOption[]; }; @@ -115,6 +113,5 @@ export const SlashCommands = (props: TExtensionProps) => Command.configure({ suggestion: { items: getSlashCommandFilteredSections(props), - render: renderItems, }, }); diff --git a/packages/editor/src/core/extensions/starter-kit.ts b/packages/editor/src/core/extensions/starter-kit.ts index e6a4c968d..286768ace 100644 --- a/packages/editor/src/core/extensions/starter-kit.ts +++ b/packages/editor/src/core/extensions/starter-kit.ts @@ -27,6 +27,8 @@ export const CustomStarterKitExtension = (args: TArgs) => { codeBlock: false, horizontalRule: false, blockquote: false, + link: false, + listKeymap: false, paragraph: { HTMLAttributes: { class: "editor-paragraph-block", @@ -41,6 +43,6 @@ export const CustomStarterKitExtension = (args: TArgs) => { class: "text-custom-text-300 transition-all motion-reduce:transition-none motion-reduce:hover:transform-none duration-200 ease-[cubic-bezier(0.165, 0.84, 0.44, 1)]", }, - ...(enableHistory ? {} : { history: false }), + ...(enableHistory ? {} : { undoRedo: false }), }); }; diff --git a/packages/editor/src/core/extensions/table/table/table-view.tsx b/packages/editor/src/core/extensions/table/table/table-view.tsx index 6595ea3cb..c7f60f514 100644 --- a/packages/editor/src/core/extensions/table/table/table-view.tsx +++ b/packages/editor/src/core/extensions/table/table/table-view.tsx @@ -1,274 +1,21 @@ -import { Editor } from "@tiptap/core"; -import { Node as ProseMirrorNode, ResolvedPos } from "@tiptap/pm/model"; -import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/pm/tables"; -import { Decoration, NodeView } from "@tiptap/pm/view"; +import type { Editor, NodeViewProps } from "@tiptap/core"; +import type { Node as ProseMirrorNode, ResolvedPos } from "@tiptap/pm/model"; +import { TableMap, updateColumnsOnResize } from "@tiptap/pm/tables"; +import type { Decoration, NodeView } from "@tiptap/pm/view"; import { h } from "jsx-dom-cjs"; -import tippy, { Instance, Props } from "tippy.js"; -import { CORE_EXTENSIONS } from "@/constants/extension"; -import { icons } from "./icons"; -import { isCellSelection } from "./utilities/helpers"; - -type ToolboxItem = { - label: string; - icon: string; - action: (args: any) => void; -}; - -export function updateColumns( - node: ProseMirrorNode, - colgroup: HTMLElement, - table: HTMLElement, - cellMinWidth: number, - overrideCol?: number, - overrideValue?: any -) { - let totalWidth = 0; - let fixedWidth = true; - let nextDOM = colgroup.firstChild as HTMLElement; - const row = node.firstChild; - - if (!row) return; - - for (let i = 0, col = 0; i < row.childCount; i += 1) { - const { colspan, colWidth } = row.child(i).attrs; - - for (let j = 0; j < colspan; j += 1, col += 1) { - const hasWidth = overrideCol === col ? overrideValue : colWidth && colWidth[j]; - const cssWidth = hasWidth ? `${hasWidth}px` : ""; - - totalWidth += hasWidth || cellMinWidth; - - if (!hasWidth) { - fixedWidth = false; - } - - if (!nextDOM) { - colgroup.appendChild(document.createElement("col")).style.width = cssWidth; - } else { - if (nextDOM.style.width !== cssWidth) { - nextDOM.style.width = cssWidth; - } - - nextDOM = nextDOM.nextSibling as HTMLElement; - } - } - } - - while (nextDOM) { - const after = nextDOM.nextSibling; - - nextDOM.parentNode?.removeChild(nextDOM); - nextDOM = after as HTMLElement; - } - - if (fixedWidth) { - table.style.width = `${totalWidth}px`; - table.style.minWidth = ""; - } else { - table.style.width = ""; - table.style.minWidth = `${totalWidth}px`; - } -} - -const defaultTippyOptions: Partial = { - allowHTML: true, - arrow: false, - trigger: "click", - animation: "scale-subtle", - theme: "light-border no-padding", - interactive: true, - hideOnClick: true, - placement: "right", -}; - -function setCellsBackgroundColor(editor: Editor, color: { backgroundColor: string; textColor: string }) { - return editor - .chain() - .focus() - .updateAttributes(CORE_EXTENSIONS.TABLE_CELL, { - background: color.backgroundColor, - textColor: color.textColor, - }) - .run(); -} - -function setTableRowBackgroundColor(editor: Editor, color: { backgroundColor: string; textColor: string }) { - const { state, dispatch } = editor.view; - const { selection } = state; - if (!isCellSelection(selection)) { - return false; - } - - // Get the position of the hovered cell in the selection to determine the row. - const hoveredCell = selection.$headCell || selection.$anchorCell; - - // Find the depth of the table row node - let rowDepth = hoveredCell.depth; - while (rowDepth > 0 && hoveredCell.node(rowDepth).type.name !== CORE_EXTENSIONS.TABLE_ROW) { - rowDepth--; - } - - // If we couldn't find a tableRow node, we can't set the background color - if (hoveredCell.node(rowDepth).type.name !== CORE_EXTENSIONS.TABLE_ROW) { - return false; - } - - // Get the position where the table row starts - const rowStartPos = hoveredCell.start(rowDepth); - - // Create a transaction that sets the background color on the tableRow node. - const tr = state.tr.setNodeMarkup(rowStartPos - 1, null, { - ...hoveredCell.node(rowDepth).attrs, - background: color.backgroundColor, - textColor: color.textColor, - }); - - dispatch(tr); - return true; -} - -const columnsToolboxItems: ToolboxItem[] = [ - { - label: "Toggle column header", - icon: icons.toggleColumnHeader, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().toggleHeaderColumn().run(), - }, - { - label: "Add column before", - icon: icons.insertLeftTableIcon, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().addColumnBefore().run(), - }, - { - label: "Add column after", - icon: icons.insertRightTableIcon, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().addColumnAfter().run(), - }, - { - label: "Pick color", - icon: "", // No icon needed for color picker - action: (_args: unknown) => {}, // Placeholder action; actual color picking is handled in `createToolbox` - }, - { - label: "Delete column", - icon: icons.deleteColumn, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().deleteColumn().run(), - }, -]; - -const rowsToolboxItems: ToolboxItem[] = [ - { - label: "Toggle row header", - icon: icons.toggleRowHeader, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().toggleHeaderRow().run(), - }, - { - label: "Add row above", - icon: icons.insertTopTableIcon, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().addRowBefore().run(), - }, - { - label: "Add row below", - icon: icons.insertBottomTableIcon, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().addRowAfter().run(), - }, - { - label: "Pick color", - icon: "", - action: (_args: unknown) => {}, // Placeholder action; actual color picking is handled in `createToolbox` - }, - { - label: "Delete row", - icon: icons.deleteRow, - action: ({ editor }: { editor: Editor }) => editor.chain().focus().deleteRow().run(), - }, -]; - -function createToolbox({ - triggerButton, - items, - tippyOptions, - onSelectColor, - onClickItem, - colors, -}: { - triggerButton: Element | null; - items: ToolboxItem[]; - tippyOptions: any; - onClickItem: (item: ToolboxItem) => void; - onSelectColor: (color: { backgroundColor: string; textColor: string }) => void; - colors: { [key: string]: { backgroundColor: string; textColor: string; icon?: string } }; -}): Instance { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - const toolbox = tippy(triggerButton, { - content: h( - "div", - { - className: - "rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 text-xs shadow-custom-shadow-rg min-w-[12rem] whitespace-nowrap", - }, - items.map((item) => { - if (item.label === "Pick color") { - return h("div", { className: "flex flex-col" }, [ - h("hr", { className: "my-2 border-custom-border-200" }), - h("div", { className: "text-custom-text-200 text-sm" }, item.label), - h( - "div", - { className: "grid grid-cols-6 gap-x-1 gap-y-2.5 mt-2" }, - Object.entries(colors).map(([_, colorValue]) => - h("div", { - className: "grid place-items-center size-6 rounded cursor-pointer", - style: `background-color: ${colorValue.backgroundColor};color: ${colorValue.textColor || "inherit"};`, - innerHTML: - colorValue.icon ?? `A`, - onClick: () => onSelectColor(colorValue), - }) - ) - ), - h("hr", { className: "my-2 border-custom-border-200" }), - ]); - } else { - return h( - "div", - { - className: - "flex items-center gap-2 px-1 py-1.5 bg-custom-background-100 hover:bg-custom-background-80 text-sm text-custom-text-200 rounded cursor-pointer", - itemType: "div", - onClick: () => onClickItem(item), - }, - [ - h("span", { - className: "h-3 w-3 flex-shrink-0", - innerHTML: item.icon, - }), - h("div", { className: "label" }, item.label), - ] - ); - } - }) - ), - ...tippyOptions, - }); - - return Array.isArray(toolbox) ? toolbox[0] : toolbox; -} export class TableView implements NodeView { node: ProseMirrorNode; cellMinWidth: number; - decorations: Decoration[]; + decorations: readonly Decoration[]; editor: Editor; - getPos: () => number; + getPos: NodeViewProps["getPos"]; hoveredCell: ResolvedPos | null = null; map: TableMap; root: HTMLElement; table: HTMLTableElement; colgroup: HTMLTableColElement; tbody: HTMLElement; - rowsControl?: HTMLElement | null; - columnsControl?: HTMLElement | null; - columnsToolbox?: Instance; - rowsToolbox?: Instance; controls?: HTMLElement; get dom() { @@ -282,9 +29,9 @@ export class TableView implements NodeView { constructor( node: ProseMirrorNode, cellMinWidth: number, - decorations: Decoration[], + decorations: readonly Decoration[], editor: Editor, - getPos: () => number + getPos: NodeViewProps["getPos"] ) { this.node = node; this.cellMinWidth = cellMinWidth; @@ -294,88 +41,6 @@ export class TableView implements NodeView { this.hoveredCell = null; this.map = TableMap.get(node); - if (editor.isEditable) { - this.rowsControl = h( - "div", - { className: "rows-control" }, - h("div", { - itemType: "button", - className: "rows-control-div", - onClick: () => this.selectRow(), - }) - ); - - this.columnsControl = h( - "div", - { className: "columns-control" }, - h("div", { - itemType: "button", - className: "columns-control-div", - onClick: () => this.selectColumn(), - }) - ); - - this.controls = h( - "div", - { className: "table-controls", contentEditable: "false" }, - this.rowsControl, - this.columnsControl - ); - const columnColors = { - Blue: { backgroundColor: "#D9E4FF", textColor: "#171717" }, - Orange: { backgroundColor: "#FFEDD5", textColor: "#171717" }, - Grey: { backgroundColor: "#F1F1F1", textColor: "#171717" }, - Yellow: { backgroundColor: "#FEF3C7", textColor: "#171717" }, - Green: { backgroundColor: "#DCFCE7", textColor: "#171717" }, - Red: { backgroundColor: "#FFDDDD", textColor: "#171717" }, - Pink: { backgroundColor: "#FFE8FA", textColor: "#171717" }, - Purple: { backgroundColor: "#E8DAFB", textColor: "#171717" }, - None: { - backgroundColor: "none", - textColor: "none", - icon: ``, - }, - }; - - this.columnsToolbox = createToolbox({ - triggerButton: this.columnsControl.querySelector(".columns-control-div"), - items: columnsToolboxItems, - colors: columnColors, - onSelectColor: (color) => setCellsBackgroundColor(this.editor, color), - tippyOptions: { - ...defaultTippyOptions, - appendTo: this.controls, - }, - onClickItem: (item) => { - item.action({ - editor: this.editor, - triggerButton: this.columnsControl?.firstElementChild, - controlsContainer: this.controls, - }); - this.columnsToolbox?.hide(); - }, - }); - - this.rowsToolbox = createToolbox({ - triggerButton: this.rowsControl.firstElementChild, - items: rowsToolboxItems, - colors: columnColors, - tippyOptions: { - ...defaultTippyOptions, - appendTo: this.controls, - }, - onSelectColor: (color) => setTableRowBackgroundColor(editor, color), - onClickItem: (item) => { - item.action({ - editor: this.editor, - triggerButton: this.rowsControl?.firstElementChild, - controlsContainer: this.controls, - }); - this.rowsToolbox?.hide(); - }, - }); - } - this.colgroup = h( "colgroup", null, @@ -387,9 +52,8 @@ export class TableView implements NodeView { this.root = h( "div", { - className: "table-wrapper editor-full-width-block horizontal-scrollbar scrollbar-sm controls--disabled", + className: "table-wrapper editor-full-width-block horizontal-scrollbar scrollbar-sm", }, - this.controls, this.table ); @@ -405,10 +69,6 @@ export class TableView implements NodeView { this.decorations = [...decorations]; this.map = TableMap.get(this.node); - if (this.editor.isEditable) { - this.updateControls(); - } - this.render(); return true; @@ -426,67 +86,4 @@ export class TableView implements NodeView { ignoreMutation() { return true; } - - updateControls() { - const { hoveredTable: table, hoveredCell: cell } = Object.values(this.decorations).reduce( - (acc, curr) => { - if (curr.spec.hoveredCell !== undefined) { - acc["hoveredCell"] = curr.spec.hoveredCell; - } - - if (curr.spec.hoveredTable !== undefined) { - acc["hoveredTable"] = curr.spec.hoveredTable; - } - return acc; - }, - {} as Record - ) as any; - - if (table === undefined || cell === undefined) { - return this.root.classList.add("controls--disabled"); - } - - this.root.classList.remove("controls--disabled"); - this.hoveredCell = cell; - - const cellDom = this.editor.view.nodeDOM(cell.pos) as HTMLElement; - - if (!this.table || !cellDom) { - return; - } - - const tableRect = this.table?.getBoundingClientRect(); - const cellRect = cellDom?.getBoundingClientRect(); - - if (this.columnsControl) { - this.columnsControl.style.left = `${cellRect.left - tableRect.left - this.table.parentElement!.scrollLeft}px`; - this.columnsControl.style.width = `${cellRect.width}px`; - } - if (this.rowsControl) { - this.rowsControl.style.top = `${cellRect.top - tableRect.top}px`; - this.rowsControl.style.height = `${cellRect.height}px`; - } - } - - selectColumn() { - if (!this.hoveredCell) return; - - const colIndex = this.map.colCount(this.hoveredCell.pos - (this.getPos() + 1)); - const anchorCellPos = this.hoveredCell.pos; - const headCellPos = this.map.map[colIndex + this.map.width * (this.map.height - 1)] + (this.getPos() + 1); - - const cellSelection = CellSelection.create(this.editor.view.state.doc, anchorCellPos, headCellPos); - this.editor.view.dispatch(this.editor.state.tr.setSelection(cellSelection)); - } - - selectRow() { - if (!this.hoveredCell) return; - - const anchorCellPos = this.hoveredCell.pos; - const anchorCellIndex = this.map.map.indexOf(anchorCellPos - (this.getPos() + 1)); - const headCellPos = this.map.map[anchorCellIndex + (this.map.width - 1)] + (this.getPos() + 1); - - const cellSelection = CellSelection.create(this.editor.state.doc, anchorCellPos, headCellPos); - this.editor.view.dispatch(this.editor.view.state.tr.setSelection(cellSelection)); - } } diff --git a/packages/editor/src/core/extensions/table/table/table.ts b/packages/editor/src/core/extensions/table/table/table.ts index 2462fa817..6e12a6185 100644 --- a/packages/editor/src/core/extensions/table/table/table.ts +++ b/packages/editor/src/core/extensions/table/table/table.ts @@ -18,7 +18,6 @@ import { toggleHeader, toggleHeaderCell, } from "@tiptap/pm/tables"; -import type { Decoration } from "@tiptap/pm/view"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; // local imports @@ -264,7 +263,7 @@ export const Table = Node.create({ return ({ editor, node, decorations, getPos }) => { const { cellMinWidth } = this.options; - return new TableView(node, cellMinWidth, decorations as Decoration[], editor, getPos); + return new TableView(node, cellMinWidth, decorations, editor, getPos); }; }, diff --git a/packages/editor/src/core/extensions/utility.ts b/packages/editor/src/core/extensions/utility.ts index e996a694d..9c2d64206 100644 --- a/packages/editor/src/core/extensions/utility.ts +++ b/packages/editor/src/core/extensions/utility.ts @@ -16,6 +16,7 @@ type TActiveDropbarExtensions = | CORE_EXTENSIONS.EMOJI | CORE_EXTENSIONS.SLASH_COMMANDS | CORE_EXTENSIONS.TABLE + | "bubble-menu" | CORE_EXTENSIONS.SIDE_MENU | TAdditionalActiveDropbarExtensions; @@ -36,6 +37,9 @@ declare module "@tiptap/core" { removeActiveDropbarExtension: (extension: TActiveDropbarExtensions) => () => void; }; } + interface Storage { + [CORE_EXTENSIONS.UTILITY]: UtilityExtensionStorage; + } } export type UtilityExtensionStorage = { diff --git a/packages/editor/src/core/helpers/assets.ts b/packages/editor/src/core/helpers/assets.ts index 74179f6c4..a7f19b6c2 100644 --- a/packages/editor/src/core/helpers/assets.ts +++ b/packages/editor/src/core/helpers/assets.ts @@ -1,16 +1,18 @@ -import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; +import type { Node as ProseMirrorNode } from "@tiptap/pm/model"; +// plane imports +import { ADDITIONAL_EXTENSIONS, CORE_EXTENSIONS } from "@plane/utils"; // extensions import { getImageBlockId } from "@/extensions/custom-image/utils"; // plane editor imports import { ADDITIONAL_ASSETS_META_DATA_RECORD } from "@/plane-editor/constants/assets"; // types -import { TEditorAsset } from "@/types"; +import type { TEditorAsset } from "@/types"; export type TAssetMetaDataRecord = (attrs: ProseMirrorNode["attrs"]) => TEditorAsset | undefined; -export const CORE_ASSETS_META_DATA_RECORD: Partial> = { +export const CORE_ASSETS_META_DATA_RECORD: Partial< + Record +> = { [CORE_EXTENSIONS.IMAGE]: (attrs) => { if (!attrs?.src) return; return { diff --git a/packages/editor/src/core/helpers/editor-ref.ts b/packages/editor/src/core/helpers/editor-ref.ts index 2e45e8963..e56aa7bdf 100644 --- a/packages/editor/src/core/helpers/editor-ref.ts +++ b/packages/editor/src/core/helpers/editor-ref.ts @@ -1,5 +1,5 @@ -import { HocuspocusProvider } from "@hocuspocus/provider"; -import { Editor } from "@tiptap/core"; +import type { HocuspocusProvider } from "@hocuspocus/provider"; +import type { Editor } from "@tiptap/core"; import { DOMSerializer } from "@tiptap/pm/model"; import * as Y from "yjs"; // components @@ -11,7 +11,6 @@ import { CORE_EDITOR_META } from "@/constants/meta"; import type { EditorRefApi, TEditorCommands } from "@/types"; // local imports import { getParagraphCount } from "./common"; -import { getExtensionStorage } from "./get-extension-storage"; import { insertContentAtSavedSelection } from "./insert-content-at-cursor-position"; import { scrollSummary, scrollToNodeViaDOMCoordinates } from "./scroll-to-node"; @@ -72,18 +71,18 @@ export const getEditorRefHelpers = (args: TArgs): EditorRefApi => { }; }, getDocumentInfo: () => ({ - characters: editor ? getExtensionStorage(editor, CORE_EXTENSIONS.CHARACTER_COUNT)?.characters?.() : 0, + characters: editor?.storage.characterCount?.characters?.() ?? 0, paragraphs: getParagraphCount(editor?.state), - words: editor ? getExtensionStorage(editor, CORE_EXTENSIONS.CHARACTER_COUNT)?.words?.() : 0, + words: editor?.storage.characterCount?.words?.() ?? 0, }), - getHeadings: () => (editor ? getExtensionStorage(editor, CORE_EXTENSIONS.HEADINGS_LIST)?.headings : []), + getHeadings: () => (editor ? editor.storage.headingsList?.headings : []), getMarkDown: () => { - const markdownOutput = editor?.storage?.markdown?.getMarkdown?.(); + const markdownOutput = editor?.storage?.markdown?.getMarkdown?.() ?? ""; return markdownOutput; }, isAnyDropbarOpen: () => { if (!editor) return false; - const utilityStorage = getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY); + const utilityStorage = editor.storage.utility; return utilityStorage.activeDropbarExtensions.length > 0; }, scrollSummary: (marking) => { @@ -91,7 +90,17 @@ export const getEditorRefHelpers = (args: TArgs): EditorRefApi => { scrollSummary(editor, marking); }, setEditorValue: (content, emitUpdate = false) => { - editor?.commands.setContent(content, emitUpdate, { preserveWhitespace: true }); + editor + ?.chain() + .setMeta(CORE_EDITOR_META.SKIP_FILE_DELETION, true) + .setMeta(CORE_EDITOR_META.INTENTIONAL_DELETION, true) + .setContent(content, { + emitUpdate, + parseOptions: { + preserveWhitespace: true, + }, + }) + .run(); }, emitRealTimeUpdate: (message) => provider?.sendStateless(message), executeMenuItemCommand: (props) => { @@ -148,8 +157,7 @@ export const getEditorRefHelpers = (args: TArgs): EditorRefApi => { editor.chain().focus().deleteRange({ from, to }).insertContent(contentHTML).run(); } }, - isEditorReadyToDiscard: () => - !!editor && getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY)?.uploadInProgress === false, + isEditorReadyToDiscard: () => editor?.storage?.utility?.uploadInProgress === false, isMenuItemActive: (props) => { const { itemKey } = props; const editorItems = getEditorMenuItems(editor); @@ -163,11 +171,11 @@ export const getEditorRefHelpers = (args: TArgs): EditorRefApi => { listenToRealTimeUpdate: () => provider && { on: provider.on.bind(provider), off: provider.off.bind(provider) }, onDocumentInfoChange: (callback) => { const handleDocumentInfoChange = () => { - if (!editor) return; + if (!editor?.storage) return; callback({ - characters: editor ? getExtensionStorage(editor, CORE_EXTENSIONS.CHARACTER_COUNT)?.characters?.() : 0, + characters: editor.storage.characterCount?.characters?.() ?? 0, paragraphs: getParagraphCount(editor?.state), - words: editor ? getExtensionStorage(editor, CORE_EXTENSIONS.CHARACTER_COUNT)?.words?.() : 0, + words: editor.storage.characterCount?.words?.() ?? 0, }); }; @@ -183,7 +191,7 @@ export const getEditorRefHelpers = (args: TArgs): EditorRefApi => { onHeadingChange: (callback) => { const handleHeadingChange = () => { if (!editor) return; - const headings = getExtensionStorage(editor, CORE_EXTENSIONS.HEADINGS_LIST)?.headings; + const headings = editor.storage.headingsList?.headings; if (headings) { callback(headings); } diff --git a/packages/editor/src/core/helpers/floating-ui.ts b/packages/editor/src/core/helpers/floating-ui.ts new file mode 100644 index 000000000..6143b0321 --- /dev/null +++ b/packages/editor/src/core/helpers/floating-ui.ts @@ -0,0 +1,33 @@ +import { computePosition, flip, type Middleware, type Strategy, type Placement, shift } from "@floating-ui/dom"; +import { type Editor, posToDOMRect } from "@tiptap/core"; + +export const updateFloatingUIFloaterPosition = ( + editor: Editor, + element: HTMLElement, + options?: { + elementStyle?: Partial; + middleware?: Middleware[]; + placement?: Placement; + strategy?: Strategy; + } +) => { + const virtualElement = { + getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to), + }; + + computePosition(virtualElement, element, { + placement: options?.placement ?? "bottom-start", + strategy: options?.strategy ?? "absolute", + middleware: options?.middleware ?? [shift(), flip()], + }) + .then(({ x, y, strategy }) => { + Object.assign(element.style, { + width: "max-content", + position: strategy, + left: `${x}px`, + top: `${y}px`, + ...options?.elementStyle, + }); + }) + .catch((error) => console.error("An error occurred while updating floating UI floter position:", error)); +}; diff --git a/packages/editor/src/core/helpers/get-extension-storage.ts b/packages/editor/src/core/helpers/get-extension-storage.ts deleted file mode 100644 index 86db93e18..000000000 --- a/packages/editor/src/core/helpers/get-extension-storage.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Editor } from "@tiptap/core"; -// plane editor types -import { ExtensionStorageMap } from "@/plane-editor/types/storage"; - -export const getExtensionStorage = ( - editor: Editor, - extensionName: K -): ExtensionStorageMap[K] => editor.storage[extensionName]; diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index 1285a6a7e..8e991d033 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -1,17 +1,21 @@ import { useEditorState, useEditor as useTiptapEditor } from "@tiptap/react"; import { useImperativeHandle, useEffect } from "react"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; +import type { MarkdownStorage } from "tiptap-markdown"; // extensions import { CoreEditorExtensions } from "@/extensions"; // helpers import { getEditorRefHelpers } from "@/helpers/editor-ref"; -import { getExtensionStorage } from "@/helpers/get-extension-storage"; // props import { CoreEditorProps } from "@/props"; // types import type { TEditorHookProps } from "@/types"; +declare module "@tiptap/core" { + interface Storage { + markdown: MarkdownStorage; + } +} + export const useEditor = (props: TEditorHookProps) => { const { autofocus = false, @@ -86,10 +90,15 @@ export const useEditor = (props: TEditorHookProps) => { // supported and value is undefined when the data from swr is not populated if (value == null) return; if (editor) { - const isUploadInProgress = getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY)?.uploadInProgress; + const { uploadInProgress: isUploadInProgress } = editor.storage.utility; if (!editor.isDestroyed && !isUploadInProgress) { try { - editor.commands.setContent(value, false, { preserveWhitespace: true }); + editor.commands.setContent(value, { + emitUpdate: false, + parseOptions: { + preserveWhitespace: true, + }, + }); if (editor.state.selection) { const docLength = editor.state.doc.content.size; const relativePosition = Math.min(editor.state.selection.from, docLength - 1); @@ -113,7 +122,7 @@ export const useEditor = (props: TEditorHookProps) => { const assetsList = useEditorState({ editor, selector: ({ editor }) => ({ - assets: editor ? getExtensionStorage(editor, CORE_EXTENSIONS.UTILITY)?.assetsList : [], + assets: editor?.storage.utility?.assetsList ?? [], }), }); // trigger callback when assets list changes diff --git a/packages/editor/src/core/hooks/use-file-upload.ts b/packages/editor/src/core/hooks/use-file-upload.ts index dce48cca5..4691601a5 100644 --- a/packages/editor/src/core/hooks/use-file-upload.ts +++ b/packages/editor/src/core/hooks/use-file-upload.ts @@ -1,4 +1,4 @@ -import { Editor } from "@tiptap/core"; +import type { Editor, NodeViewProps } from "@tiptap/core"; import { DragEvent, useCallback, useEffect, useState } from "react"; // helpers import { EFileError, isFileValid } from "@/helpers/file"; @@ -66,9 +66,8 @@ export const useUploader = (args: TUploaderArgs) => { throw new Error("Something went wrong while uploading the file."); } onUpload(url, file); - } catch (errPayload) { - const error = errPayload?.response?.data?.error || "Something went wrong"; - console.error(error); + } catch { + console.error("useFileUpload: Error in uploading file"); } finally { handleProgressStatus?.(false); setIsUploading(false); @@ -90,13 +89,13 @@ export const useUploader = (args: TUploaderArgs) => { type TDropzoneArgs = { editor: Editor; - pos: number; + getPos: NodeViewProps["getPos"]; type: Extract; uploader: (file: File) => Promise; }; export const useDropZone = (args: TDropzoneArgs) => { - const { editor, pos, type, uploader } = args; + const { editor, getPos, type, uploader } = args; // states const [isDragging, setIsDragging] = useState(false); const [draggedInside, setDraggedInside] = useState(false); @@ -124,8 +123,9 @@ export const useDropZone = (args: TDropzoneArgs) => { e.preventDefault(); setDraggedInside(false); const filesList = e.dataTransfer.files; + const pos = getPos(); - if (filesList.length === 0 || !editor.isEditable) { + if (filesList.length === 0 || !editor.isEditable || pos === undefined) { return; } @@ -137,7 +137,7 @@ export const useDropZone = (args: TDropzoneArgs) => { uploader, }); }, - [editor, pos, type, uploader] + [editor, type, uploader, getPos] ); const onDragEnter = useCallback(() => setDraggedInside(true), []); const onDragLeave = useCallback(() => setDraggedInside(false), []); diff --git a/packages/editor/src/core/plugins/file/delete.ts b/packages/editor/src/core/plugins/file/delete.ts index 427b100b7..fbb434e7d 100644 --- a/packages/editor/src/core/plugins/file/delete.ts +++ b/packages/editor/src/core/plugins/file/delete.ts @@ -1,5 +1,5 @@ -import { Editor } from "@tiptap/core"; -import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; +import type { Editor } from "@tiptap/core"; +import { type EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; // constants import { CORE_EDITOR_META } from "@/constants/meta"; // plane editor imports @@ -7,6 +7,7 @@ import { NODE_FILE_MAP } from "@/plane-editor/constants/utility"; // types import { TFileHandler } from "@/types"; // local imports +import type { NodeFileMapType } from "../../../ce/constants/utility"; import { TFileNode } from "./types"; const DELETE_PLUGIN_KEY = new PluginKey("delete-utility"); @@ -21,7 +22,7 @@ export const TrackFileDeletionPlugin = (editor: Editor, deleteHandler: TFileHand if (!transactions.some((tr) => tr.docChanged)) return null; newState.doc.descendants((node) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const nodeFileSetDetails = NODE_FILE_MAP[nodeType]; if (nodeFileSetDetails) { if (newFileSources[nodeType]) { @@ -40,7 +41,7 @@ export const TrackFileDeletionPlugin = (editor: Editor, deleteHandler: TFileHand // iterate through all the nodes in the old state oldState.doc.descendants((node) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const isAValidNode = NODE_FILE_MAP[nodeType]; // if the node doesn't match, then return as no point in checking if (!isAValidNode) return; @@ -51,12 +52,13 @@ export const TrackFileDeletionPlugin = (editor: Editor, deleteHandler: TFileHand }); removedFiles.forEach(async (node) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const src = node.attrs.src; const nodeFileSetDetails = NODE_FILE_MAP[nodeType]; if (!nodeFileSetDetails || !src) return; try { - editor.storage[nodeType][nodeFileSetDetails.fileSetName]?.set(src, true); + // @ts-expect-error add proper types for storage + editor.storage[nodeType]?.[nodeFileSetDetails.fileSetName]?.set(src, true); // update assets list storage value editor.commands.updateAssetsList?.({ idToRemove: node.attrs.id, diff --git a/packages/editor/src/core/plugins/file/restore.ts b/packages/editor/src/core/plugins/file/restore.ts index bb4eb2afb..87da43711 100644 --- a/packages/editor/src/core/plugins/file/restore.ts +++ b/packages/editor/src/core/plugins/file/restore.ts @@ -1,7 +1,7 @@ -import { Editor } from "@tiptap/core"; -import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; -// constants -import { CORE_EXTENSIONS } from "@/constants/extension"; +import type { Editor } from "@tiptap/core"; +import { type EditorState, Plugin, PluginKey, type Transaction } from "@tiptap/pm/state"; +// plane imports +import { CORE_EXTENSIONS } from "@plane/utils"; // helpers import { CORE_ASSETS_META_DATA_RECORD } from "@/helpers/assets"; // plane editor imports @@ -9,6 +9,7 @@ import { NODE_FILE_MAP } from "@/plane-editor/constants/utility"; // types import { TFileHandler } from "@/types"; // local imports +import type { NodeFileMapType } from "../../../ce/constants/utility"; import { TFileNode } from "./types"; const RESTORE_PLUGIN_KEY = new PluginKey("restore-utility"); @@ -23,7 +24,7 @@ export const TrackFileRestorationPlugin = (editor: Editor, restoreHandler: TFile [key: string]: Set | undefined; } = {}; oldState.doc.descendants((node) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const nodeFileSetDetails = NODE_FILE_MAP[nodeType]; if (nodeFileSetDetails) { if (oldFileSources[nodeType]) { @@ -38,7 +39,7 @@ export const TrackFileRestorationPlugin = (editor: Editor, restoreHandler: TFile const addedFiles: TFileNode[] = []; newState.doc.descendants((node, pos) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const isAValidNode = NODE_FILE_MAP[nodeType]; // if the node doesn't match, then return as no point in checking if (!isAValidNode) return; @@ -58,9 +59,11 @@ export const TrackFileRestorationPlugin = (editor: Editor, restoreHandler: TFile }); addedFiles.forEach(async (node) => { - const nodeType = node.type.name; + const nodeType = node.type.name as keyof NodeFileMapType; const src = node.attrs.src; const nodeFileSetDetails = NODE_FILE_MAP[nodeType]; + if (!nodeFileSetDetails) return; + // @ts-expect-error add proper types for storage const extensionFileSetStorage = editor.storage[nodeType]?.[nodeFileSetDetails.fileSetName]; const wasDeleted = extensionFileSetStorage?.get(src); if (!nodeFileSetDetails || !src) return; diff --git a/packages/editor/src/core/plugins/markdown-clipboard.ts b/packages/editor/src/core/plugins/markdown-clipboard.ts index 78f649b23..7eda09eea 100644 --- a/packages/editor/src/core/plugins/markdown-clipboard.ts +++ b/packages/editor/src/core/plugins/markdown-clipboard.ts @@ -9,6 +9,7 @@ export const MarkdownClipboardPlugin = (editor: Editor): Plugin => key: new PluginKey("markdownClipboard"), props: { clipboardTextSerializer: (slice) => { + // @ts-expect-error tiptap-markdown types are not updated const markdownSerializer = editor.storage.markdown.serializer; const isTableRow = slice.content.firstChild?.type?.name === CORE_EXTENSIONS.TABLE_ROW; const nodeSelect = slice.openStart === 0 && slice.openEnd === 0; diff --git a/packages/editor/src/styles/table.css b/packages/editor/src/styles/table.css index c2c013d77..ef9534866 100644 --- a/packages/editor/src/styles/table.css +++ b/packages/editor/src/styles/table.css @@ -143,61 +143,6 @@ } /* End column resizer */ -.table-wrapper .table-controls { - position: absolute; - - .columns-control, - .rows-control { - transition: opacity ease-in 100ms; - position: absolute; - z-index: 5; - display: flex; - justify-content: center; - align-items: center; - } - - .columns-control { - height: 20px; - transform: translateY(-50%); - - .columns-control-div { - color: white; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath fill='%238F95B2' d='M4.5 10.5c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S6 12.825 6 12s-.675-1.5-1.5-1.5zm15 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S21 12.825 21 12s-.675-1.5-1.5-1.5zm-7.5 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5 1.5-.675 1.5-1.5-.675-1.5-1.5-1.5z'/%3E%3C/svg%3E"); - width: 30px; - height: 15px; - } - } - - .rows-control { - width: 20px; - transform: translateX(-50%); - left: -8px; - - .rows-control-div { - color: white; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath fill='%238F95B2' d='M12 3c-.825 0-1.5.675-1.5 1.5S11.175 6 12 6s1.5-.675 1.5-1.5S12.825 3 12 3zm0 15c-.825 0-1.5.675-1.5 1.5S11.175 21 12 21s1.5-.675 1.5-1.5S12.825 18 12 18zm0-7.5c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5 1.5-.675 1.5-1.5-.675-1.5-1.5-1.5z'/%3E%3C/svg%3E"); - height: 30px; - width: 15px; - } - } - - .columns-control-div, - .rows-control-div { - background-color: rgba(var(--color-background-80)); - border: 0.5px solid rgba(var(--color-border-200)); - border-radius: 4px; - background-size: 1.25rem; - background-repeat: no-repeat; - background-position: center; - transition: - transform ease-out 100ms, - background-color ease-out 100ms; - outline: none; - box-shadow: rgba(var(--color-shadow-2xs)); - cursor: pointer; - } -} - .resize-cursor .table-wrapper .table-controls .rows-control, .table-wrapper.controls--disabled .table-controls .rows-control, .resize-cursor .table-wrapper .table-controls .columns-control, diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json index 70029ef19..3c0bf07ff 100644 --- a/packages/editor/tsconfig.json +++ b/packages/editor/tsconfig.json @@ -5,10 +5,10 @@ "module": "ESNext", "moduleResolution": "bundler", "noEmit": true, + "strict": true, "skipLibCheck": true, "sourceMap": true, "target": "ESNext", - "baseUrl": ".", "paths": { "@/*": ["./src/core/*"], diff --git a/packages/editor/tsdown.config.ts b/packages/editor/tsdown.config.ts index 5e9a7b960..90b213cd2 100644 --- a/packages/editor/tsdown.config.ts +++ b/packages/editor/tsdown.config.ts @@ -7,5 +7,6 @@ export default defineConfig({ dts: true, clean: false, sourcemap: true, + minify: true, copy: ["src/styles"], }); diff --git a/packages/utils/src/editor.ts b/packages/utils/src/editor.ts index 69fb73b8b..4f770b9d8 100644 --- a/packages/utils/src/editor.ts +++ b/packages/utils/src/editor.ts @@ -50,3 +50,51 @@ export const isEditorEmpty = (description: string | undefined): boolean => description === "

" || description === `

` || description.trim() === ""; + +export enum CORE_EXTENSIONS { + BLOCKQUOTE = "blockquote", + BOLD = "bold", + BULLET_LIST = "bulletList", + CALLOUT = "calloutComponent", + CHARACTER_COUNT = "characterCount", + CODE_BLOCK = "codeBlock", + CODE_INLINE = "code", + CUSTOM_COLOR = "customColor", + CUSTOM_IMAGE = "imageComponent", + CUSTOM_LINK = "link", + DOCUMENT = "doc", + DROP_CURSOR = "dropCursor", + ENTER_KEY = "enterKey", + GAP_CURSOR = "gapCursor", + HARD_BREAK = "hardBreak", + HEADING = "heading", + HEADINGS_LIST = "headingsList", + HISTORY = "history", + HORIZONTAL_RULE = "horizontalRule", + IMAGE = "image", + ITALIC = "italic", + LIST_ITEM = "listItem", + MARKDOWN_CLIPBOARD = "markdownClipboard", + MENTION = "mention", + ORDERED_LIST = "orderedList", + PARAGRAPH = "paragraph", + PLACEHOLDER = "placeholder", + SIDE_MENU = "editorSideMenu", + SLASH_COMMANDS = "slash-command", + STRIKETHROUGH = "strike", + TABLE = "table", + TABLE_CELL = "tableCell", + TABLE_HEADER = "tableHeader", + TABLE_ROW = "tableRow", + TASK_ITEM = "taskItem", + TASK_LIST = "taskList", + TEXT_ALIGN = "textAlign", + TEXT_STYLE = "textStyle", + TYPOGRAPHY = "typography", + UNDERLINE = "underline", + UTILITY = "utility", + WORK_ITEM_EMBED = "issue-embed-component", + EMOJI = "emoji", +} + +export enum ADDITIONAL_EXTENSIONS {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c974098e..9a0f07ccf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,12 @@ settings: catalogs: default: + '@tiptap/core': + specifier: ^3.5.3 + version: 3.5.3 + '@tiptap/html': + specifier: ^3.5.3 + version: 3.5.3 '@types/lodash-es': specifier: 4.17.12 version: 4.17.12 @@ -213,11 +219,11 @@ importers: specifier: workspace:* version: link:../../packages/types '@tiptap/core': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/pm@2.26.1) + specifier: 'catalog:' + version: 3.5.3(@tiptap/pm@3.5.3) '@tiptap/html': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: 'catalog:' + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(happy-dom@18.0.1) axios: specifier: 'catalog:' version: 1.12.0 @@ -254,9 +260,12 @@ importers: uuid: specifier: 'catalog:' version: 10.0.0 + ws: + specifier: ^8.18.3 + version: 8.18.3 y-prosemirror: - specifier: ^1.2.15 - version: 1.3.6(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + specifier: ^1.3.7 + version: 1.3.7(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) y-protocols: specifier: ^1.0.6 version: 1.0.6(yjs@13.6.27) @@ -297,24 +306,12 @@ importers: '@types/ws': specifier: ^8.18.1 version: 8.18.1 - concurrently: - specifier: ^9.0.1 - version: 9.1.2 - nodemon: - specifier: ^3.1.7 - version: 3.1.10 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.13.3(@swc/helpers@0.5.17))(@types/node@20.19.11)(typescript@5.8.3) tsdown: specifier: 'catalog:' version: 0.14.2(typescript@5.8.3) typescript: specifier: 5.8.3 version: 5.8.3 - ws: - specifier: ^8.18.3 - version: 8.18.3 apps/space: dependencies: @@ -733,62 +730,56 @@ importers: specifier: workspace:* version: link:../utils '@tiptap/core': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/pm@2.26.1) + specifier: 'catalog:' + version: 3.5.3(@tiptap/pm@3.5.3) '@tiptap/extension-blockquote': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-character-count': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) '@tiptap/extension-collaboration': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(y-prosemirror@1.3.6(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/y-tiptap@3.0.0(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(yjs@13.6.27) '@tiptap/extension-emoji': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(@tiptap/suggestion@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1))(emojibase@16.0.0) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/suggestion@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))(emojibase@16.0.0) '@tiptap/extension-image': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) '@tiptap/extension-list-item': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) '@tiptap/extension-mention': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(@tiptap/suggestion@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)) - '@tiptap/extension-placeholder': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/suggestion@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) '@tiptap/extension-task-item': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) '@tiptap/extension-task-list': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) '@tiptap/extension-text-align': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) '@tiptap/extension-text-style': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-underline': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extensions': + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) '@tiptap/html': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: 'catalog:' + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(happy-dom@18.0.1) '@tiptap/pm': - specifier: ^2.22.3 - version: 2.26.1 + specifier: ^3.5.3 + version: 3.5.3 '@tiptap/react': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^3.5.3 + version: 3.5.3(@floating-ui/dom@1.7.2)(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@types/react-dom@18.3.1)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tiptap/starter-kit': - specifier: ^2.22.3 - version: 2.26.1 + specifier: ^3.5.3 + version: 3.5.3 '@tiptap/suggestion': - specifier: ^2.22.3 - version: 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + specifier: ^3.5.3 + version: 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) emoji-regex: specifier: ^10.3.0 version: 10.4.0 @@ -823,8 +814,8 @@ importers: specifier: ^6.3.7 version: 6.3.7 tiptap-markdown: - specifier: ^0.8.10 - version: 0.8.10(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) + specifier: ^0.9.0 + version: 0.9.0(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) uuid: specifier: 'catalog:' version: 10.0.0 @@ -859,6 +850,9 @@ importers: '@types/react-dom': specifier: 'catalog:' version: 18.3.1 + '@types/uuid': + specifier: ^8.3.4 + version: 8.3.4 postcss: specifier: ^8.4.38 version: 8.5.6 @@ -3180,207 +3174,224 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tiptap/core@2.26.1': - resolution: {integrity: sha512-fymyd/XZvYiHjBoLt1gxs024xP/LY26d43R1vluYq7AHBL/7DE3ywzy+1GEsGyAv5Je2L0KBhNIR/izbq3Kaqg==} + '@tiptap/core@3.5.3': + resolution: {integrity: sha512-T09yWx2k4VB3mIXY/dw5YAZemkL2lXSCAIGaNFvvvyLObzMjE7gJN9VfO4VRQmNTcKSrt2IZgYHGuBvq2CUyvw==} peerDependencies: - '@tiptap/pm': ^2.7.0 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-blockquote@2.26.1': - resolution: {integrity: sha512-viQ6AHRhjCYYipKK6ZepBzwZpkuMvO9yhRHeUZDvlSOAh8rvsUTSre0y74nu8QRYUt4a44lJJ6BpphJK7bEgYA==} + '@tiptap/extension-blockquote@3.5.3': + resolution: {integrity: sha512-OHtt3eAc1lp97Ic2rJoGoMtoebO4+q5esCmAHpmKVGa64D/xDlp1OHHtS/6vIgp+FdydyFuQteb83h7x5wkWkA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-bold@2.26.1': - resolution: {integrity: sha512-zCce9PRuTNhadFir71luLo99HERDpGJ0EEflGm7RN8I1SnNi9gD5ooK42BOIQtejGCJqg3hTPZiYDJC2hXvckQ==} + '@tiptap/extension-bold@3.5.3': + resolution: {integrity: sha512-6JSHrL2tWwSfnmrXAcTLhEBlNJSTHs/1hdNXThRld9I1XfoJKC3kcCZlDtiab9BgsZwrqP0QCnDtrhOW8ZbeWw==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-bubble-menu@2.26.1': - resolution: {integrity: sha512-oHevUcZbTMFOTpdCEo4YEDe044MB4P1ZrWyML8CGe5tnnKdlI9BN03AXpI1mEEa5CA3H1/eEckXx8EiCgYwQ3Q==} + '@tiptap/extension-bubble-menu@3.5.3': + resolution: {integrity: sha512-cstoEbLzGQ4WfYhsYxUZroVtdxAJ2zKBk0+z9CxRoSO2CXvK+9zEe65Nu/yj04W/Rii8E0OlRvUsS+HUlfCRvQ==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-bullet-list@2.26.1': - resolution: {integrity: sha512-HHakuV4ckYCDOnBbne088FvCEP4YICw+wgPBz/V2dfpiFYQ4WzT0LPK9s7OFMCN+ROraoug+1ryN1Z1KdIgujQ==} + '@tiptap/extension-bullet-list@3.5.3': + resolution: {integrity: sha512-hf1qE0tca3i5UksJ0Z9ko0eh0kv1slSysPO2bw87J/un/eU0ebqjJmFxCWfvOxbPnfy5cTvy7EanEEHvMx9LGQ==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-character-count@2.26.1': - resolution: {integrity: sha512-F7LP1a9GF28thbApowWT2I41baqX74HMUTrV9LGrNXaOkW2gxZz+CDOzfHsbHyfuwfIxIjv07Qf/HKA6Cc1qbA==} + '@tiptap/extension-code-block@3.5.3': + resolution: {integrity: sha512-DSk44pQrnGl5csaHVp6Pe10xFjsT9LQvNBK1d/DDUUyXFpCf1UoVkuPksWPR37BGRENrBT8bz7RbpAl9J0Aa3g==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-code-block@2.26.1': - resolution: {integrity: sha512-/TDDOwONl0qEUc4+B6V9NnWtSjz95eg7/8uCb8Y8iRbGvI9vT4/znRKofFxstvKmW4URu/H74/g0ywV57h0B+A==} + '@tiptap/extension-code@3.5.3': + resolution: {integrity: sha512-GeVvT2fXuspqfWUU0ib6MRNw0GpIeu+lILBB+YcJJOdQlp06Vv+tG1GTNUd3LWsYKWBsP32IpWa3c/HurHJ5jA==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-code@2.26.1': - resolution: {integrity: sha512-GU9deB1A/Tr4FMPu71CvlcjGKwRhGYz60wQ8m4aM+ELZcVIcZRa1ebR8bExRIEWnvRztQuyRiCQzw2N0xQJ1QQ==} + '@tiptap/extension-collaboration@3.5.3': + resolution: {integrity: sha512-XecSpvZ6kZHICXO8vxo28B3ZMdO/hWoN/nE/YfVkXDNORFjuGcJsyME6IbTl4QkUh+gDrwLYAfSa0j8ZBToHvw==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + '@tiptap/y-tiptap': ^3.0.0-beta.3 + yjs: ^13 - '@tiptap/extension-collaboration@2.26.1': - resolution: {integrity: sha512-ozCrGW5IAzi/18Ngdi0v/Q175D7J3ZGoTffDDyPxnTK/oksfROajoe+ZIEgoDGXPeI/I7TTlTONuqQ6LZT5r7Q==} + '@tiptap/extension-document@3.6.2': + resolution: {integrity: sha512-4qg3KWL3aO1M7hfDpZR6/vSo7Cfqr3McyGUfqb/BXqYDW1DwT8jJkDTcHrGU7WUKRlWgoyPyzM8pZiGlP0uQHg==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 - y-prosemirror: ^1.2.11 + '@tiptap/core': ^3.6.2 - '@tiptap/extension-document@2.26.1': - resolution: {integrity: sha512-2P2IZp1NRAE+21mRuFBiP3X2WKfZ6kUC23NJKpn8bcOamY3obYqCt0ltGPhE4eR8n8QAl2fI/3jIgjR07dC8ow==} + '@tiptap/extension-dropcursor@3.5.3': + resolution: {integrity: sha512-isEw/VbEmlmDAxWTxZMR/eChGT1Y0zm7LSWyFhyFdUMjddv7yHL0NYrYLVuQahbTSOwu+N66CFi/PV1AV1BLlA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extensions': ^3.5.3 - '@tiptap/extension-dropcursor@2.26.1': - resolution: {integrity: sha512-JkDQU2ZYFOuT5mNYb8OiWGwD1HcjbtmX8tLNugQbToECmz9WvVPqJmn7V/q8VGpP81iEECz/IsyRmuf2kSD4uA==} + '@tiptap/extension-emoji@3.5.3': + resolution: {integrity: sha512-ykw3SnUfBEZdn6caAjXqSiMHX8XqE3EDgvIPSZY8ElEgznP1AND81v6ZV2MKb1Y4lC7+EVUFhL3iph454IYYvg==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + '@tiptap/suggestion': ^3.5.3 - '@tiptap/extension-emoji@2.26.1': - resolution: {integrity: sha512-CtK10GF80Qr4lgJ7P6W6tVThOjpq1lh8oyoBospZ+CjD4GYcY73bdl+FP0uxhZdJsMHzaqzMP5wWQ54zHsIaIg==} + '@tiptap/extension-floating-menu@3.5.3': + resolution: {integrity: sha512-GObcggzjPkaCKity4DE/4Cks6rqN7p/LGFINSlmL2sPs5/6IRcrJkCHpYUKH7aTRovIzYheudUSrIIc45M6eJw==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 - '@tiptap/suggestion': ^2.7.0 + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-floating-menu@2.26.1': - resolution: {integrity: sha512-OJF+H6qhQogVTMedAGSWuoL1RPe3LZYXONuFCVyzHnvvMpK+BP1vm180E2zDNFnn/DVA+FOrzNGpZW7YjoFH1w==} + '@tiptap/extension-gapcursor@3.5.3': + resolution: {integrity: sha512-6Bg+Elcz87amXF7VnkVGx/sPWWWiH5Ipnk+W8JDTdLBv8afxUOvdt/r9FnRGIGKYKDVkxio5pv68vEeqQ4AEsw==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/extensions': ^3.5.3 - '@tiptap/extension-gapcursor@2.26.1': - resolution: {integrity: sha512-KOiMZc3PwJS3hR0nSq5d0TJi2jkNZkLZElcT6pCEnhRHzPH6dRMu9GM5Jj798ZRUy0T9UFcKJalFZaDxnmRnpg==} + '@tiptap/extension-hard-break@3.5.3': + resolution: {integrity: sha512-0K5oB8jqE6+6PHE3aAlJsQ+CmyA77slBTj62vDCht9FZTyoilxqYaXjKaBG2uX6FWW9HcSPnKUTj9TM9f+EE4g==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-hard-break@2.26.1': - resolution: {integrity: sha512-d6uStdNKi8kjPlHAyO59M6KGWATNwhLCD7dng0NXfwGndc22fthzIk/6j9F6ltQx30huy5qQram6j3JXwNACoA==} + '@tiptap/extension-heading@3.5.3': + resolution: {integrity: sha512-cmA9OjBKH9RDzwyzJq/3DYCAWEqmDje7uJcICmCkfE12pp/GfdqW5prwnp8Frj+ImOYuARhxYRYLO+6thRYgtg==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-heading@2.26.1': - resolution: {integrity: sha512-KSzL8WZV3pjJG9ke4RaU70+B5UlYR2S6olNt5UCAawM+fi11mobVztiBoC19xtpSVqIXC1AmXOqUgnuSvmE4ZA==} + '@tiptap/extension-horizontal-rule@3.5.3': + resolution: {integrity: sha512-+gydDHZlAmeqKlWO/pGP4XjTgZuynSpAAf2yK9HGHp8WLqRCbyqWU2T3NCbL5/E51xclaw7j7KUacnpeVlRsgA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-history@2.26.1': - resolution: {integrity: sha512-m6YR1gkkauIDo3PRl0gP+7Oc4n5OqDzcjVh6LvWREmZP8nmi94hfseYbqOXUb6RPHIc0JKF02eiRifT4MSd2nw==} + '@tiptap/extension-image@3.5.3': + resolution: {integrity: sha512-hWGW0CcWa6rftZInrIwHxswHSXdm0xlplqohEvGqIvh+fI1vklYcA/UyJg0bwLtyVozPwihch869okPZbTFTag==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-horizontal-rule@2.26.1': - resolution: {integrity: sha512-mT6baqOhs/NakgrAeDeed194E/ZJFGL692H0C7f1N7WDRaWxUu2oR0LrnRqSH5OyPjELkzu6nQnNy0+0tFGHHg==} + '@tiptap/extension-italic@3.5.3': + resolution: {integrity: sha512-3E/6SY878Bv/Psw1CwIgj/VOJRrbdxPjGrqI6ZK4LFpdTR7aR4QE0rXcWR9h2ZWRS8fsiTGDwfyPncoQc36TvQ==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-image@2.26.1': - resolution: {integrity: sha512-96+MaYBJebQlR/ik5W72GLUfXdEoxFs+6jsoERxbM5qEdhb7TEnodBFtWZOwgDO27kFd6rSNZuW9r5KJNtljEg==} + '@tiptap/extension-link@3.5.3': + resolution: {integrity: sha512-I9pxEh1XvRK1JrZWaq0+n/fgCbdN5+A+6Jh/VTihhFXPmv93gGPAmTc3ma70iHL8I6K39kUh00ssSbQmV/8SmQ==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-italic@2.26.1': - resolution: {integrity: sha512-pOs6oU4LyGO89IrYE4jbE8ZYsPwMMIiKkYfXcfeD9NtpGNBnjeVXXF5I9ndY2ANrCAgC8k58C3/powDRf0T2yA==} + '@tiptap/extension-list-item@3.5.3': + resolution: {integrity: sha512-lOj9LWcuIPOUAJo7fCQSDQcjPJDvlTXtTzcBfBy4BQsTN8HUlNPv2zyWTIZ9uMoYNKc7cwkZateDpj0BP34fIA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-list-item@2.26.1': - resolution: {integrity: sha512-quOXckC73Luc3x+Dcm88YAEBW+Crh3x5uvtQOQtn2GEG91AshrvbnhGRiYnfvEN7UhWIS+FYI5liHFcRKSUKrQ==} + '@tiptap/extension-list-keymap@3.5.3': + resolution: {integrity: sha512-YaqZBK15qmPIYIZrrsWmtcLC3CcPLFFU4D4mJr6g0+lfPRiJdGEljnW8OR0Rvh7Z+4MA6DjmqDdIKKIvqGsUJw==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-mention@2.26.1': - resolution: {integrity: sha512-sBrlJ9nWjFx7oWCtt0hV192FgCBXva1zwImWbgXTCGPAjv0d5EoPymIfRgoeanAmuQjOHoKzzZnJ6bELTZhkGw==} + '@tiptap/extension-list@3.5.3': + resolution: {integrity: sha512-I4qb2w0DFt/ZcNXcnRm74ja9m9ziURFUK/oF0VSJAxnKanCQ6cke9Yet+zfSdHSUuNbbi0yFz1xdWAPtxImOxw==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 - '@tiptap/suggestion': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/extension-ordered-list@2.26.1': - resolution: {integrity: sha512-UHKNRxq6TBnXMGFSq91knD6QaHsyyOwLOsXMzupmKM5Su0s+CRXEjfav3qKlbb9e4m7D7S/a0aPm8nC9KIXNhQ==} + '@tiptap/extension-mention@3.5.3': + resolution: {integrity: sha512-KFw3ntbznB9UHT10RkyqrEKCROHZ7cLXnQpEuNyFh5rX6Z9PEt1iDiUHN6J1QDooOj8YNTQwNXkNR6s40NLc/w==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + '@tiptap/suggestion': ^3.5.3 - '@tiptap/extension-paragraph@2.26.1': - resolution: {integrity: sha512-UezvM9VDRAVJlX1tykgHWSD1g3MKfVMWWZ+Tg+PE4+kizOwoYkRWznVPgCAxjmyHajxpCKRXgqTZkOxjJ9Kjzg==} + '@tiptap/extension-ordered-list@3.5.3': + resolution: {integrity: sha512-gX73It1V3wncbwvU2UCTdjfkoUVXL87yXEO6FAztFvsr8agggBy8kBagUHuMZekO56rXJMDPaI/p4tw1rPy+fw==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-placeholder@2.26.1': - resolution: {integrity: sha512-MBlqbkd+63btY7Qu+SqrXvWjPwooGZDsLTtl7jp52BczBl61cq9yygglt9XpM11TFMBdySgdLHBrLtQ0B7fBlw==} + '@tiptap/extension-paragraph@3.5.3': + resolution: {integrity: sha512-6yFNl0V3zC/Ggqt/aFgpDFCi58W8mC9hFgWUF146tW9HpAJsGwyted3+4LGfrZf1C64FVRDRXN51xsubrV1iMQ==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-strike@2.26.1': - resolution: {integrity: sha512-CkoRH+pAi6MgdCh7K0cVZl4N2uR4pZdabXAnFSoLZRSg6imLvEUmWHfSi1dl3Z7JOvd3a4yZ4NxerQn5MWbJ7g==} + '@tiptap/extension-strike@3.5.3': + resolution: {integrity: sha512-j/Mj0CzzA7hBk4VPqoS8I/cSyAyCoaNyCBdIfAleAKdQ8MREDXKySJn1X9wLz9V8kdaF14FPG7POBWaJGHDgeg==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-task-item@2.26.1': - resolution: {integrity: sha512-b7JNeOsBqEd1p2oQ5N6Msz9fr2o73WR1WsYDC0WhECg07Goud2gQEkwWkQaLsvfcwuS746eMJK/nrT2pVEngYA==} + '@tiptap/extension-task-item@3.5.3': + resolution: {integrity: sha512-LcXzLbwCSqwndJL2lSdFFx8yDzBtg3mydt0MbDs87AL0MLwkj7eBBpAc0Lh0cWNnycdlNwL08dDytY2E2eT9fw==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-task-list@2.26.1': - resolution: {integrity: sha512-xR4LMpMPZ6bpkZNmFvIojmNGtdGKNlKFbpvyIOgs4qhlWskbFQQVevglHjV1R8xJLic5c+byJQaAmQdQudqGng==} + '@tiptap/extension-task-list@3.5.3': + resolution: {integrity: sha512-3+vOOktyF5zFGdJiE4z9GD/K7lNGS1xp9AOowZJzkT1RvIQUiGe9nz+DPmYgoG3j0/mqdiKEaSo5VnS8rnzudQ==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/extension-list': ^3.5.3 - '@tiptap/extension-text-align@2.26.1': - resolution: {integrity: sha512-x6mpNGELy2QtSPBoQqNgiXO9PjZoB+O2EAfXA9YRiBDSIRNOrw+7vOVpi+IgzswFmhMNgIYUVfQRud4FHUCNew==} + '@tiptap/extension-text-align@3.5.3': + resolution: {integrity: sha512-O+YT9Z1loNhbUy34sMm9nXbATL5TNYIqaGYFCOJrV/YEMZGHjzBRXtUKLS/T6CY3HKCqAtg6mdMPAPQXRCh6mA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-text-style@2.26.1': - resolution: {integrity: sha512-t9Nc/UkrbCfnSHEUi1gvUQ2ZPzvfdYFT5TExoV2DTiUCkhG6+mecT5bTVFGW3QkPmbToL+nFhGn4ZRMDD0SP3Q==} + '@tiptap/extension-text-style@3.5.3': + resolution: {integrity: sha512-vrWUGE5TDtiQ2G8laWczfxLMq2XKASkZb2ecmVRf5XLzrhDlN2wpGMwIHaZrSTgRk5NitlW8Fjm/YqTd6HLlBA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-text@2.26.1': - resolution: {integrity: sha512-p2n8WVMd/2vckdJlol24acaTDIZAhI7qle5cM75bn01sOEZoFlSw6SwINOULrUCzNJsYb43qrLEibZb4j2LeQw==} + '@tiptap/extension-text@3.5.3': + resolution: {integrity: sha512-Y4LDjJp0/H7Y6XB+pclv4kZDv51VuLTYIMXZ/Jjas7sI3r2bl6prhx5NUY6zGlkJnUD1Ho1MMaY9AvgMzIq4BA==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/extension-underline@2.26.1': - resolution: {integrity: sha512-/fufv41WDMdf0a4xmFAxONoAz08TonJXX6NEoSJmuGKO59M/Y0Pz8DTK1g32Wk44kn7dyScDiPlvvndl+UOv0A==} + '@tiptap/extension-underline@3.5.3': + resolution: {integrity: sha512-Dp2yZl8uc1kIJokWMQjOyuCZk2OsqTc6OUCMPT1CzdF/MqGSiOmX+fWtcpVjwNiqb89ZwGA8W+C0zrVWEzAg/A==} peerDependencies: - '@tiptap/core': ^2.7.0 + '@tiptap/core': ^3.5.3 - '@tiptap/html@2.26.1': - resolution: {integrity: sha512-93keIjciRdjgQabxntXBjW6NTrAoM+uC/u3dwoM5CJFs40cpJC+/CEPYG7SJ5Cyv8srv/OqzyjCjoz7PQGvXyA==} + '@tiptap/extensions@3.5.3': + resolution: {integrity: sha512-bJGpa2FZAUPzwpBDL9vv9tg3j5cAprcRzrHmYhBW44NYmqaDOvLa4VewiUOxfgx0f8l8D9Hw6Lq0mH/UqPymbQ==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 - '@tiptap/pm@2.26.1': - resolution: {integrity: sha512-8aF+mY/vSHbGFqyG663ds84b+vca5Lge3tHdTMTKazxCnhXR9dn2oQJMnZ78YZvdRbkPkMJJHti9h3K7u2UQvw==} - - '@tiptap/react@2.26.1': - resolution: {integrity: sha512-Zxlwzi1iML7aELa+PyysFD2ncVo2mEcjTkhoDok9iTbMGpm1oU8hgR1i6iHrcSNQLfaRiW6M7HNhZZQPKIC9yw==} + '@tiptap/html@3.5.3': + resolution: {integrity: sha512-S6Uox1Gt3YQiiXYBZ6OT1XN2jyT/CZY+xwhuJYEP6s/lQkc3AXGxtvNZpuLbwNEDT0x/rSl66OZdtmv1nKia6g==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + happy-dom: ^18.0.1 + + '@tiptap/pm@3.5.3': + resolution: {integrity: sha512-bjZZ+0DzTH65Z8X7nTgOOYZwEa0MSHqybKrYWI8871/cYvzzBTL1R01IOWvkW5qXD6ZdqExHbaUNhICIrR8xNQ==} + + '@tiptap/react@3.5.3': + resolution: {integrity: sha512-mXKCmdhCn6v+FsIRAR5eS5CXyv7eoQ2FHti9N1v2Bj72jO0QVDaDdzKuJ3g2o36KwATVQ6x3FYCH5Mys+znAXQ==} + peerDependencies: + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@2.26.1': - resolution: {integrity: sha512-oziMGCds8SVQ3s5dRpBxVdEKZAmO/O//BjZ69mhA3q4vJdR0rnfLb5fTxSeQvHiqB878HBNn76kNaJrHrV35GA==} + '@tiptap/starter-kit@3.5.3': + resolution: {integrity: sha512-LS7fXxkCumBSoZnQhbTiK9aZRNH0EqHiI3Mpp8Mb1etm8g2XHdRVIKjwav3b2p0VrWqxTp8NMMcopOfolOawMw==} - '@tiptap/suggestion@2.26.1': - resolution: {integrity: sha512-iNWJdQN7h01keNoVwyCsdI7ZX11YkrexZjCnutWK17Dd72s3NYVTmQXu7saftwddT4nDdlczNxAFosrt0zMhcg==} + '@tiptap/suggestion@3.5.3': + resolution: {integrity: sha512-cJRjsG/xyeERTTQTDFlfm9BxP3jCnDM7algb019IXC0EpK366OL5tGEZnK5b+ttiwPLKXg05Hgw4dUgHE7GPVw==} peerDependencies: - '@tiptap/core': ^2.7.0 - '@tiptap/pm': ^2.7.0 + '@tiptap/core': ^3.5.3 + '@tiptap/pm': ^3.5.3 + + '@tiptap/y-tiptap@3.0.0': + resolution: {integrity: sha512-HIeJZCj+KYJde2x6fONzo4o6kd7gW7eonwhQsv2p2VQnUgwNXMVhN+D6Z3AH/2i541Sq33y1PO4U/1ThCPjqbA==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + prosemirror-model: ^1.7.1 + prosemirror-state: ^1.2.3 + prosemirror-view: 1.40.0 + y-protocols: ^1.0.1 + yjs: ^13.5.38 '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -3639,6 +3650,9 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -4415,11 +4429,6 @@ packages: compute-scroll-into-view@3.1.1: resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} - concurrently@9.1.2: - resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==} - engines: {node: '>=18'} - hasBin: true - constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} @@ -4868,10 +4877,6 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - entities@5.0.0: - resolution: {integrity: sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==} - engines: {node: '>=0.12'} - entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -5419,6 +5424,10 @@ packages: gud@1.0.0: resolution: {integrity: sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==} + happy-dom@18.0.1: + resolution: {integrity: sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==} + engines: {node: '>=20.0.0'} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -5550,9 +5559,6 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore-by-default@1.0.1: - resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -6302,11 +6308,6 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - nodemon@3.1.10: - resolution: {integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==} - engines: {node: '>=10'} - hasBin: true - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -6871,9 +6872,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pstree.remy@1.1.8: - resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -7214,9 +7212,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -7320,10 +7315,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -7350,10 +7341,6 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - slash@5.1.0: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} @@ -7660,10 +7647,10 @@ packages: tippy.js@6.3.7: resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} - tiptap-markdown@0.8.10: - resolution: {integrity: sha512-iDVkR2BjAqkTDtFX0h94yVvE2AihCXlF0Q7RIXSJPRSR5I0PA1TMuAg6FHFpmqTn4tPxJ0by0CK7PUMlnFLGEQ==} + tiptap-markdown@0.9.0: + resolution: {integrity: sha512-dKLQ9iiuGNgrlGVjrNauF/UBzWu4LYOx5pkD0jNkmQt/GOwfCJsBuzZTsf1jZ204ANHOm572mZ9PYvGh1S7tpQ==} peerDependencies: - '@tiptap/core': ^2.0.3 + '@tiptap/core': ^3.0.1 tlds@1.259.0: resolution: {integrity: sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==} @@ -7684,10 +7671,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - touch@3.1.1: - resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} - hasBin: true - tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -7858,9 +7841,6 @@ packages: unconfig@7.3.3: resolution: {integrity: sha512-QCkQoOnJF8L107gxfHL0uavn7WD9b3dpBcFX6HtfQYmjw2YzWxGuFQ0N0J6tE9oguCBJn9KOvfqYDCMPHIZrBA==} - undefsafe@2.0.5: - resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -8106,6 +8086,10 @@ packages: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} @@ -8213,6 +8197,16 @@ packages: y-protocols: ^1.0.1 yjs: ^13.5.38 + y-prosemirror@1.3.7: + resolution: {integrity: sha512-NpM99WSdD4Fx4if5xOMDpPtU3oAmTSjlzh5U4353ABbRHl1HtAFUx6HlebLZfyFxXN9jzKMDkVbcRjqOZVkYQg==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + prosemirror-model: ^1.7.1 + prosemirror-state: ^1.2.3 + prosemirror-view: 1.40.0 + y-protocols: ^1.0.1 + yjs: ^13.5.38 + y-protocols@1.0.6: resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -8262,10 +8256,6 @@ packages: yoga-layout@2.0.1: resolution: {integrity: sha512-tT/oChyDXelLo2A+UVnlW9GU7CsvFMaEnd9kVFsaiCQonFAXd3xrHhkLYu+suwwosrAEQ746xBU+HvYtm1Zs2Q==} - zeed-dom@0.15.1: - resolution: {integrity: sha512-dtZ0aQSFyZmoJS0m06/xBN1SazUBPL5HpzlAcs/KcRW0rzadYw12deQBjeMhGKMMeGEp7bA9vmikMLaO4exBcg==} - engines: {node: '>=14.13.1'} - zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -8325,7 +8315,7 @@ snapshots: '@babel/traverse': 7.28.3 '@babel/types': 7.28.2 convert-source-map: 2.0.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8399,7 +8389,7 @@ snapshots: '@babel/parser': 7.28.3 '@babel/template': 7.27.2 '@babel/types': 7.28.2 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -8508,6 +8498,7 @@ snapshots: '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 + optional: true '@csstools/color-helpers@5.0.2': {} @@ -8742,7 +8733,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -8894,7 +8885,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -9034,6 +9025,7 @@ snapshots: dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + optional: true '@juggle/resize-observer@3.4.0': {} @@ -9926,7 +9918,7 @@ snapshots: '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.3)(webpack@5.101.3(@swc/core@1.13.3(@swc/helpers@0.5.17))(esbuild@0.25.0))': dependencies: - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -10158,164 +10150,169 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 - '@tiptap/core@2.26.1(@tiptap/pm@2.26.1)': + '@tiptap/core@3.5.3(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/pm': 2.26.1 + '@tiptap/pm': 3.5.3 - '@tiptap/extension-blockquote@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-blockquote@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-bold@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-bold@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-bubble-menu@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-bubble-menu@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - tippy.js: 6.3.7 + '@floating-ui/dom': 1.7.3 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + optional: true - '@tiptap/extension-bullet-list@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-bullet-list@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-character-count@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-code-block@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 - '@tiptap/extension-code-block@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-code@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-code@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-collaboration@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/y-tiptap@3.0.0(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))(yjs@13.6.27)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + '@tiptap/y-tiptap': 3.0.0(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + yjs: 13.6.27 - '@tiptap/extension-collaboration@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(y-prosemirror@1.3.6(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27))': + '@tiptap/extension-document@3.6.2(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - y-prosemirror: 1.3.6(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-document@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-dropcursor@3.5.3(@tiptap/extensions@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/extensions': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-dropcursor@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-emoji@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/suggestion@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))(emojibase@16.0.0)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - - '@tiptap/extension-emoji@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(@tiptap/suggestion@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1))(emojibase@16.0.0)': - dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - '@tiptap/suggestion': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + '@tiptap/suggestion': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) emoji-regex: 10.4.0 emojibase-data: 15.3.2(emojibase@16.0.0) is-emoji-supported: 0.0.5 transitivePeerDependencies: - emojibase - '@tiptap/extension-floating-menu@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-floating-menu@3.5.3(@floating-ui/dom@1.7.2)(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - tippy.js: 6.3.7 + '@floating-ui/dom': 1.7.2 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + optional: true - '@tiptap/extension-gapcursor@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-gapcursor@3.5.3(@tiptap/extensions@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/extensions': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-hard-break@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-hard-break@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-heading@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-heading@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-history@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-horizontal-rule@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 - '@tiptap/extension-horizontal-rule@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-image@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-image@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-italic@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-italic@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-link@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + linkifyjs: 4.3.2 - '@tiptap/extension-list-item@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-list-item@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-mention@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(@tiptap/suggestion@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1))': + '@tiptap/extension-list-keymap@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - '@tiptap/suggestion': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-ordered-list@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 - '@tiptap/extension-paragraph@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-mention@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@tiptap/suggestion@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + '@tiptap/suggestion': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-placeholder@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-ordered-list@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-strike@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-paragraph@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-task-item@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-strike@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-task-list@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-task-item@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-text-align@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-task-list@3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) - '@tiptap/extension-text-style@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-text-align@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-text@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-text-style@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/extension-underline@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))': + '@tiptap/extension-text@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/html@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/extension-underline@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 - zeed-dom: 0.15.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) - '@tiptap/pm@2.26.1': + '@tiptap/extensions@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': + dependencies: + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + + '@tiptap/html@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(happy-dom@18.0.1)': + dependencies: + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + happy-dom: 18.0.1 + + '@tiptap/pm@3.5.3': dependencies: prosemirror-changeset: 2.3.1 prosemirror-collab: 1.3.1 @@ -10336,54 +10333,75 @@ snapshots: prosemirror-transform: 1.10.4 prosemirror-view: 1.40.0 - '@tiptap/react@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tiptap/react@3.5.3(@floating-ui/dom@1.7.2)(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)(@types/react-dom@18.3.1)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/extension-bubble-menu': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-floating-menu': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 + '@types/react': 18.3.11 + '@types/react-dom': 18.3.1 '@types/use-sync-external-store': 0.0.6 fast-deep-equal: 3.1.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) + optionalDependencies: + '@tiptap/extension-bubble-menu': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/extension-floating-menu': 3.5.3(@floating-ui/dom@1.7.2)(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + transitivePeerDependencies: + - '@floating-ui/dom' - '@tiptap/starter-kit@2.26.1': + '@tiptap/starter-kit@3.5.3': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/extension-blockquote': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-bold': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-bullet-list': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-code': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-code-block': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-document': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-dropcursor': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-gapcursor': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-hard-break': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-heading': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-history': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-horizontal-rule': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1) - '@tiptap/extension-italic': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-list-item': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-ordered-list': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-paragraph': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-strike': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-text': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/extension-text-style': 2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/extension-blockquote': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-bold': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-bullet-list': 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-code': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-code-block': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/extension-document': 3.6.2(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-dropcursor': 3.5.3(@tiptap/extensions@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-gapcursor': 3.5.3(@tiptap/extensions@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-hard-break': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-heading': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-horizontal-rule': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/extension-italic': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-link': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/extension-list': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/extension-list-item': 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-list-keymap': 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-ordered-list': 3.5.3(@tiptap/extension-list@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)) + '@tiptap/extension-paragraph': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-strike': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-text': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extension-underline': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)) + '@tiptap/extensions': 3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 - '@tiptap/suggestion@2.26.1(@tiptap/core@2.26.1(@tiptap/pm@2.26.1))(@tiptap/pm@2.26.1)': + '@tiptap/suggestion@3.5.3(@tiptap/core@3.5.3(@tiptap/pm@3.5.3))(@tiptap/pm@3.5.3)': dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) - '@tiptap/pm': 2.26.1 + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) + '@tiptap/pm': 3.5.3 - '@tsconfig/node10@1.0.11': {} + '@tiptap/y-tiptap@3.0.0(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27)': + dependencies: + lib0: 0.2.114 + prosemirror-model: 1.25.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.40.0 + y-protocols: 1.0.6(yjs@13.6.27) + yjs: 13.6.27 - '@tsconfig/node12@1.0.11': {} + '@tsconfig/node10@1.0.11': + optional: true - '@tsconfig/node14@1.0.3': {} + '@tsconfig/node12@1.0.11': + optional: true - '@tsconfig/node16@1.0.4': {} + '@tsconfig/node14@1.0.3': + optional: true + + '@tsconfig/node16@1.0.4': + optional: true '@tybys/wasm-util@0.10.1': dependencies: @@ -10652,6 +10670,8 @@ snapshots: '@types/uuid@9.0.8': {} + '@types/whatwg-mimetype@3.0.2': {} + '@types/ws@8.18.1': dependencies: '@types/node': 20.19.11 @@ -10679,7 +10699,7 @@ snapshots: '@typescript-eslint/types': 8.40.0 '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.40.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 8.57.1 typescript: 5.8.3 transitivePeerDependencies: @@ -10689,7 +10709,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.8.3) '@typescript-eslint/types': 8.40.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -10698,7 +10718,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.8.3) '@typescript-eslint/types': 8.40.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -10726,7 +10746,7 @@ snapshots: '@typescript-eslint/types': 8.38.0 '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.8.3) '@typescript-eslint/utils': 8.38.0(eslint@8.57.1)(typescript@5.8.3) - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 8.57.1 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -10743,7 +10763,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.8.3) '@typescript-eslint/types': 8.38.0 '@typescript-eslint/visitor-keys': 8.38.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -10759,7 +10779,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.8.3) '@typescript-eslint/types': 8.40.0 '@typescript-eslint/visitor-keys': 8.40.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -11015,6 +11035,7 @@ snapshots: acorn-walk@8.3.4: dependencies: acorn: 8.15.0 + optional: true acorn@8.15.0: {} @@ -11074,7 +11095,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - arg@4.1.3: {} + arg@4.1.3: + optional: true arg@5.0.2: {} @@ -11518,16 +11540,6 @@ snapshots: compute-scroll-into-view@3.1.1: {} - concurrently@9.1.2: - dependencies: - chalk: 4.1.2 - lodash: 4.17.21 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - constant-case@3.0.4: dependencies: no-case: 3.0.4 @@ -11570,7 +11582,8 @@ snapshots: loose-envify: 1.4.0 object-assign: 4.1.1 - create-require@1.1.1: {} + create-require@1.1.1: + optional: true crelt@1.0.6: {} @@ -11712,11 +11725,9 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.1(supports-color@5.5.0): + debug@4.4.1: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 5.5.0 decimal.js-light@2.5.1: {} @@ -11787,7 +11798,8 @@ snapshots: didyoumean@1.2.2: {} - diff@4.0.2: {} + diff@4.0.2: + optional: true diff@5.2.0: {} @@ -11936,8 +11948,6 @@ snapshots: entities@4.5.0: {} - entities@5.0.0: {} - entities@6.0.1: {} error-ex@1.3.2: @@ -12049,7 +12059,7 @@ snapshots: esbuild-register@3.6.0(esbuild@0.25.0): dependencies: - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 esbuild: 0.25.0 transitivePeerDependencies: - supports-color @@ -12130,7 +12140,7 @@ snapshots: eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 8.57.1 get-tsconfig: 4.10.1 is-bun-module: 2.0.0 @@ -12272,7 +12282,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -12701,6 +12711,12 @@ snapshots: gud@1.0.0: {} + happy-dom@18.0.1: + dependencies: + '@types/node': 20.19.11 + '@types/whatwg-mimetype': 3.0.2 + whatwg-mimetype: 3.0.0 + has-bigints@1.1.0: {} has-flag@3.0.0: {} @@ -12798,14 +12814,14 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -12827,8 +12843,6 @@ snapshots: ieee754@1.2.1: {} - ignore-by-default@1.0.1: {} - ignore@5.3.2: {} ignore@7.0.5: {} @@ -12874,7 +12888,7 @@ snapshots: dependencies: '@ioredis/commands': 1.3.0 cluster-key-slot: 1.1.2 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 denque: 1.5.1 lodash.defaults: 4.2.0 lodash.flatten: 4.4.0 @@ -12890,7 +12904,7 @@ snapshots: dependencies: '@ioredis/commands': 1.3.0 cluster-key-slot: 1.1.2 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -13310,7 +13324,8 @@ snapshots: dependencies: semver: 6.3.1 - make-error@1.3.6: {} + make-error@1.3.6: + optional: true map-or-similar@1.5.0: {} @@ -13510,7 +13525,7 @@ snapshots: micromark@3.2.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 decode-named-character-reference: 1.2.0 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -13665,19 +13680,6 @@ snapshots: node-releases@2.0.19: {} - nodemon@3.1.10: - dependencies: - chokidar: 3.6.0 - debug: 4.4.1(supports-color@5.5.0) - ignore-by-default: 1.0.1 - minimatch: 3.1.2 - pstree.remy: 1.1.8 - semver: 7.7.2 - simple-update-notifier: 2.0.0 - supports-color: 5.5.0 - touch: 3.1.1 - undefsafe: 2.0.5 - normalize-path@3.0.0: {} normalize-range@0.1.2: {} @@ -14231,8 +14233,6 @@ snapshots: proxy-from-env@1.1.0: {} - pstree.remy@1.1.8: {} - pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -14622,7 +14622,7 @@ snapshots: '@babel/types': 7.28.2 ast-kit: 2.1.2 birpc: 2.5.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 dts-resolver: 2.1.2 get-tsconfig: 4.10.1 rolldown: 1.0.0-beta.34 @@ -14688,10 +14688,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - sade@1.8.1: dependencies: mri: 1.2.0 @@ -14852,8 +14848,6 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.8.3: {} - side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -14890,10 +14884,6 @@ snapshots: dependencies: is-arrayish: 0.3.2 - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.2 - slash@5.1.0: {} smooth-scroll-into-view-if-needed@2.0.2: @@ -15226,9 +15216,9 @@ snapshots: dependencies: '@popperjs/core': 2.11.8 - tiptap-markdown@0.8.10(@tiptap/core@2.26.1(@tiptap/pm@2.26.1)): + tiptap-markdown@0.9.0(@tiptap/core@3.5.3(@tiptap/pm@3.5.3)): dependencies: - '@tiptap/core': 2.26.1(@tiptap/pm@2.26.1) + '@tiptap/core': 3.5.3(@tiptap/pm@3.5.3) '@types/markdown-it': 13.0.9 markdown-it: 14.1.0 markdown-it-task-lists: 2.1.1 @@ -15248,8 +15238,6 @@ snapshots: toidentifier@1.0.1: {} - touch@3.1.1: {} - tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -15276,26 +15264,6 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@swc/core@1.13.3(@swc/helpers@0.5.17))(@types/node@20.19.11)(typescript@5.8.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.11 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optionalDependencies: - '@swc/core': 1.13.3(@swc/helpers@0.5.17) - ts-node@10.9.2(@swc/core@1.13.3(@swc/helpers@0.5.17))(@types/node@22.17.2)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -15335,7 +15303,7 @@ snapshots: ansis: 4.1.0 cac: 6.7.14 chokidar: 3.6.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 diff: 8.0.2 empathic: 2.0.0 hookable: 5.5.3 @@ -15451,8 +15419,6 @@ snapshots: jiti: 2.5.1 quansync: 0.2.11 - undefsafe@2.0.5: {} - undici-types@6.21.0: {} unicode-properties@1.4.1: @@ -15609,7 +15575,8 @@ snapshots: kleur: 4.1.5 sade: 1.8.1 - v8-compile-cache-lib@3.0.1: {} + v8-compile-cache-lib@3.0.1: + optional: true vary@1.1.2: {} @@ -15740,6 +15707,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-mimetype@3.0.0: {} + whatwg-mimetype@4.0.0: {} whatwg-url@14.2.0: @@ -15859,6 +15828,15 @@ snapshots: y-protocols: 1.0.6(yjs@13.6.27) yjs: 13.6.27 + y-prosemirror@1.3.7(prosemirror-model@1.25.3)(prosemirror-state@1.4.3)(prosemirror-view@1.40.0)(y-protocols@1.0.6(yjs@13.6.27))(yjs@13.6.27): + dependencies: + lib0: 0.2.114 + prosemirror-model: 1.25.3 + prosemirror-state: 1.4.3 + prosemirror-view: 1.40.0 + y-protocols: 1.0.6(yjs@13.6.27) + yjs: 13.6.27 + y-protocols@1.0.6(yjs@13.6.27): dependencies: lib0: 0.2.114 @@ -15888,7 +15866,8 @@ snapshots: dependencies: lib0: 0.2.114 - yn@3.1.1: {} + yn@3.1.1: + optional: true yocto-queue@0.1.0: {} @@ -15896,9 +15875,4 @@ snapshots: yoga-layout@2.0.1: {} - zeed-dom@0.15.1: - dependencies: - css-what: 6.2.2 - entities: 5.0.0 - zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ae83b7676..e33945c7b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -23,6 +23,8 @@ catalog: typescript: 5.8.3 tsdown: 0.14.2 uuid: 10.0.0 + "@tiptap/core": ^3.5.3 + "@tiptap/html": ^3.5.3 onlyBuiltDependencies: - turbo