Tiptap v3 upgrade - WIP

This commit is contained in:
Philipinho
2025-06-13 15:48:52 -07:00
parent 1c674efddd
commit 7a9be34811
24 changed files with 4299 additions and 5371 deletions

View File

@ -16,6 +16,7 @@
"@emoji-mart/data": "^1.2.1",
"@emoji-mart/react": "^1.1.1",
"@excalidraw/excalidraw": "0.18.0-864353b",
"@floating-ui/dom": "^1.6.0",
"@mantine/core": "^7.17.0",
"@mantine/form": "^7.17.0",
"@mantine/hooks": "^7.17.0",
@ -24,7 +25,6 @@
"@mantine/spotlight": "^7.17.0",
"@tabler/icons-react": "^3.34.0",
"@tanstack/react-query": "^5.80.6",
"@tiptap/extension-character-count": "^2.10.3",
"axios": "^1.9.0",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",

View File

@ -36,7 +36,7 @@ import { useSettingsNavigation } from "@/hooks/use-settings-navigation";
interface DataItem {
label: string;
icon: React.ElementType;
icon: any;
path: string;
isCloud?: boolean;
isEnterprise?: boolean;

View File

@ -1,5 +1,5 @@
import { Placeholder } from "@tiptap/extensions";
import { EditorContent, useEditor } from "@tiptap/react";
import { Placeholder } from "@tiptap/extension-placeholder";
import { Underline } from "@tiptap/extension-underline";
import { Link } from "@tiptap/extension-link";
import { StarterKit } from "@tiptap/starter-kit";

View File

@ -1,9 +1,5 @@
import {
BubbleMenu,
BubbleMenuProps,
isNodeSelection,
useEditor,
} from "@tiptap/react";
import { isNodeSelection, useEditor } from "@tiptap/react";
import { BubbleMenu, BubbleMenuProps } from "@tiptap/react/menus";
import { FC, useEffect, useRef, useState } from "react";
import {
IconBold,

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
findParentNode,
posToDOMRect,
} from "@tiptap/react";
import { findParentNode, posToDOMRect } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import React, { useCallback } from "react";
import { Node as PMNode } from "prosemirror-model";
import {

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
findParentNode,
posToDOMRect,
} from '@tiptap/react';
import { findParentNode, posToDOMRect } from '@tiptap/react';
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import { useCallback } from 'react';
import { sticky } from 'tippy.js';
import { Node as PMNode } from 'prosemirror-model';

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
findParentNode,
posToDOMRect,
} from '@tiptap/react';
import { findParentNode, posToDOMRect } from '@tiptap/react';
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import { useCallback } from 'react';
import { sticky } from 'tippy.js';
import { Node as PMNode } from 'prosemirror-model';

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
findParentNode,
posToDOMRect,
} from "@tiptap/react";
import { findParentNode, posToDOMRect } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import React, { useCallback } from "react";
import { sticky } from "tippy.js";
import { Node as PMNode } from "prosemirror-model";

View File

@ -1,4 +1,4 @@
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import React, { useCallback, useState } from "react";
import { EditorMenuProps } from "@/features/editor/components/table/types/types.ts";
import { LinkEditorPanel } from "@/features/editor/components/link/link-editor-panel.tsx";

View File

@ -1,4 +1,4 @@
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import React, { useCallback } from "react";
import {

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
posToDOMRect,
findParentNode,
} from "@tiptap/react";
import { posToDOMRect, findParentNode } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import { Node as PMNode } from "@tiptap/pm/model";
import React, { useCallback } from "react";

View File

@ -1,8 +1,5 @@
import {
BubbleMenu as BaseBubbleMenu,
findParentNode,
posToDOMRect,
} from "@tiptap/react";
import { findParentNode, posToDOMRect } from "@tiptap/react";
import { BubbleMenu as BaseBubbleMenu } from "@tiptap/react/menus";
import React, { useCallback } from "react";
import { sticky } from "tippy.js";
import { Node as PMNode } from "prosemirror-model";

View File

