diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index 2a9ec776e..8b31acdaf 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -30,7 +30,6 @@ "dependencies": { "@tiptap/core": "^2.1.13", "@tiptap/extension-blockquote": "^2.1.13", - "@tiptap/extension-code": "^2.1.13", "@tiptap/extension-code-block-lowlight": "^2.1.13", "@tiptap/extension-color": "^2.1.13", "@tiptap/extension-image": "^2.1.13", diff --git a/packages/editor/core/src/lib/editor-commands.ts b/packages/editor/core/src/lib/editor-commands.ts index 147797e2d..4a56f07c2 100644 --- a/packages/editor/core/src/lib/editor-commands.ts +++ b/packages/editor/core/src/lib/editor-commands.ts @@ -34,8 +34,32 @@ export const toggleUnderline = (editor: Editor, range?: Range) => { }; export const toggleCodeBlock = (editor: Editor, range?: Range) => { - if (range) editor.chain().focus().deleteRange(range).toggleCodeBlock().run(); - else editor.chain().focus().toggleCodeBlock().run(); + // Check if code block is active then toggle code block + if (editor.isActive("codeBlock")) { + if (range) { + editor.chain().focus().deleteRange(range).toggleCodeBlock().run(); + return; + } + editor.chain().focus().toggleCodeBlock().run(); + return; + } + + // Check if user hasn't selected any text + const isSelectionEmpty = editor.state.selection.empty; + + if (isSelectionEmpty) { + if (range) { + editor.chain().focus().deleteRange(range).toggleCodeBlock().run(); + return; + } + editor.chain().focus().toggleCodeBlock().run(); + } else { + if (range) { + editor.chain().focus().deleteRange(range).toggleCode().run(); + return; + } + editor.chain().focus().toggleCode().run(); + } }; export const toggleOrderedList = (editor: Editor, range?: Range) => { @@ -59,8 +83,8 @@ export const toggleStrike = (editor: Editor, range?: Range) => { }; export const toggleBlockquote = (editor: Editor, range?: Range) => { - if (range) editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(); - else editor.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run(); + if (range) editor.chain().focus().deleteRange(range).toggleBlockquote().run(); + else editor.chain().focus().toggleBlockquote().run(); }; export const insertTableCommand = (editor: Editor, range?: Range) => { diff --git a/packages/editor/core/src/ui/extensions/code-inline/index.tsx b/packages/editor/core/src/ui/extensions/code-inline/index.tsx index 539dc9346..1c5d34109 100644 --- a/packages/editor/core/src/ui/extensions/code-inline/index.tsx +++ b/packages/editor/core/src/ui/extensions/code-inline/index.tsx @@ -1,12 +1,80 @@ -import { markInputRule, markPasteRule } from "@tiptap/core"; -import Code from "@tiptap/extension-code"; +import { Mark, markInputRule, markPasteRule, mergeAttributes } from "@tiptap/core"; -export const inputRegex = /(?; +} + +declare module "@tiptap/core" { + interface Commands { + code: { + /** + * Set a code mark + */ + setCode: () => ReturnType; + /** + * Toggle inline code + */ + toggleCode: () => ReturnType; + /** + * Unset a code mark + */ + unsetCode: () => ReturnType; + }; + } +} + +export const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/; +export const pasteRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))/g; + +export const CustomCodeInlineExtension = Mark.create({ + name: "code", + + addOptions() { + return { + HTMLAttributes: { + class: "rounded-md bg-custom-primary-30 mx-1 px-1 py-[2px] font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }; + }, + + excludes: "_", + + code: true, -export const CustomCodeInlineExtension = Code.extend({ exitable: true, - inclusive: false, + + parseHTML() { + return [{ tag: "code" }]; + }, + + renderHTML({ HTMLAttributes }) { + return ["code", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]; + }, + + addCommands() { + return { + setCode: + () => + ({ commands }) => + commands.setMark(this.name), + toggleCode: + () => + ({ commands }) => + commands.toggleMark(this.name), + unsetCode: + () => + ({ commands }) => + commands.unsetMark(this.name), + }; + }, + + addKeyboardShortcuts() { + return { + "Mod-e": () => this.editor.commands.toggleCode(), + }; + }, + addInputRules() { return [ markInputRule({ @@ -15,6 +83,7 @@ export const CustomCodeInlineExtension = Code.extend({ }), ]; }, + addPasteRules() { return [ markPasteRule({ @@ -23,9 +92,4 @@ export const CustomCodeInlineExtension = Code.extend({ }), ]; }, -}).configure({ - HTMLAttributes: { - class: "rounded-md bg-custom-primary-30 mx-1 px-1 py-[2px] font-mono font-medium text-custom-text-1000", - spellcheck: "false", - }, }); diff --git a/packages/editor/core/src/ui/menus/menu-items/index.tsx b/packages/editor/core/src/ui/menus/menu-items/index.tsx index 610d677f8..f60febc59 100644 --- a/packages/editor/core/src/ui/menus/menu-items/index.tsx +++ b/packages/editor/core/src/ui/menus/menu-items/index.tsx @@ -106,7 +106,7 @@ export const TodoListItem = (editor: Editor): EditorMenuItem => ({ export const CodeItem = (editor: Editor): EditorMenuItem => ({ name: "code", - isActive: () => editor?.isActive("code"), + isActive: () => editor?.isActive("code") || editor?.isActive("codeBlock"), command: () => toggleCodeBlock(editor), icon: CodeIcon, }); @@ -120,7 +120,7 @@ export const NumberedListItem = (editor: Editor): EditorMenuItem => ({ export const QuoteItem = (editor: Editor): EditorMenuItem => ({ name: "quote", - isActive: () => editor?.isActive("quote"), + isActive: () => editor?.isActive("blockquote"), command: () => toggleBlockquote(editor), icon: QuoteIcon, });