diff --git a/package-lock.json b/package-lock.json index 87692758d1..c6e9fd50bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10622,18 +10622,6 @@ "@tiptap/pm": "^2.7.0" } }, - "node_modules/@tiptap/extension-hard-break": { - "version": "2.11.5", - "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.11.5.tgz", - "integrity": "sha512-q9doeN+Yg9F5QNTG8pZGYfNye3tmntOwch683v0CCVCI4ldKaLZ0jG3NbBTq+mosHYdgOH2rNbIORlRRsQ+iYQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/core": "^2.7.0" - } - }, "node_modules/@tiptap/extension-history": { "version": "2.11.5", "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.11.5.tgz", @@ -31224,7 +31212,6 @@ "@tiptap/extension-collaboration": "^2.11.5", "@tiptap/extension-collaboration-cursor": "^2.11.5", "@tiptap/extension-gapcursor": "^2.11.5", - "@tiptap/extension-hard-break": "^2.11.5", "@tiptap/extension-history": "^2.11.5", "@tiptap/extension-horizontal-rule": "^2.11.5", "@tiptap/extension-italic": "^2.11.5", diff --git a/packages/core/package.json b/packages/core/package.json index f99e435d17..07183e8c2d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -69,7 +69,6 @@ "@tiptap/extension-collaboration": "^2.11.5", "@tiptap/extension-collaboration-cursor": "^2.11.5", "@tiptap/extension-gapcursor": "^2.11.5", - "@tiptap/extension-hard-break": "^2.11.5", "@tiptap/extension-history": "^2.11.5", "@tiptap/extension-horizontal-rule": "^2.11.5", "@tiptap/extension-italic": "^2.11.5", diff --git a/packages/core/src/blocks/TableBlockContent/TableExtension.ts b/packages/core/src/blocks/TableBlockContent/TableExtension.ts index 33b47c0c90..0ed6836eea 100644 --- a/packages/core/src/blocks/TableBlockContent/TableExtension.ts +++ b/packages/core/src/blocks/TableBlockContent/TableExtension.ts @@ -31,7 +31,7 @@ export const TableExtension = Extension.create({ this.editor.state.selection.$head.parent.type.name === "tableParagraph" ) { - this.editor.commands.setHardBreak(); + this.editor.commands.insertContent({ type: "hardBreak" }); return true; } diff --git a/packages/core/src/editor/BlockNoteExtensions.ts b/packages/core/src/editor/BlockNoteExtensions.ts index 9d7f1fd0fc..a5233f11f6 100644 --- a/packages/core/src/editor/BlockNoteExtensions.ts +++ b/packages/core/src/editor/BlockNoteExtensions.ts @@ -1,6 +1,5 @@ import { AnyExtension, Extension, extensions } from "@tiptap/core"; import { Gapcursor } from "@tiptap/extension-gapcursor"; -import { HardBreak } from "@tiptap/extension-hard-break"; import { History } from "@tiptap/extension-history"; import { Link } from "@tiptap/extension-link"; import { Text } from "@tiptap/extension-text"; @@ -17,6 +16,7 @@ import { CommentsPlugin } from "../extensions/Comments/CommentsPlugin.js"; import type { ThreadStore } from "../comments/index.js"; import { FilePanelProsemirrorPlugin } from "../extensions/FilePanel/FilePanelPlugin.js"; import { FormattingToolbarProsemirrorPlugin } from "../extensions/FormattingToolbar/FormattingToolbarPlugin.js"; +import { HardBreak } from "../extensions/HardBreak/HardBreak.js"; import { KeyboardShortcutsExtension } from "../extensions/KeyboardShortcuts/KeyboardShortcutsExtension.js"; import { LinkToolbarProsemirrorPlugin } from "../extensions/LinkToolbar/LinkToolbarPlugin.js"; import { @@ -179,7 +179,7 @@ const getTipTapExtensions = < types: ["blockContainer", "columnList", "column"], setIdAttribute: opts.setIdAttribute, }), - HardBreak.extend({ priority: 10 }), + HardBreak, // Comments, // basics: diff --git a/packages/core/src/extensions/HardBreak/HardBreak.ts b/packages/core/src/extensions/HardBreak/HardBreak.ts new file mode 100644 index 0000000000..6c1a99b241 --- /dev/null +++ b/packages/core/src/extensions/HardBreak/HardBreak.ts @@ -0,0 +1,35 @@ +// Stripped down version of the TipTap HardBreak extension: +// https://github.com/ueberdosis/tiptap/blob/f3258d9ee5fb7979102fe63434f6ea4120507311/packages/extension-hard-break/src/hard-break.ts#L80 +// Changes: +// - Removed options +// - Removed keyboard shortcuts & moved them to the `KeyboardShortcutsExtension` +// - Removed `setHardBreak` command (added a simpler version in the Shift+Enter +// handler in `KeyboardShortcutsExtension`). +// - Added priority +import { mergeAttributes, Node } from "@tiptap/core"; + +export const HardBreak = Node.create({ + name: "hardBreak", + + inline: true, + + group: "inline", + + selectable: false, + + linebreakReplacement: true, + + priority: 10, + + parseHTML() { + return [{ tag: "br" }]; + }, + + renderHTML({ HTMLAttributes }) { + return ["br", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; + }, + + renderText() { + return "\n"; + }, +}); diff --git a/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts b/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts index ae00f7074a..9e7d540f64 100644 --- a/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +++ b/packages/core/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts @@ -437,8 +437,8 @@ export const KeyboardShortcutsExtension = Extension.create<{ }), ]); - const handleEnter = () => - this.editor.commands.first(({ commands }) => [ + const handleEnter = (withShift = false) => { + return this.editor.commands.first(({ commands }) => [ // Removes a level of nesting if the block is empty & indented, while the selection is also empty & at the start // of the block. () => @@ -467,6 +467,34 @@ export const KeyboardShortcutsExtension = Extension.create<{ return commands.liftListItem("blockContainer"); } + return false; + }), + // Creates a hard break if block is configured to do so. + () => + commands.command(({ state }) => { + const blockInfo = getBlockInfoFromSelection(state); + + const blockHardBreakShortcut: "shift+enter" | "enter" | "none" = + this.options.editor.schema.blockSchema[blockInfo.blockNoteType] + .hardBreakShortcut ?? "shift+enter"; + + if (blockHardBreakShortcut === "none") { + return false; + } + + if ( + // If shortcut is not configured, or is configured as "shift+enter", + // create a hard break for shift+enter, but not for enter. + (blockHardBreakShortcut === "shift+enter" && withShift) || + // If shortcut is configured as "enter", create a hard break for + // both enter and shift+enter. + blockHardBreakShortcut === "enter" + ) { + return commands.insertContent({ + type: "hardBreak", + }); + } + return false; }), // Creates a new block and moves the selection to it if the current one is empty, while the selection is also @@ -538,11 +566,13 @@ export const KeyboardShortcutsExtension = Extension.create<{ return false; }), ]); + }; return { Backspace: handleBackspace, Delete: handleDelete, - Enter: handleEnter, + Enter: () => handleEnter(), + "Shift-Enter": () => handleEnter(true), // Always returning true for tab key presses ensures they're not captured by the browser. Otherwise, they blur the // editor since the browser will try to use tab for keyboard navigation. Tab: () => { diff --git a/packages/core/src/schema/blocks/types.ts b/packages/core/src/schema/blocks/types.ts index dac8f5c9e9..0db756ec74 100644 --- a/packages/core/src/schema/blocks/types.ts +++ b/packages/core/src/schema/blocks/types.ts @@ -63,6 +63,7 @@ export type BlockConfig = content: "inline" | "none" | "table"; isSelectable?: boolean; isFileBlock?: false; + hardBreakShortcut?: "shift+enter" | "enter" | "none"; } | FileBlockConfig;