@ -1,20 +1,17 @@
import { StarterKit } from "@tiptap/starter-kit";
import { Placeholder } from "@tiptap/extension-placeholder";
import { Table, TableHeader } from "@tiptap/extension-table";
import { TextStyle, Color } from "@tiptap/extension-text-style";
import { TaskList, TaskItem } from "@tiptap/extension-list";
import { Placeholder, CharacterCount } from "@tiptap/extensions";
import StarterKit from "@tiptap/starter-kit";
import { TextAlign } from "@tiptap/extension-text-align";
import { TaskList } from "@tiptap/extension-task-list";
import { TaskItem } from "@tiptap/extension-task-item";
import { Underline } from "@tiptap/extension-underline";
import { Superscript } from "@tiptap/extension-superscript";
import SubScript from "@tiptap/extension-subscript";
import { Highlight } from "@tiptap/extension-highlight";
import { Typography } from "@tiptap/extension-typography";
import { TextStyle } from "@tiptap/extension-text-style";
import { Color } from "@tiptap/extension-color";
import Table from "@tiptap/extension-table";
import TableHeader from "@tiptap/extension-table-header";
import SlashCommand from "@/features/editor/extensions/slash-command";
import { Collaboration } from "@tiptap/extension-collaboration";
import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
import Collaboration from "@tiptap/extension-collaboration";
import CollaborationCaret from "@tiptap/extension-collaboration-caret";
import { HocuspocusProvider } from "@hocuspocus/provider";
import {
Comment,
@ -72,7 +69,6 @@ import MentionView from "@/features/editor/components/mention/mention-view.tsx";
import i18n from "@/i18n.ts";
import { MarkdownClipboard } from "@/features/editor/extensions/markdown-clipboard.ts";
import EmojiCommand from "./emoji-command";
import { CharacterCount } from "@tiptap/extension-character-count";
const lowlight = createLowlight(common);
lowlight.register("mermaid", plaintext);
@ -88,7 +84,7 @@ lowlight.register("scala", scala);
export const mainExtensions = [
StarterKit.configure({
history: false,
undoRedo: false,
dropcursor: {
width: 3,
color: "#70CFF8",
@ -213,7 +209,7 @@ export const mainExtensions = [
MarkdownClipboard.configure({
transformPastedText: true,
}),
CharacterCount
CharacterCount,
] as any;
type CollabExtensions = (provider: HocuspocusProvider, user: IUser) => any[];
@ -222,7 +218,7 @@ export const collabExtensions: CollabExtensions = (provider, user) => [
Collaboration.configure({
document: provider.document,
}),
CollaborationCursor.configure({
CollaborationCaret.configure({
provider,
user: {
name: user.name,

View File

@ -102,8 +102,8 @@ export default function PageEditor({
url: collaborationURL,
document: ydoc,
token: collabQuery?.token,
connect: false,
preserveConnection: false,
//connect: false,
// preserveConnection: false,
onAuthenticationFailed: (auth: onAuthenticationFailedParameters) => {
const payload = jwtDecode(collabQuery?.token);
const now = Date.now().valueOf() / 1000;
@ -112,11 +112,11 @@ export default function PageEditor({
refetchCollabToken();
}
},
onStatus: (status) => {
if (status.status === "connected") {
setYjsConnectionStatus(status.status);
}
},
// onStatus: (status) => {
// if (status.status === "connected") {
// setYjsConnectionStatus(status.status);
// }
//},
});
provider.on("synced", () => {

View File

@ -1,3 +1,4 @@
import { Placeholder } from "@tiptap/extensions";
import "@/features/editor/styles/index.css";
import React, { useMemo } from "react";
import { EditorProvider } from "@tiptap/react";
@ -5,7 +6,6 @@ import { mainExtensions } from "@/features/editor/extensions/extensions";
import { Document } from "@tiptap/extension-document";
import { Heading } from "@tiptap/extension-heading";
import { Text } from "@tiptap/extension-text";
import { Placeholder } from "@tiptap/extension-placeholder";
import { useAtom } from "jotai/index";
import {
pageEditorAtom,

View File

@ -1,10 +1,10 @@
import { Placeholder, History } from "@tiptap/extensions";
import "@/features/editor/styles/index.css";
import React, { useCallback, useEffect, useState } from "react";
import { EditorContent, useEditor } from "@tiptap/react";
import { Document } from "@tiptap/extension-document";
import { Heading } from "@tiptap/extension-heading";
import { Text } from "@tiptap/extension-text";
import { Placeholder } from "@tiptap/extension-placeholder";
import { useAtomValue } from "jotai";
import {
pageEditorAtom,
@ -14,7 +14,6 @@ import { updatePageData, useUpdateTitlePageMutation } from "@/features/page/quer
import { useDebouncedCallback } from "@mantine/hooks";
import { useAtom } from "jotai";
import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
import { History } from "@tiptap/extension-history";
import { buildPageUrl } from "@/features/page/page.utils.ts";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";

View File

@ -1,4 +1,4 @@
import { Hocuspocus, Server as HocuspocusServer } from '@hocuspocus/server';
import { Hocuspocus } from '@hocuspocus/server';
import { IncomingMessage } from 'http';
import WebSocket from 'ws';
import { AuthenticationExtension } from './extensions/authentication.extension';
@ -26,7 +26,7 @@ export class CollaborationGateway {
) {
this.redisConfig = parseRedisUrl(this.environmentService.getRedisUrl());
this.hocuspocus = HocuspocusServer.configure({
this.hocuspocus = new Hocuspocus({
debounce: 10000,
maxDebounce: 45000,
unloadImmediately: false,
@ -65,6 +65,6 @@ export class CollaborationGateway {
}
async destroy(): Promise<void> {
await this.hocuspocus.destroy();
//await this.hocuspocus.destroy();
}
}

View File

@ -1,17 +1,13 @@
import { StarterKit } from '@tiptap/starter-kit';
import { Table, TableHeader } from '@tiptap/extension-table';
import { TextStyle, Color } from '@tiptap/extension-text-style';
import { TaskList, TaskItem } from '@tiptap/extension-list';
import { TextAlign } from '@tiptap/extension-text-align';
import { TaskList } from '@tiptap/extension-task-list';
import { TaskItem } from '@tiptap/extension-task-item';
import { Underline } from '@tiptap/extension-underline';
import { Superscript } from '@tiptap/extension-superscript';
import SubScript from '@tiptap/extension-subscript';
import { Highlight } from '@tiptap/extension-highlight';
import { Typography } from '@tiptap/extension-typography';
import { TextStyle } from '@tiptap/extension-text-style';
import { Color } from '@tiptap/extension-color';
import { Youtube } from '@tiptap/extension-youtube';
import Table from '@tiptap/extension-table';
import TableHeader from '@tiptap/extension-table-header';
import {
Callout,
Comment,
@ -31,8 +27,9 @@ import {
Drawio,
Excalidraw,
Embed,
Mention
Mention,
} from '@docmost/editor-ext';
import StarterKit from '@tiptap/starter-kit';
import { generateText, getSchema, JSONContent } from '@tiptap/core';
import { generateHTML } from '../common/helpers/prosemirror/html';
// @tiptap/html library works best for generating prosemirror json state but not HTML
@ -44,9 +41,10 @@ import { Node } from '@tiptap/pm/model';
export const tiptapExtensions = [
StarterKit.configure({
codeBlock: false,
undoRedo: false,
}),
Comment,
TextAlign.configure({ types: ["heading", "paragraph"] }),
TextAlign.configure({ types: ['heading', 'paragraph'] }),
TaskList,
TaskItem,
Underline,
@ -76,7 +74,7 @@ export const tiptapExtensions = [
Drawio,
Excalidraw,
Embed,
Mention
Mention,
] as any;
export function jsonToHtml(tiptapJson: any) {

View File

@ -19,47 +19,38 @@
},
"dependencies": {
"@docmost/editor-ext": "workspace:*",
"@hocuspocus/extension-redis": "^2.15.2",
"@hocuspocus/provider": "^2.15.2",
"@hocuspocus/server": "^2.15.2",
"@hocuspocus/transformer": "^2.15.2",
"@hocuspocus/extension-redis": "^3.1.3",
"@hocuspocus/provider": "^3.1.3",
"@hocuspocus/server": "^3.1.3",
"@hocuspocus/transformer": "^3.1.3",
"@joplin/turndown": "^4.0.74",
"@joplin/turndown-plugin-gfm": "^1.0.56",
"@sindresorhus/slugify": "1.1.0",
"@tiptap/core": "^2.10.3",
"@tiptap/extension-code-block": "^2.10.3",
"@tiptap/extension-code-block-lowlight": "^2.10.3",
"@tiptap/extension-collaboration": "^2.10.3",
"@tiptap/extension-collaboration-cursor": "^2.10.3",
"@tiptap/extension-color": "^2.10.3",
"@tiptap/extension-document": "^2.10.3",
"@tiptap/extension-heading": "^2.10.3",
"@tiptap/extension-highlight": "^2.10.3",
"@tiptap/extension-history": "^2.10.3",
"@tiptap/extension-image": "^2.10.3",
"@tiptap/extension-link": "^2.10.3",
"@tiptap/extension-list-item": "^2.10.3",
"@tiptap/extension-list-keymap": "^2.10.3",
"@tiptap/extension-placeholder": "^2.10.3",
"@tiptap/extension-subscript": "^2.10.3",
"@tiptap/extension-superscript": "^2.10.3",
"@tiptap/extension-table": "^2.10.3",
"@tiptap/extension-table-cell": "^2.10.3",
"@tiptap/extension-table-header": "^2.10.3",
"@tiptap/extension-table-row": "^2.10.3",
"@tiptap/extension-task-item": "^2.10.3",
"@tiptap/extension-task-list": "^2.10.3",
"@tiptap/extension-text": "^2.10.3",
"@tiptap/extension-text-align": "^2.10.3",
"@tiptap/extension-text-style": "^2.10.3",
"@tiptap/extension-typography": "^2.10.3",
"@tiptap/extension-underline": "^2.10.3",
"@tiptap/extension-youtube": "^2.10.3",
"@tiptap/html": "^2.10.3",
"@tiptap/pm": "^2.10.3",
"@tiptap/react": "^2.10.3",
"@tiptap/starter-kit": "^2.10.3",
"@tiptap/suggestion": "^2.10.3",
"@tiptap/core": "3.0.0-beta.7",
"@tiptap/extension-code-block": "3.0.0-beta.7",
"@tiptap/extension-code-block-lowlight": "3.0.0-beta.7",
"@tiptap/extension-collaboration": "3.0.0-beta.7",
"@tiptap/extension-collaboration-caret": "3.0.0-beta.7",
"@tiptap/extension-color": "3.0.0-beta.7",
"@tiptap/extension-document": "3.0.0-beta.7",
"@tiptap/extension-heading": "3.0.0-beta.7",
"@tiptap/extension-highlight": "3.0.0-beta.7",
"@tiptap/extension-image": "3.0.0-beta.7",
"@tiptap/extension-list": "3.0.0-beta.7",
"@tiptap/extension-placeholder": "3.0.0-beta.7",
"@tiptap/extension-subscript": "3.0.0-beta.7",
"@tiptap/extension-superscript": "3.0.0-beta.7",
"@tiptap/extension-table": "3.0.0-beta.7",
"@tiptap/extension-text": "3.0.0-beta.7",
"@tiptap/extension-text-align": "3.0.0-beta.7",
"@tiptap/extension-text-style": "3.0.0-beta.7",
"@tiptap/extension-typography": "3.0.0-beta.7",
"@tiptap/extension-youtube": "3.0.0-beta.7",
"@tiptap/extensions": "3.0.0-beta.7",
"@tiptap/html": "3.0.0-beta.7",
"@tiptap/pm": "3.0.0-beta.7",
"@tiptap/react": "3.0.0-beta.7",
"@tiptap/suggestion": "3.0.0-beta.7",
"bytes": "^3.1.2",
"cross-env": "^7.0.3",
"date-fns": "^4.1.0",

View File

@ -27,7 +27,7 @@ export const Details = Node.create<DetailsOptions>({
content: "detailsSummary detailsContent",
defining: true,
isolating: true,
allowGapCursor: false,
//allowGapCursor: false,
addOptions() {
return {
HTMLAttributes: {},

View File

@ -1,4 +1,4 @@
import { TableCell as TiptapTableCell } from "@tiptap/extension-table-cell";
import { TableCell as TiptapTableCell } from "@tiptap/extension-table";
export const TableCell = TiptapTableCell.extend({
name: "tableCell",

View File

@ -1,4 +1,4 @@
import TiptapTableRow from "@tiptap/extension-table-row";
import { TableRow as TiptapTableRow } from "@tiptap/extension-table";
export const TableRow = TiptapTableRow.extend({
allowGapCursor: false,

View File

@ -1,9 +1,10 @@
import { Table } from "@tiptap/extension-table";
// @ts-nocheck
import { Editor, findParentNode, isTextSelection } from "@tiptap/core";
import { Selection, Transaction } from "@tiptap/pm/state";
import { EditorState, Selection, Transaction } from '@tiptap/pm/state';
import { CellSelection, TableMap } from "@tiptap/pm/tables";
import { Node, ResolvedPos } from "@tiptap/pm/model";
import Table from "@tiptap/extension-table";
import { EditorView } from '@tiptap/pm/view';
export const isRectSelected = (rect: any) => (selection: CellSelection) => {
const map = TableMap.get(selection.$anchorCell.node(-1));

9463
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff