@tiptap/extension-code-block
Advanced tools
| {"version":3,"file":"index.d.cts","names":[],"sources":["../src/code-block.ts"],"mappings":";;UAKiB;;;;;EAKf;;;;;EAKA;;;;;EAKA;;;;;EAKA;;;;;;EAMA;;;;;EAKA;;;;;EAKA;;;;;;EAMA,gBAAgB;;;YAIN,SAAS;IACjB;;;;;;MAME,eAAe;QAAe;YAAuB;;;;;;MAMrD,kBAAkB;QAAe;YAAuB;;;;;;;cAQjD,oBAAkB;;;;cAKlB,iBAAe;;;;;cAMf,WAAS,KAAA"} |
| {"version":3,"file":"index.d.ts","names":[],"sources":["../src/code-block.ts"],"mappings":";;UAKiB;;;;;EAKf;;;;;EAKA;;;;;EAKA;;;;;EAKA;;;;;;EAMA;;;;;EAKA;;;;;EAKA;;;;;;EAMA,gBAAgB;;;YAIN,SAAS;IACjB;;;;;;MAME,eAAe;QAAe;YAAuB;;;;;;MAMrD,kBAAkB;QAAe;YAAuB;;;;;;;cAQjD,oBAAkB;;;;cAKlB,iBAAe;;;;;cAMf,WAAS,KAAA"} |
+251
-370
@@ -1,374 +0,255 @@ | ||
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var index_exports = {}; | ||
| __export(index_exports, { | ||
| CodeBlock: () => CodeBlock, | ||
| backtickInputRegex: () => backtickInputRegex, | ||
| default: () => index_default, | ||
| tildeInputRegex: () => tildeInputRegex | ||
| Object.defineProperties(exports, { | ||
| __esModule: { value: true }, | ||
| [Symbol.toStringTag]: { value: "Module" } | ||
| }); | ||
| module.exports = __toCommonJS(index_exports); | ||
| // src/code-block.ts | ||
| var import_core = require("@tiptap/core"); | ||
| var import_state = require("@tiptap/pm/state"); | ||
| var DEFAULT_TAB_SIZE = 4; | ||
| var backtickInputRegex = /^```([a-z]+)?[\s\n]$/; | ||
| var tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/; | ||
| var CodeBlock = import_core.Node.create({ | ||
| name: "codeBlock", | ||
| addOptions() { | ||
| return { | ||
| languageClassPrefix: "language-", | ||
| exitOnTripleEnter: true, | ||
| exitOnArrowDown: true, | ||
| exitOnArrowUp: true, | ||
| defaultLanguage: null, | ||
| enableTabIndentation: false, | ||
| tabSize: DEFAULT_TAB_SIZE, | ||
| HTMLAttributes: {} | ||
| }; | ||
| }, | ||
| content: "text*", | ||
| marks: "", | ||
| group: "block", | ||
| code: true, | ||
| defining: true, | ||
| addAttributes() { | ||
| return { | ||
| language: { | ||
| default: this.options.defaultLanguage, | ||
| parseHTML: (element) => { | ||
| var _a; | ||
| const { languageClassPrefix } = this.options; | ||
| if (!languageClassPrefix) { | ||
| return null; | ||
| } | ||
| const classNames = [...((_a = element.firstElementChild) == null ? void 0 : _a.classList) || []]; | ||
| const languages = classNames.filter((className) => className.startsWith(languageClassPrefix)).map((className) => className.replace(languageClassPrefix, "")); | ||
| const language = languages[0]; | ||
| if (!language) { | ||
| return null; | ||
| } | ||
| return language; | ||
| }, | ||
| rendered: false | ||
| } | ||
| }; | ||
| }, | ||
| parseHTML() { | ||
| return [ | ||
| { | ||
| tag: "pre", | ||
| preserveWhitespace: "full" | ||
| } | ||
| ]; | ||
| }, | ||
| renderHTML({ node, HTMLAttributes }) { | ||
| return [ | ||
| "pre", | ||
| (0, import_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), | ||
| [ | ||
| "code", | ||
| { | ||
| class: node.attrs.language ? this.options.languageClassPrefix + node.attrs.language : null | ||
| }, | ||
| 0 | ||
| ] | ||
| ]; | ||
| }, | ||
| markdownTokenName: "code", | ||
| parseMarkdown: (token, helpers) => { | ||
| var _a, _b; | ||
| if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && ((_b = token.raw) == null ? void 0 : _b.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") { | ||
| return []; | ||
| } | ||
| return helpers.createNode( | ||
| "codeBlock", | ||
| { language: token.lang || null }, | ||
| token.text ? [helpers.createTextNode(token.text)] : [] | ||
| ); | ||
| }, | ||
| renderMarkdown: (node, h) => { | ||
| var _a; | ||
| let output = ""; | ||
| const language = ((_a = node.attrs) == null ? void 0 : _a.language) || ""; | ||
| if (!node.content) { | ||
| output = `\`\`\`${language} | ||
| \`\`\``; | ||
| } else { | ||
| const lines = [`\`\`\`${language}`, h.renderChildren(node.content), "```"]; | ||
| output = lines.join("\n"); | ||
| } | ||
| return output; | ||
| }, | ||
| addCommands() { | ||
| return { | ||
| setCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.setNode(this.name, attributes); | ||
| }, | ||
| toggleCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.toggleNode(this.name, "paragraph", attributes); | ||
| } | ||
| }; | ||
| }, | ||
| addKeyboardShortcuts() { | ||
| return { | ||
| "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(), | ||
| // remove code block when at start of document or code block is empty | ||
| Backspace: () => { | ||
| const { empty, $anchor } = this.editor.state.selection; | ||
| const isAtStart = $anchor.pos === 1; | ||
| if (!empty || $anchor.parent.type.name !== this.name) { | ||
| return false; | ||
| } | ||
| if (isAtStart || !$anchor.parent.textContent.length) { | ||
| return this.editor.commands.clearNodes(); | ||
| } | ||
| return false; | ||
| }, | ||
| // handle tab indentation | ||
| Tab: ({ editor }) => { | ||
| var _a; | ||
| if (!this.options.enableTabIndentation) { | ||
| return false; | ||
| } | ||
| const tabSize = (_a = this.options.tabSize) != null ? _a : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const indent = " ".repeat(tabSize); | ||
| if (empty) { | ||
| return editor.commands.insertContent(indent); | ||
| } | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const text = state.doc.textBetween(from, to, "\n", "\n"); | ||
| const lines = text.split("\n"); | ||
| const indentedText = lines.map((line) => indent + line).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(indentedText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| // handle shift+tab reverse indentation | ||
| "Shift-Tab": ({ editor }) => { | ||
| var _a; | ||
| if (!this.options.enableTabIndentation) { | ||
| return false; | ||
| } | ||
| const tabSize = (_a = this.options.tabSize) != null ? _a : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| if (empty) { | ||
| return editor.commands.command(({ tr }) => { | ||
| var _a2; | ||
| const { pos } = $from; | ||
| const codeBlockStart = $from.start(); | ||
| const codeBlockEnd = $from.end(); | ||
| const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, "\n", "\n"); | ||
| const lines = allText.split("\n"); | ||
| let currentLineIndex = 0; | ||
| let charCount = 0; | ||
| const relativeCursorPos = pos - codeBlockStart; | ||
| for (let i = 0; i < lines.length; i += 1) { | ||
| if (charCount + lines[i].length >= relativeCursorPos) { | ||
| currentLineIndex = i; | ||
| break; | ||
| } | ||
| charCount += lines[i].length + 1; | ||
| } | ||
| const currentLine = lines[currentLineIndex]; | ||
| const leadingSpaces = ((_a2 = currentLine.match(/^ */)) == null ? void 0 : _a2[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| if (spacesToRemove === 0) { | ||
| return true; | ||
| } | ||
| let lineStartPos = codeBlockStart; | ||
| for (let i = 0; i < currentLineIndex; i += 1) { | ||
| lineStartPos += lines[i].length + 1; | ||
| } | ||
| tr.delete(lineStartPos, lineStartPos + spacesToRemove); | ||
| const cursorPosInLine = pos - lineStartPos; | ||
| if (cursorPosInLine <= spacesToRemove) { | ||
| tr.setSelection(import_state.TextSelection.create(tr.doc, lineStartPos)); | ||
| } | ||
| return true; | ||
| }); | ||
| } | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const text = state.doc.textBetween(from, to, "\n", "\n"); | ||
| const lines = text.split("\n"); | ||
| const reverseIndentText = lines.map((line) => { | ||
| var _a2; | ||
| const leadingSpaces = ((_a2 = line.match(/^ */)) == null ? void 0 : _a2[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| return line.slice(spacesToRemove); | ||
| }).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(reverseIndentText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| // exit node on triple enter | ||
| Enter: ({ editor }) => { | ||
| if (!this.options.exitOnTripleEnter) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n"); | ||
| if (!isAtEnd || !endsWithDoubleNewline) { | ||
| return false; | ||
| } | ||
| return editor.chain().command(({ tr }) => { | ||
| tr.delete($from.pos - 2, $from.pos); | ||
| return true; | ||
| }).exitCode().run(); | ||
| }, | ||
| // exit node on arrow up if there is no node before it | ||
| ArrowUp: ({ editor }) => { | ||
| if (!this.options.exitOnArrowUp) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| if ($from.parentOffset !== 0) { | ||
| return false; | ||
| } | ||
| const before = $from.before(); | ||
| if (before > 0) { | ||
| return false; | ||
| } | ||
| return editor.commands.insertDefaultBlock({ pos: before }); | ||
| }, | ||
| // exit node on arrow down | ||
| ArrowDown: ({ editor }) => { | ||
| if (!this.options.exitOnArrowDown) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection, doc } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| if (!isAtEnd) { | ||
| return false; | ||
| } | ||
| const after = $from.after(); | ||
| if (after === void 0) { | ||
| return false; | ||
| } | ||
| const nodeAfter = doc.nodeAt(after); | ||
| if (nodeAfter) { | ||
| return editor.commands.command(({ tr }) => { | ||
| tr.setSelection(import_state.Selection.near(doc.resolve(after))); | ||
| return true; | ||
| }); | ||
| } | ||
| return editor.commands.exitCode(); | ||
| } | ||
| }; | ||
| }, | ||
| addInputRules() { | ||
| return [ | ||
| (0, import_core.textblockTypeInputRule)({ | ||
| find: backtickInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ | ||
| language: match[1] | ||
| }) | ||
| }), | ||
| (0, import_core.textblockTypeInputRule)({ | ||
| find: tildeInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ | ||
| language: match[1] | ||
| }) | ||
| }) | ||
| ]; | ||
| }, | ||
| addProseMirrorPlugins() { | ||
| return [ | ||
| // this plugin creates a code block for pasted content from VS Code | ||
| // we can also detect the copied code language | ||
| new import_state.Plugin({ | ||
| key: new import_state.PluginKey("codeBlockVSCodeHandler"), | ||
| props: { | ||
| handlePaste: (view, event) => { | ||
| if (!event.clipboardData) { | ||
| return false; | ||
| } | ||
| if (this.editor.isActive(this.type.name)) { | ||
| return false; | ||
| } | ||
| const text = event.clipboardData.getData("text/plain"); | ||
| const vscode = event.clipboardData.getData("vscode-editor-data"); | ||
| const vscodeData = vscode ? JSON.parse(vscode) : void 0; | ||
| const language = vscodeData == null ? void 0 : vscodeData.mode; | ||
| if (!text || !language) { | ||
| return false; | ||
| } | ||
| const { tr, schema } = view.state; | ||
| const textNode = schema.text(text.replace(/\r\n?/g, "\n")); | ||
| tr.replaceSelectionWith(this.type.create({ language }, textNode)); | ||
| if (tr.selection.$from.parent.type !== this.type) { | ||
| tr.setSelection( | ||
| import_state.TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))) | ||
| ); | ||
| } | ||
| tr.setMeta("paste", true); | ||
| view.dispatch(tr); | ||
| return true; | ||
| } | ||
| } | ||
| }) | ||
| ]; | ||
| } | ||
| let _tiptap_core = require("@tiptap/core"); | ||
| let _tiptap_pm_state = require("@tiptap/pm/state"); | ||
| //#region src/code-block.ts | ||
| const DEFAULT_TAB_SIZE = 4; | ||
| /** | ||
| * Matches a code block with backticks. | ||
| */ | ||
| const backtickInputRegex = /^```([a-z]+)?[\s\n]$/; | ||
| /** | ||
| * Matches a code block with tildes. | ||
| */ | ||
| const tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/; | ||
| /** | ||
| * This extension allows you to create code blocks. | ||
| * @see https://tiptap.dev/api/nodes/code-block | ||
| */ | ||
| const CodeBlock = _tiptap_core.Node.create({ | ||
| name: "codeBlock", | ||
| addOptions() { | ||
| return { | ||
| languageClassPrefix: "language-", | ||
| exitOnTripleEnter: true, | ||
| exitOnArrowDown: true, | ||
| exitOnArrowUp: true, | ||
| defaultLanguage: null, | ||
| enableTabIndentation: false, | ||
| tabSize: DEFAULT_TAB_SIZE, | ||
| HTMLAttributes: {} | ||
| }; | ||
| }, | ||
| content: "text*", | ||
| marks: "", | ||
| group: "block", | ||
| code: true, | ||
| defining: true, | ||
| addAttributes() { | ||
| return { language: { | ||
| default: this.options.defaultLanguage, | ||
| parseHTML: (element) => { | ||
| var _element$firstElement; | ||
| const { languageClassPrefix } = this.options; | ||
| if (!languageClassPrefix) return null; | ||
| const language = [...((_element$firstElement = element.firstElementChild) === null || _element$firstElement === void 0 ? void 0 : _element$firstElement.classList) || []].filter((className) => className.startsWith(languageClassPrefix)).map((className) => className.replace(languageClassPrefix, ""))[0]; | ||
| if (!language) return null; | ||
| return language; | ||
| }, | ||
| rendered: false | ||
| } }; | ||
| }, | ||
| parseHTML() { | ||
| return [{ | ||
| tag: "pre", | ||
| preserveWhitespace: "full" | ||
| }]; | ||
| }, | ||
| renderHTML({ node, HTMLAttributes }) { | ||
| return [ | ||
| "pre", | ||
| (0, _tiptap_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), | ||
| [ | ||
| "code", | ||
| { class: node.attrs.language ? this.options.languageClassPrefix + node.attrs.language : null }, | ||
| 0 | ||
| ] | ||
| ]; | ||
| }, | ||
| markdownTokenName: "code", | ||
| parseMarkdown: (token, helpers) => { | ||
| var _token$raw, _token$raw2; | ||
| if (((_token$raw = token.raw) === null || _token$raw === void 0 ? void 0 : _token$raw.startsWith("```")) === false && ((_token$raw2 = token.raw) === null || _token$raw2 === void 0 ? void 0 : _token$raw2.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") return []; | ||
| return helpers.createNode("codeBlock", { language: token.lang || null }, token.text ? [helpers.createTextNode(token.text)] : []); | ||
| }, | ||
| renderMarkdown: (node, h) => { | ||
| var _node$attrs; | ||
| let output = ""; | ||
| const language = ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.language) || ""; | ||
| if (!node.content) output = `\`\`\`${language}\n\n\`\`\``; | ||
| else output = [ | ||
| `\`\`\`${language}`, | ||
| h.renderChildren(node.content), | ||
| "```" | ||
| ].join("\n"); | ||
| return output; | ||
| }, | ||
| addCommands() { | ||
| return { | ||
| setCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.setNode(this.name, attributes); | ||
| }, | ||
| toggleCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.toggleNode(this.name, "paragraph", attributes); | ||
| } | ||
| }; | ||
| }, | ||
| addKeyboardShortcuts() { | ||
| return { | ||
| "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(), | ||
| Backspace: () => { | ||
| const { empty, $anchor } = this.editor.state.selection; | ||
| const isAtStart = $anchor.pos === 1; | ||
| if (!empty || $anchor.parent.type.name !== this.name) return false; | ||
| if (isAtStart || !$anchor.parent.textContent.length) return this.editor.commands.clearNodes(); | ||
| return false; | ||
| }, | ||
| Tab: ({ editor }) => { | ||
| var _this$options$tabSize; | ||
| if (!this.options.enableTabIndentation) return false; | ||
| const tabSize = (_this$options$tabSize = this.options.tabSize) !== null && _this$options$tabSize !== void 0 ? _this$options$tabSize : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) return false; | ||
| const indent = " ".repeat(tabSize); | ||
| if (empty) return editor.commands.insertContent(indent); | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const indentedText = state.doc.textBetween(from, to, "\n", "\n").split("\n").map((line) => indent + line).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(indentedText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| "Shift-Tab": ({ editor }) => { | ||
| var _this$options$tabSize2; | ||
| if (!this.options.enableTabIndentation) return false; | ||
| const tabSize = (_this$options$tabSize2 = this.options.tabSize) !== null && _this$options$tabSize2 !== void 0 ? _this$options$tabSize2 : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) return false; | ||
| if (empty) return editor.commands.command(({ tr }) => { | ||
| var _currentLine$match; | ||
| const { pos } = $from; | ||
| const codeBlockStart = $from.start(); | ||
| const codeBlockEnd = $from.end(); | ||
| const lines = state.doc.textBetween(codeBlockStart, codeBlockEnd, "\n", "\n").split("\n"); | ||
| let currentLineIndex = 0; | ||
| let charCount = 0; | ||
| const relativeCursorPos = pos - codeBlockStart; | ||
| for (let i = 0; i < lines.length; i += 1) { | ||
| if (charCount + lines[i].length >= relativeCursorPos) { | ||
| currentLineIndex = i; | ||
| break; | ||
| } | ||
| charCount += lines[i].length + 1; | ||
| } | ||
| const leadingSpaces = ((_currentLine$match = lines[currentLineIndex].match(/^ */)) === null || _currentLine$match === void 0 ? void 0 : _currentLine$match[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| if (spacesToRemove === 0) return true; | ||
| let lineStartPos = codeBlockStart; | ||
| for (let i = 0; i < currentLineIndex; i += 1) lineStartPos += lines[i].length + 1; | ||
| tr.delete(lineStartPos, lineStartPos + spacesToRemove); | ||
| if (pos - lineStartPos <= spacesToRemove) tr.setSelection(_tiptap_pm_state.TextSelection.create(tr.doc, lineStartPos)); | ||
| return true; | ||
| }); | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const reverseIndentText = state.doc.textBetween(from, to, "\n", "\n").split("\n").map((line) => { | ||
| var _line$match; | ||
| const leadingSpaces = ((_line$match = line.match(/^ */)) === null || _line$match === void 0 ? void 0 : _line$match[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| return line.slice(spacesToRemove); | ||
| }).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(reverseIndentText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| Enter: ({ editor }) => { | ||
| if (!this.options.exitOnTripleEnter) return false; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n"); | ||
| if (!isAtEnd || !endsWithDoubleNewline) return false; | ||
| return editor.chain().command(({ tr }) => { | ||
| tr.delete($from.pos - 2, $from.pos); | ||
| return true; | ||
| }).exitCode().run(); | ||
| }, | ||
| ArrowUp: ({ editor }) => { | ||
| if (!this.options.exitOnArrowUp) return false; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| if ($from.parentOffset !== 0) return false; | ||
| const before = $from.before(); | ||
| if (before > 0) return false; | ||
| return editor.commands.insertDefaultBlock({ pos: before }); | ||
| }, | ||
| ArrowDown: ({ editor }) => { | ||
| if (!this.options.exitOnArrowDown) return false; | ||
| const { state } = editor; | ||
| const { selection, doc } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| if (!($from.parentOffset === $from.parent.nodeSize - 2)) return false; | ||
| const after = $from.after(); | ||
| if (after === void 0) return false; | ||
| if (doc.nodeAt(after)) return editor.commands.command(({ tr }) => { | ||
| tr.setSelection(_tiptap_pm_state.Selection.near(doc.resolve(after))); | ||
| return true; | ||
| }); | ||
| return editor.commands.exitCode(); | ||
| } | ||
| }; | ||
| }, | ||
| addInputRules() { | ||
| return [(0, _tiptap_core.textblockTypeInputRule)({ | ||
| find: backtickInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ language: match[1] }) | ||
| }), (0, _tiptap_core.textblockTypeInputRule)({ | ||
| find: tildeInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ language: match[1] }) | ||
| })]; | ||
| }, | ||
| addProseMirrorPlugins() { | ||
| return [new _tiptap_pm_state.Plugin({ | ||
| key: new _tiptap_pm_state.PluginKey("codeBlockVSCodeHandler"), | ||
| props: { handlePaste: (view, event) => { | ||
| if (!event.clipboardData) return false; | ||
| if (this.editor.isActive(this.type.name)) return false; | ||
| const text = event.clipboardData.getData("text/plain"); | ||
| const vscode = event.clipboardData.getData("vscode-editor-data"); | ||
| const vscodeData = vscode ? JSON.parse(vscode) : void 0; | ||
| const language = vscodeData === null || vscodeData === void 0 ? void 0 : vscodeData.mode; | ||
| if (!text || !language) return false; | ||
| const { tr, schema } = view.state; | ||
| const textNode = schema.text(text.replace(/\r\n?/g, "\n")); | ||
| tr.replaceSelectionWith(this.type.create({ language }, textNode)); | ||
| if (tr.selection.$from.parent.type !== this.type) tr.setSelection(_tiptap_pm_state.TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2)))); | ||
| tr.setMeta("paste", true); | ||
| view.dispatch(tr); | ||
| return true; | ||
| } } | ||
| })]; | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/index.ts | ||
| var src_default = CodeBlock; | ||
| //#endregion | ||
| exports.CodeBlock = CodeBlock; | ||
| exports.backtickInputRegex = backtickInputRegex; | ||
| exports.default = src_default; | ||
| exports.tildeInputRegex = tildeInputRegex; | ||
| // src/index.ts | ||
| var index_default = CodeBlock; | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| CodeBlock, | ||
| backtickInputRegex, | ||
| tildeInputRegex | ||
| }); | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/index.ts","../src/code-block.ts"],"sourcesContent":["import { CodeBlock } from './code-block.js'\n\nexport * from './code-block.js'\n\nexport default CodeBlock\n","import { mergeAttributes, Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\n\nconst DEFAULT_TAB_SIZE = 4\n\nexport interface CodeBlockOptions {\n /**\n * Adds a prefix to language classes that are applied to code tags.\n * @default 'language-'\n */\n languageClassPrefix: string | null | undefined\n /**\n * Define whether the node should be exited on triple enter.\n * @default true\n */\n exitOnTripleEnter: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow down if there is no node after it.\n * @default true\n */\n exitOnArrowDown: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow up if there is no node before it.\n * @default true\n */\n exitOnArrowUp: boolean | null | undefined\n /**\n * The default language.\n * @default null\n * @example 'js'\n */\n defaultLanguage: string | null | undefined\n /**\n * Enable tab key for indentation in code blocks.\n * @default false\n */\n enableTabIndentation: boolean | null | undefined\n /**\n * The number of spaces to use for tab indentation.\n * @default 4\n */\n tabSize: number | null | undefined\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n * @param attributes Code block attributes\n * @example editor.commands.setCodeBlock({ language: 'javascript' })\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType\n /**\n * Toggle a code block\n * @param attributes Code block attributes\n * @example editor.commands.toggleCodeBlock({ language: 'javascript' })\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType\n }\n }\n}\n\n/**\n * Matches a code block with backticks.\n */\nexport const backtickInputRegex = /^```([a-z]+)?[\\s\\n]$/\n\n/**\n * Matches a code block with tildes.\n */\nexport const tildeInputRegex = /^~~~([a-z]+)?[\\s\\n]$/\n\n/**\n * This extension allows you to create code blocks.\n * @see https://tiptap.dev/api/nodes/code-block\n */\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n addOptions() {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: true,\n exitOnArrowDown: true,\n exitOnArrowUp: true,\n defaultLanguage: null,\n enableTabIndentation: false,\n tabSize: DEFAULT_TAB_SIZE,\n HTMLAttributes: {},\n }\n },\n\n content: 'text*',\n\n marks: '',\n\n group: 'block',\n\n code: true,\n\n defining: true,\n\n addAttributes() {\n return {\n language: {\n default: this.options.defaultLanguage,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\n\n if (!languageClassPrefix) {\n return null\n }\n\n const classNames = [...(element.firstElementChild?.classList || [])]\n const languages = classNames\n .filter(className => className.startsWith(languageClassPrefix))\n .map(className => className.replace(languageClassPrefix, ''))\n const language = languages[0]\n\n if (!language) {\n return null\n }\n\n return language\n },\n rendered: false,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n [\n 'code',\n {\n class: node.attrs.language\n ? this.options.languageClassPrefix + node.attrs.language\n : null,\n },\n 0,\n ],\n ]\n },\n\n markdownTokenName: 'code',\n\n parseMarkdown: (token, helpers) => {\n if (\n token.raw?.startsWith('```') === false &&\n token.raw?.startsWith('~~~') === false &&\n token.codeBlockStyle !== 'indented'\n ) {\n return []\n }\n\n return helpers.createNode(\n 'codeBlock',\n { language: token.lang || null },\n token.text ? [helpers.createTextNode(token.text)] : [],\n )\n },\n\n renderMarkdown: (node, h) => {\n let output = ''\n const language = node.attrs?.language || ''\n\n if (!node.content) {\n output = `\\`\\`\\`${language}\\n\\n\\`\\`\\``\n } else {\n const lines = [`\\`\\`\\`${language}`, h.renderChildren(node.content), '```']\n output = lines.join('\\n')\n }\n\n return output\n },\n\n addCommands() {\n return {\n setCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.setNode(this.name, attributes)\n },\n toggleCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.toggleNode(this.name, 'paragraph', attributes)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Alt-c': () => this.editor.commands.toggleCodeBlock(),\n\n // remove code block when at start of document or code block is empty\n Backspace: () => {\n const { empty, $anchor } = this.editor.state.selection\n const isAtStart = $anchor.pos === 1\n\n if (!empty || $anchor.parent.type.name !== this.name) {\n return false\n }\n\n if (isAtStart || !$anchor.parent.textContent.length) {\n return this.editor.commands.clearNodes()\n }\n\n return false\n },\n\n // handle tab indentation\n Tab: ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n const indent = ' '.repeat(tabSize)\n\n if (empty) {\n return editor.commands.insertContent(indent)\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const indentedText = lines.map(line => indent + line).join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(indentedText))\n return true\n })\n },\n\n // handle shift+tab reverse indentation\n 'Shift-Tab': ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n if (empty) {\n return editor.commands.command(({ tr }) => {\n const { pos } = $from\n const codeBlockStart = $from.start()\n const codeBlockEnd = $from.end()\n\n const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, '\\n', '\\n')\n const lines = allText.split('\\n')\n\n let currentLineIndex = 0\n let charCount = 0\n const relativeCursorPos = pos - codeBlockStart\n\n for (let i = 0; i < lines.length; i += 1) {\n if (charCount + lines[i].length >= relativeCursorPos) {\n currentLineIndex = i\n break\n }\n charCount += lines[i].length + 1\n }\n\n const currentLine = lines[currentLineIndex]\n const leadingSpaces = currentLine.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n\n if (spacesToRemove === 0) {\n return true\n }\n\n let lineStartPos = codeBlockStart\n for (let i = 0; i < currentLineIndex; i += 1) {\n lineStartPos += lines[i].length + 1\n }\n\n tr.delete(lineStartPos, lineStartPos + spacesToRemove)\n\n const cursorPosInLine = pos - lineStartPos\n if (cursorPosInLine <= spacesToRemove) {\n tr.setSelection(TextSelection.create(tr.doc, lineStartPos))\n }\n\n return true\n })\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const reverseIndentText = lines\n .map(line => {\n const leadingSpaces = line.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n return line.slice(spacesToRemove)\n })\n .join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(reverseIndentText))\n return true\n })\n },\n\n // exit node on triple enter\n Enter: ({ editor }) => {\n if (!this.options.exitOnTripleEnter) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n const endsWithDoubleNewline = $from.parent.textContent.endsWith('\\n\\n')\n\n if (!isAtEnd || !endsWithDoubleNewline) {\n return false\n }\n\n return editor\n .chain()\n .command(({ tr }) => {\n tr.delete($from.pos - 2, $from.pos)\n\n return true\n })\n .exitCode()\n .run()\n },\n\n // exit node on arrow up if there is no node before it\n ArrowUp: ({ editor }) => {\n if (!this.options.exitOnArrowUp) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n if ($from.parentOffset !== 0) {\n return false\n }\n\n const before = $from.before()\n\n if (before > 0) {\n return false\n }\n\n return editor.commands.insertDefaultBlock({ pos: before })\n },\n\n // exit node on arrow down\n ArrowDown: ({ editor }) => {\n if (!this.options.exitOnArrowDown) {\n return false\n }\n\n const { state } = editor\n const { selection, doc } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n\n if (!isAtEnd) {\n return false\n }\n\n const after = $from.after()\n\n if (after === undefined) {\n return false\n }\n\n const nodeAfter = doc.nodeAt(after)\n\n if (nodeAfter) {\n return editor.commands.command(({ tr }) => {\n tr.setSelection(Selection.near(doc.resolve(after)))\n return true\n })\n }\n\n return editor.commands.exitCode()\n },\n }\n },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n return [\n // this plugin creates a code block for pasted content from VS Code\n // we can also detect the copied code language\n new Plugin({\n key: new PluginKey('codeBlockVSCodeHandler'),\n props: {\n handlePaste: (view, event) => {\n if (!event.clipboardData) {\n return false\n }\n\n // don’t create a new code block within code blocks\n if (this.editor.isActive(this.type.name)) {\n return false\n }\n\n const text = event.clipboardData.getData('text/plain')\n const vscode = event.clipboardData.getData('vscode-editor-data')\n const vscodeData = vscode ? JSON.parse(vscode) : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr, schema } = view.state\n\n // prepare a text node\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n const textNode = schema.text(text.replace(/\\r\\n?/g, '\\n'))\n\n // create a code block with the text node\n // replace selection with the code block\n tr.replaceSelectionWith(this.type.create({ language }, textNode))\n\n if (tr.selection.$from.parent.type !== this.type) {\n // put cursor inside the newly created code block\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))),\n )\n }\n\n // store meta information\n // this is useful for other plugins that depends on the paste event\n // like the paste rule plugin\n tr.setMeta('paste', true)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n"],"mappings":"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","names":["_a"]} | ||
| {"version":3,"file":"index.cjs","names":["Node","TextSelection","Selection","Plugin","PluginKey"],"sources":["../src/code-block.ts","../src/index.ts"],"sourcesContent":["import { mergeAttributes, Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\n\nconst DEFAULT_TAB_SIZE = 4\n\nexport interface CodeBlockOptions {\n /**\n * Adds a prefix to language classes that are applied to code tags.\n * @default 'language-'\n */\n languageClassPrefix: string | null | undefined\n /**\n * Define whether the node should be exited on triple enter.\n * @default true\n */\n exitOnTripleEnter: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow down if there is no node after it.\n * @default true\n */\n exitOnArrowDown: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow up if there is no node before it.\n * @default true\n */\n exitOnArrowUp: boolean | null | undefined\n /**\n * The default language.\n * @default null\n * @example 'js'\n */\n defaultLanguage: string | null | undefined\n /**\n * Enable tab key for indentation in code blocks.\n * @default false\n */\n enableTabIndentation: boolean | null | undefined\n /**\n * The number of spaces to use for tab indentation.\n * @default 4\n */\n tabSize: number | null | undefined\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n * @param attributes Code block attributes\n * @example editor.commands.setCodeBlock({ language: 'javascript' })\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType\n /**\n * Toggle a code block\n * @param attributes Code block attributes\n * @example editor.commands.toggleCodeBlock({ language: 'javascript' })\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType\n }\n }\n}\n\n/**\n * Matches a code block with backticks.\n */\nexport const backtickInputRegex = /^```([a-z]+)?[\\s\\n]$/\n\n/**\n * Matches a code block with tildes.\n */\nexport const tildeInputRegex = /^~~~([a-z]+)?[\\s\\n]$/\n\n/**\n * This extension allows you to create code blocks.\n * @see https://tiptap.dev/api/nodes/code-block\n */\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n addOptions() {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: true,\n exitOnArrowDown: true,\n exitOnArrowUp: true,\n defaultLanguage: null,\n enableTabIndentation: false,\n tabSize: DEFAULT_TAB_SIZE,\n HTMLAttributes: {},\n }\n },\n\n content: 'text*',\n\n marks: '',\n\n group: 'block',\n\n code: true,\n\n defining: true,\n\n addAttributes() {\n return {\n language: {\n default: this.options.defaultLanguage,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\n\n if (!languageClassPrefix) {\n return null\n }\n\n const classNames = [...(element.firstElementChild?.classList || [])]\n const languages = classNames\n .filter(className => className.startsWith(languageClassPrefix))\n .map(className => className.replace(languageClassPrefix, ''))\n const language = languages[0]\n\n if (!language) {\n return null\n }\n\n return language\n },\n rendered: false,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n [\n 'code',\n {\n class: node.attrs.language\n ? this.options.languageClassPrefix + node.attrs.language\n : null,\n },\n 0,\n ],\n ]\n },\n\n markdownTokenName: 'code',\n\n parseMarkdown: (token, helpers) => {\n if (\n token.raw?.startsWith('```') === false &&\n token.raw?.startsWith('~~~') === false &&\n token.codeBlockStyle !== 'indented'\n ) {\n return []\n }\n\n return helpers.createNode(\n 'codeBlock',\n { language: token.lang || null },\n token.text ? [helpers.createTextNode(token.text)] : [],\n )\n },\n\n renderMarkdown: (node, h) => {\n let output = ''\n const language = node.attrs?.language || ''\n\n if (!node.content) {\n output = `\\`\\`\\`${language}\\n\\n\\`\\`\\``\n } else {\n const lines = [`\\`\\`\\`${language}`, h.renderChildren(node.content), '```']\n output = lines.join('\\n')\n }\n\n return output\n },\n\n addCommands() {\n return {\n setCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.setNode(this.name, attributes)\n },\n toggleCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.toggleNode(this.name, 'paragraph', attributes)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Alt-c': () => this.editor.commands.toggleCodeBlock(),\n\n // remove code block when at start of document or code block is empty\n Backspace: () => {\n const { empty, $anchor } = this.editor.state.selection\n const isAtStart = $anchor.pos === 1\n\n if (!empty || $anchor.parent.type.name !== this.name) {\n return false\n }\n\n if (isAtStart || !$anchor.parent.textContent.length) {\n return this.editor.commands.clearNodes()\n }\n\n return false\n },\n\n // handle tab indentation\n Tab: ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n const indent = ' '.repeat(tabSize)\n\n if (empty) {\n return editor.commands.insertContent(indent)\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const indentedText = lines.map(line => indent + line).join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(indentedText))\n return true\n })\n },\n\n // handle shift+tab reverse indentation\n 'Shift-Tab': ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n if (empty) {\n return editor.commands.command(({ tr }) => {\n const { pos } = $from\n const codeBlockStart = $from.start()\n const codeBlockEnd = $from.end()\n\n const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, '\\n', '\\n')\n const lines = allText.split('\\n')\n\n let currentLineIndex = 0\n let charCount = 0\n const relativeCursorPos = pos - codeBlockStart\n\n for (let i = 0; i < lines.length; i += 1) {\n if (charCount + lines[i].length >= relativeCursorPos) {\n currentLineIndex = i\n break\n }\n charCount += lines[i].length + 1\n }\n\n const currentLine = lines[currentLineIndex]\n const leadingSpaces = currentLine.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n\n if (spacesToRemove === 0) {\n return true\n }\n\n let lineStartPos = codeBlockStart\n for (let i = 0; i < currentLineIndex; i += 1) {\n lineStartPos += lines[i].length + 1\n }\n\n tr.delete(lineStartPos, lineStartPos + spacesToRemove)\n\n const cursorPosInLine = pos - lineStartPos\n if (cursorPosInLine <= spacesToRemove) {\n tr.setSelection(TextSelection.create(tr.doc, lineStartPos))\n }\n\n return true\n })\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const reverseIndentText = lines\n .map(line => {\n const leadingSpaces = line.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n return line.slice(spacesToRemove)\n })\n .join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(reverseIndentText))\n return true\n })\n },\n\n // exit node on triple enter\n Enter: ({ editor }) => {\n if (!this.options.exitOnTripleEnter) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n const endsWithDoubleNewline = $from.parent.textContent.endsWith('\\n\\n')\n\n if (!isAtEnd || !endsWithDoubleNewline) {\n return false\n }\n\n return editor\n .chain()\n .command(({ tr }) => {\n tr.delete($from.pos - 2, $from.pos)\n\n return true\n })\n .exitCode()\n .run()\n },\n\n // exit node on arrow up if there is no node before it\n ArrowUp: ({ editor }) => {\n if (!this.options.exitOnArrowUp) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n if ($from.parentOffset !== 0) {\n return false\n }\n\n const before = $from.before()\n\n if (before > 0) {\n return false\n }\n\n return editor.commands.insertDefaultBlock({ pos: before })\n },\n\n // exit node on arrow down\n ArrowDown: ({ editor }) => {\n if (!this.options.exitOnArrowDown) {\n return false\n }\n\n const { state } = editor\n const { selection, doc } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n\n if (!isAtEnd) {\n return false\n }\n\n const after = $from.after()\n\n if (after === undefined) {\n return false\n }\n\n const nodeAfter = doc.nodeAt(after)\n\n if (nodeAfter) {\n return editor.commands.command(({ tr }) => {\n tr.setSelection(Selection.near(doc.resolve(after)))\n return true\n })\n }\n\n return editor.commands.exitCode()\n },\n }\n },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n return [\n // this plugin creates a code block for pasted content from VS Code\n // we can also detect the copied code language\n new Plugin({\n key: new PluginKey('codeBlockVSCodeHandler'),\n props: {\n handlePaste: (view, event) => {\n if (!event.clipboardData) {\n return false\n }\n\n // don’t create a new code block within code blocks\n if (this.editor.isActive(this.type.name)) {\n return false\n }\n\n const text = event.clipboardData.getData('text/plain')\n const vscode = event.clipboardData.getData('vscode-editor-data')\n const vscodeData = vscode ? JSON.parse(vscode) : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr, schema } = view.state\n\n // prepare a text node\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n const textNode = schema.text(text.replace(/\\r\\n?/g, '\\n'))\n\n // create a code block with the text node\n // replace selection with the code block\n tr.replaceSelectionWith(this.type.create({ language }, textNode))\n\n if (tr.selection.$from.parent.type !== this.type) {\n // put cursor inside the newly created code block\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))),\n )\n }\n\n // store meta information\n // this is useful for other plugins that depends on the paste event\n // like the paste rule plugin\n tr.setMeta('paste', true)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n","import { CodeBlock } from './code-block.js'\n\nexport * from './code-block.js'\n\nexport default CodeBlock\n"],"mappings":"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"} |
+67
-66
@@ -1,68 +0,68 @@ | ||
| import { Node } from '@tiptap/core'; | ||
| import { Node } from "@tiptap/core"; | ||
| //#region src/code-block.d.ts | ||
| interface CodeBlockOptions { | ||
| /** | ||
| * Adds a prefix to language classes that are applied to code tags. | ||
| * @default 'language-' | ||
| */ | ||
| languageClassPrefix: string | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on triple enter. | ||
| * @default true | ||
| */ | ||
| exitOnTripleEnter: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow down if there is no node after it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowDown: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow up if there is no node before it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowUp: boolean | null | undefined; | ||
| /** | ||
| * The default language. | ||
| * @default null | ||
| * @example 'js' | ||
| */ | ||
| defaultLanguage: string | null | undefined; | ||
| /** | ||
| * Enable tab key for indentation in code blocks. | ||
| * @default false | ||
| */ | ||
| enableTabIndentation: boolean | null | undefined; | ||
| /** | ||
| * The number of spaces to use for tab indentation. | ||
| * @default 4 | ||
| */ | ||
| tabSize: number | null | undefined; | ||
| /** | ||
| * Custom HTML attributes that should be added to the rendered HTML tag. | ||
| * @default {} | ||
| * @example { class: 'foo' } | ||
| */ | ||
| HTMLAttributes: Record<string, any>; | ||
| /** | ||
| * Adds a prefix to language classes that are applied to code tags. | ||
| * @default 'language-' | ||
| */ | ||
| languageClassPrefix: string | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on triple enter. | ||
| * @default true | ||
| */ | ||
| exitOnTripleEnter: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow down if there is no node after it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowDown: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow up if there is no node before it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowUp: boolean | null | undefined; | ||
| /** | ||
| * The default language. | ||
| * @default null | ||
| * @example 'js' | ||
| */ | ||
| defaultLanguage: string | null | undefined; | ||
| /** | ||
| * Enable tab key for indentation in code blocks. | ||
| * @default false | ||
| */ | ||
| enableTabIndentation: boolean | null | undefined; | ||
| /** | ||
| * The number of spaces to use for tab indentation. | ||
| * @default 4 | ||
| */ | ||
| tabSize: number | null | undefined; | ||
| /** | ||
| * Custom HTML attributes that should be added to the rendered HTML tag. | ||
| * @default {} | ||
| * @example { class: 'foo' } | ||
| */ | ||
| HTMLAttributes: Record<string, any>; | ||
| } | ||
| declare module '@tiptap/core' { | ||
| interface Commands<ReturnType> { | ||
| codeBlock: { | ||
| /** | ||
| * Set a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.setCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| setCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| /** | ||
| * Toggle a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.toggleCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| toggleCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| }; | ||
| } | ||
| interface Commands<ReturnType> { | ||
| codeBlock: { | ||
| /** | ||
| * Set a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.setCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| setCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| /** | ||
| * Toggle a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.toggleCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| toggleCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| }; | ||
| } | ||
| } | ||
@@ -82,3 +82,4 @@ /** | ||
| declare const CodeBlock: Node<CodeBlockOptions, any>; | ||
| export { CodeBlock, type CodeBlockOptions, backtickInputRegex, CodeBlock as default, tildeInputRegex }; | ||
| //#endregion | ||
| export { CodeBlock, CodeBlock as default, CodeBlockOptions, backtickInputRegex, tildeInputRegex }; | ||
| //# sourceMappingURL=index.d.cts.map |
+67
-66
@@ -1,68 +0,68 @@ | ||
| import { Node } from '@tiptap/core'; | ||
| import { Node } from "@tiptap/core"; | ||
| //#region src/code-block.d.ts | ||
| interface CodeBlockOptions { | ||
| /** | ||
| * Adds a prefix to language classes that are applied to code tags. | ||
| * @default 'language-' | ||
| */ | ||
| languageClassPrefix: string | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on triple enter. | ||
| * @default true | ||
| */ | ||
| exitOnTripleEnter: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow down if there is no node after it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowDown: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow up if there is no node before it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowUp: boolean | null | undefined; | ||
| /** | ||
| * The default language. | ||
| * @default null | ||
| * @example 'js' | ||
| */ | ||
| defaultLanguage: string | null | undefined; | ||
| /** | ||
| * Enable tab key for indentation in code blocks. | ||
| * @default false | ||
| */ | ||
| enableTabIndentation: boolean | null | undefined; | ||
| /** | ||
| * The number of spaces to use for tab indentation. | ||
| * @default 4 | ||
| */ | ||
| tabSize: number | null | undefined; | ||
| /** | ||
| * Custom HTML attributes that should be added to the rendered HTML tag. | ||
| * @default {} | ||
| * @example { class: 'foo' } | ||
| */ | ||
| HTMLAttributes: Record<string, any>; | ||
| /** | ||
| * Adds a prefix to language classes that are applied to code tags. | ||
| * @default 'language-' | ||
| */ | ||
| languageClassPrefix: string | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on triple enter. | ||
| * @default true | ||
| */ | ||
| exitOnTripleEnter: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow down if there is no node after it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowDown: boolean | null | undefined; | ||
| /** | ||
| * Define whether the node should be exited on arrow up if there is no node before it. | ||
| * @default true | ||
| */ | ||
| exitOnArrowUp: boolean | null | undefined; | ||
| /** | ||
| * The default language. | ||
| * @default null | ||
| * @example 'js' | ||
| */ | ||
| defaultLanguage: string | null | undefined; | ||
| /** | ||
| * Enable tab key for indentation in code blocks. | ||
| * @default false | ||
| */ | ||
| enableTabIndentation: boolean | null | undefined; | ||
| /** | ||
| * The number of spaces to use for tab indentation. | ||
| * @default 4 | ||
| */ | ||
| tabSize: number | null | undefined; | ||
| /** | ||
| * Custom HTML attributes that should be added to the rendered HTML tag. | ||
| * @default {} | ||
| * @example { class: 'foo' } | ||
| */ | ||
| HTMLAttributes: Record<string, any>; | ||
| } | ||
| declare module '@tiptap/core' { | ||
| interface Commands<ReturnType> { | ||
| codeBlock: { | ||
| /** | ||
| * Set a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.setCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| setCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| /** | ||
| * Toggle a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.toggleCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| toggleCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| }; | ||
| } | ||
| interface Commands<ReturnType> { | ||
| codeBlock: { | ||
| /** | ||
| * Set a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.setCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| setCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| /** | ||
| * Toggle a code block | ||
| * @param attributes Code block attributes | ||
| * @example editor.commands.toggleCodeBlock({ language: 'javascript' }) | ||
| */ | ||
| toggleCodeBlock: (attributes?: { | ||
| language: string; | ||
| }) => ReturnType; | ||
| }; | ||
| } | ||
| } | ||
@@ -82,3 +82,4 @@ /** | ||
| declare const CodeBlock: Node<CodeBlockOptions, any>; | ||
| export { CodeBlock, type CodeBlockOptions, backtickInputRegex, CodeBlock as default, tildeInputRegex }; | ||
| //#endregion | ||
| export { CodeBlock, CodeBlock as default, CodeBlockOptions, backtickInputRegex, tildeInputRegex }; | ||
| //# sourceMappingURL=index.d.ts.map |
+244
-341
@@ -1,345 +0,248 @@ | ||
| // src/code-block.ts | ||
| import { mergeAttributes, Node, textblockTypeInputRule } from "@tiptap/core"; | ||
| import { Node, mergeAttributes, textblockTypeInputRule } from "@tiptap/core"; | ||
| import { Plugin, PluginKey, Selection, TextSelection } from "@tiptap/pm/state"; | ||
| var DEFAULT_TAB_SIZE = 4; | ||
| var backtickInputRegex = /^```([a-z]+)?[\s\n]$/; | ||
| var tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/; | ||
| var CodeBlock = Node.create({ | ||
| name: "codeBlock", | ||
| addOptions() { | ||
| return { | ||
| languageClassPrefix: "language-", | ||
| exitOnTripleEnter: true, | ||
| exitOnArrowDown: true, | ||
| exitOnArrowUp: true, | ||
| defaultLanguage: null, | ||
| enableTabIndentation: false, | ||
| tabSize: DEFAULT_TAB_SIZE, | ||
| HTMLAttributes: {} | ||
| }; | ||
| }, | ||
| content: "text*", | ||
| marks: "", | ||
| group: "block", | ||
| code: true, | ||
| defining: true, | ||
| addAttributes() { | ||
| return { | ||
| language: { | ||
| default: this.options.defaultLanguage, | ||
| parseHTML: (element) => { | ||
| var _a; | ||
| const { languageClassPrefix } = this.options; | ||
| if (!languageClassPrefix) { | ||
| return null; | ||
| } | ||
| const classNames = [...((_a = element.firstElementChild) == null ? void 0 : _a.classList) || []]; | ||
| const languages = classNames.filter((className) => className.startsWith(languageClassPrefix)).map((className) => className.replace(languageClassPrefix, "")); | ||
| const language = languages[0]; | ||
| if (!language) { | ||
| return null; | ||
| } | ||
| return language; | ||
| }, | ||
| rendered: false | ||
| } | ||
| }; | ||
| }, | ||
| parseHTML() { | ||
| return [ | ||
| { | ||
| tag: "pre", | ||
| preserveWhitespace: "full" | ||
| } | ||
| ]; | ||
| }, | ||
| renderHTML({ node, HTMLAttributes }) { | ||
| return [ | ||
| "pre", | ||
| mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), | ||
| [ | ||
| "code", | ||
| { | ||
| class: node.attrs.language ? this.options.languageClassPrefix + node.attrs.language : null | ||
| }, | ||
| 0 | ||
| ] | ||
| ]; | ||
| }, | ||
| markdownTokenName: "code", | ||
| parseMarkdown: (token, helpers) => { | ||
| var _a, _b; | ||
| if (((_a = token.raw) == null ? void 0 : _a.startsWith("```")) === false && ((_b = token.raw) == null ? void 0 : _b.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") { | ||
| return []; | ||
| } | ||
| return helpers.createNode( | ||
| "codeBlock", | ||
| { language: token.lang || null }, | ||
| token.text ? [helpers.createTextNode(token.text)] : [] | ||
| ); | ||
| }, | ||
| renderMarkdown: (node, h) => { | ||
| var _a; | ||
| let output = ""; | ||
| const language = ((_a = node.attrs) == null ? void 0 : _a.language) || ""; | ||
| if (!node.content) { | ||
| output = `\`\`\`${language} | ||
| \`\`\``; | ||
| } else { | ||
| const lines = [`\`\`\`${language}`, h.renderChildren(node.content), "```"]; | ||
| output = lines.join("\n"); | ||
| } | ||
| return output; | ||
| }, | ||
| addCommands() { | ||
| return { | ||
| setCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.setNode(this.name, attributes); | ||
| }, | ||
| toggleCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.toggleNode(this.name, "paragraph", attributes); | ||
| } | ||
| }; | ||
| }, | ||
| addKeyboardShortcuts() { | ||
| return { | ||
| "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(), | ||
| // remove code block when at start of document or code block is empty | ||
| Backspace: () => { | ||
| const { empty, $anchor } = this.editor.state.selection; | ||
| const isAtStart = $anchor.pos === 1; | ||
| if (!empty || $anchor.parent.type.name !== this.name) { | ||
| return false; | ||
| } | ||
| if (isAtStart || !$anchor.parent.textContent.length) { | ||
| return this.editor.commands.clearNodes(); | ||
| } | ||
| return false; | ||
| }, | ||
| // handle tab indentation | ||
| Tab: ({ editor }) => { | ||
| var _a; | ||
| if (!this.options.enableTabIndentation) { | ||
| return false; | ||
| } | ||
| const tabSize = (_a = this.options.tabSize) != null ? _a : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const indent = " ".repeat(tabSize); | ||
| if (empty) { | ||
| return editor.commands.insertContent(indent); | ||
| } | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const text = state.doc.textBetween(from, to, "\n", "\n"); | ||
| const lines = text.split("\n"); | ||
| const indentedText = lines.map((line) => indent + line).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(indentedText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| // handle shift+tab reverse indentation | ||
| "Shift-Tab": ({ editor }) => { | ||
| var _a; | ||
| if (!this.options.enableTabIndentation) { | ||
| return false; | ||
| } | ||
| const tabSize = (_a = this.options.tabSize) != null ? _a : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| if (empty) { | ||
| return editor.commands.command(({ tr }) => { | ||
| var _a2; | ||
| const { pos } = $from; | ||
| const codeBlockStart = $from.start(); | ||
| const codeBlockEnd = $from.end(); | ||
| const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, "\n", "\n"); | ||
| const lines = allText.split("\n"); | ||
| let currentLineIndex = 0; | ||
| let charCount = 0; | ||
| const relativeCursorPos = pos - codeBlockStart; | ||
| for (let i = 0; i < lines.length; i += 1) { | ||
| if (charCount + lines[i].length >= relativeCursorPos) { | ||
| currentLineIndex = i; | ||
| break; | ||
| } | ||
| charCount += lines[i].length + 1; | ||
| } | ||
| const currentLine = lines[currentLineIndex]; | ||
| const leadingSpaces = ((_a2 = currentLine.match(/^ */)) == null ? void 0 : _a2[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| if (spacesToRemove === 0) { | ||
| return true; | ||
| } | ||
| let lineStartPos = codeBlockStart; | ||
| for (let i = 0; i < currentLineIndex; i += 1) { | ||
| lineStartPos += lines[i].length + 1; | ||
| } | ||
| tr.delete(lineStartPos, lineStartPos + spacesToRemove); | ||
| const cursorPosInLine = pos - lineStartPos; | ||
| if (cursorPosInLine <= spacesToRemove) { | ||
| tr.setSelection(TextSelection.create(tr.doc, lineStartPos)); | ||
| } | ||
| return true; | ||
| }); | ||
| } | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const text = state.doc.textBetween(from, to, "\n", "\n"); | ||
| const lines = text.split("\n"); | ||
| const reverseIndentText = lines.map((line) => { | ||
| var _a2; | ||
| const leadingSpaces = ((_a2 = line.match(/^ */)) == null ? void 0 : _a2[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| return line.slice(spacesToRemove); | ||
| }).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(reverseIndentText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| // exit node on triple enter | ||
| Enter: ({ editor }) => { | ||
| if (!this.options.exitOnTripleEnter) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n"); | ||
| if (!isAtEnd || !endsWithDoubleNewline) { | ||
| return false; | ||
| } | ||
| return editor.chain().command(({ tr }) => { | ||
| tr.delete($from.pos - 2, $from.pos); | ||
| return true; | ||
| }).exitCode().run(); | ||
| }, | ||
| // exit node on arrow up if there is no node before it | ||
| ArrowUp: ({ editor }) => { | ||
| if (!this.options.exitOnArrowUp) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| if ($from.parentOffset !== 0) { | ||
| return false; | ||
| } | ||
| const before = $from.before(); | ||
| if (before > 0) { | ||
| return false; | ||
| } | ||
| return editor.commands.insertDefaultBlock({ pos: before }); | ||
| }, | ||
| // exit node on arrow down | ||
| ArrowDown: ({ editor }) => { | ||
| if (!this.options.exitOnArrowDown) { | ||
| return false; | ||
| } | ||
| const { state } = editor; | ||
| const { selection, doc } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) { | ||
| return false; | ||
| } | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| if (!isAtEnd) { | ||
| return false; | ||
| } | ||
| const after = $from.after(); | ||
| if (after === void 0) { | ||
| return false; | ||
| } | ||
| const nodeAfter = doc.nodeAt(after); | ||
| if (nodeAfter) { | ||
| return editor.commands.command(({ tr }) => { | ||
| tr.setSelection(Selection.near(doc.resolve(after))); | ||
| return true; | ||
| }); | ||
| } | ||
| return editor.commands.exitCode(); | ||
| } | ||
| }; | ||
| }, | ||
| addInputRules() { | ||
| return [ | ||
| textblockTypeInputRule({ | ||
| find: backtickInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ | ||
| language: match[1] | ||
| }) | ||
| }), | ||
| textblockTypeInputRule({ | ||
| find: tildeInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ | ||
| language: match[1] | ||
| }) | ||
| }) | ||
| ]; | ||
| }, | ||
| addProseMirrorPlugins() { | ||
| return [ | ||
| // this plugin creates a code block for pasted content from VS Code | ||
| // we can also detect the copied code language | ||
| new Plugin({ | ||
| key: new PluginKey("codeBlockVSCodeHandler"), | ||
| props: { | ||
| handlePaste: (view, event) => { | ||
| if (!event.clipboardData) { | ||
| return false; | ||
| } | ||
| if (this.editor.isActive(this.type.name)) { | ||
| return false; | ||
| } | ||
| const text = event.clipboardData.getData("text/plain"); | ||
| const vscode = event.clipboardData.getData("vscode-editor-data"); | ||
| const vscodeData = vscode ? JSON.parse(vscode) : void 0; | ||
| const language = vscodeData == null ? void 0 : vscodeData.mode; | ||
| if (!text || !language) { | ||
| return false; | ||
| } | ||
| const { tr, schema } = view.state; | ||
| const textNode = schema.text(text.replace(/\r\n?/g, "\n")); | ||
| tr.replaceSelectionWith(this.type.create({ language }, textNode)); | ||
| if (tr.selection.$from.parent.type !== this.type) { | ||
| tr.setSelection( | ||
| TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))) | ||
| ); | ||
| } | ||
| tr.setMeta("paste", true); | ||
| view.dispatch(tr); | ||
| return true; | ||
| } | ||
| } | ||
| }) | ||
| ]; | ||
| } | ||
| //#region src/code-block.ts | ||
| const DEFAULT_TAB_SIZE = 4; | ||
| /** | ||
| * Matches a code block with backticks. | ||
| */ | ||
| const backtickInputRegex = /^```([a-z]+)?[\s\n]$/; | ||
| /** | ||
| * Matches a code block with tildes. | ||
| */ | ||
| const tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/; | ||
| /** | ||
| * This extension allows you to create code blocks. | ||
| * @see https://tiptap.dev/api/nodes/code-block | ||
| */ | ||
| const CodeBlock = Node.create({ | ||
| name: "codeBlock", | ||
| addOptions() { | ||
| return { | ||
| languageClassPrefix: "language-", | ||
| exitOnTripleEnter: true, | ||
| exitOnArrowDown: true, | ||
| exitOnArrowUp: true, | ||
| defaultLanguage: null, | ||
| enableTabIndentation: false, | ||
| tabSize: DEFAULT_TAB_SIZE, | ||
| HTMLAttributes: {} | ||
| }; | ||
| }, | ||
| content: "text*", | ||
| marks: "", | ||
| group: "block", | ||
| code: true, | ||
| defining: true, | ||
| addAttributes() { | ||
| return { language: { | ||
| default: this.options.defaultLanguage, | ||
| parseHTML: (element) => { | ||
| var _element$firstElement; | ||
| const { languageClassPrefix } = this.options; | ||
| if (!languageClassPrefix) return null; | ||
| const language = [...((_element$firstElement = element.firstElementChild) === null || _element$firstElement === void 0 ? void 0 : _element$firstElement.classList) || []].filter((className) => className.startsWith(languageClassPrefix)).map((className) => className.replace(languageClassPrefix, ""))[0]; | ||
| if (!language) return null; | ||
| return language; | ||
| }, | ||
| rendered: false | ||
| } }; | ||
| }, | ||
| parseHTML() { | ||
| return [{ | ||
| tag: "pre", | ||
| preserveWhitespace: "full" | ||
| }]; | ||
| }, | ||
| renderHTML({ node, HTMLAttributes }) { | ||
| return [ | ||
| "pre", | ||
| mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), | ||
| [ | ||
| "code", | ||
| { class: node.attrs.language ? this.options.languageClassPrefix + node.attrs.language : null }, | ||
| 0 | ||
| ] | ||
| ]; | ||
| }, | ||
| markdownTokenName: "code", | ||
| parseMarkdown: (token, helpers) => { | ||
| var _token$raw, _token$raw2; | ||
| if (((_token$raw = token.raw) === null || _token$raw === void 0 ? void 0 : _token$raw.startsWith("```")) === false && ((_token$raw2 = token.raw) === null || _token$raw2 === void 0 ? void 0 : _token$raw2.startsWith("~~~")) === false && token.codeBlockStyle !== "indented") return []; | ||
| return helpers.createNode("codeBlock", { language: token.lang || null }, token.text ? [helpers.createTextNode(token.text)] : []); | ||
| }, | ||
| renderMarkdown: (node, h) => { | ||
| var _node$attrs; | ||
| let output = ""; | ||
| const language = ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.language) || ""; | ||
| if (!node.content) output = `\`\`\`${language}\n\n\`\`\``; | ||
| else output = [ | ||
| `\`\`\`${language}`, | ||
| h.renderChildren(node.content), | ||
| "```" | ||
| ].join("\n"); | ||
| return output; | ||
| }, | ||
| addCommands() { | ||
| return { | ||
| setCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.setNode(this.name, attributes); | ||
| }, | ||
| toggleCodeBlock: (attributes) => ({ commands }) => { | ||
| return commands.toggleNode(this.name, "paragraph", attributes); | ||
| } | ||
| }; | ||
| }, | ||
| addKeyboardShortcuts() { | ||
| return { | ||
| "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(), | ||
| Backspace: () => { | ||
| const { empty, $anchor } = this.editor.state.selection; | ||
| const isAtStart = $anchor.pos === 1; | ||
| if (!empty || $anchor.parent.type.name !== this.name) return false; | ||
| if (isAtStart || !$anchor.parent.textContent.length) return this.editor.commands.clearNodes(); | ||
| return false; | ||
| }, | ||
| Tab: ({ editor }) => { | ||
| var _this$options$tabSize; | ||
| if (!this.options.enableTabIndentation) return false; | ||
| const tabSize = (_this$options$tabSize = this.options.tabSize) !== null && _this$options$tabSize !== void 0 ? _this$options$tabSize : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) return false; | ||
| const indent = " ".repeat(tabSize); | ||
| if (empty) return editor.commands.insertContent(indent); | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const indentedText = state.doc.textBetween(from, to, "\n", "\n").split("\n").map((line) => indent + line).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(indentedText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| "Shift-Tab": ({ editor }) => { | ||
| var _this$options$tabSize2; | ||
| if (!this.options.enableTabIndentation) return false; | ||
| const tabSize = (_this$options$tabSize2 = this.options.tabSize) !== null && _this$options$tabSize2 !== void 0 ? _this$options$tabSize2 : DEFAULT_TAB_SIZE; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if ($from.parent.type !== this.type) return false; | ||
| if (empty) return editor.commands.command(({ tr }) => { | ||
| var _currentLine$match; | ||
| const { pos } = $from; | ||
| const codeBlockStart = $from.start(); | ||
| const codeBlockEnd = $from.end(); | ||
| const lines = state.doc.textBetween(codeBlockStart, codeBlockEnd, "\n", "\n").split("\n"); | ||
| let currentLineIndex = 0; | ||
| let charCount = 0; | ||
| const relativeCursorPos = pos - codeBlockStart; | ||
| for (let i = 0; i < lines.length; i += 1) { | ||
| if (charCount + lines[i].length >= relativeCursorPos) { | ||
| currentLineIndex = i; | ||
| break; | ||
| } | ||
| charCount += lines[i].length + 1; | ||
| } | ||
| const leadingSpaces = ((_currentLine$match = lines[currentLineIndex].match(/^ */)) === null || _currentLine$match === void 0 ? void 0 : _currentLine$match[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| if (spacesToRemove === 0) return true; | ||
| let lineStartPos = codeBlockStart; | ||
| for (let i = 0; i < currentLineIndex; i += 1) lineStartPos += lines[i].length + 1; | ||
| tr.delete(lineStartPos, lineStartPos + spacesToRemove); | ||
| if (pos - lineStartPos <= spacesToRemove) tr.setSelection(TextSelection.create(tr.doc, lineStartPos)); | ||
| return true; | ||
| }); | ||
| return editor.commands.command(({ tr }) => { | ||
| const { from, to } = selection; | ||
| const reverseIndentText = state.doc.textBetween(from, to, "\n", "\n").split("\n").map((line) => { | ||
| var _line$match; | ||
| const leadingSpaces = ((_line$match = line.match(/^ */)) === null || _line$match === void 0 ? void 0 : _line$match[0]) || ""; | ||
| const spacesToRemove = Math.min(leadingSpaces.length, tabSize); | ||
| return line.slice(spacesToRemove); | ||
| }).join("\n"); | ||
| tr.replaceWith(from, to, state.schema.text(reverseIndentText)); | ||
| return true; | ||
| }); | ||
| }, | ||
| Enter: ({ editor }) => { | ||
| if (!this.options.exitOnTripleEnter) return false; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2; | ||
| const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n"); | ||
| if (!isAtEnd || !endsWithDoubleNewline) return false; | ||
| return editor.chain().command(({ tr }) => { | ||
| tr.delete($from.pos - 2, $from.pos); | ||
| return true; | ||
| }).exitCode().run(); | ||
| }, | ||
| ArrowUp: ({ editor }) => { | ||
| if (!this.options.exitOnArrowUp) return false; | ||
| const { state } = editor; | ||
| const { selection } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| if ($from.parentOffset !== 0) return false; | ||
| const before = $from.before(); | ||
| if (before > 0) return false; | ||
| return editor.commands.insertDefaultBlock({ pos: before }); | ||
| }, | ||
| ArrowDown: ({ editor }) => { | ||
| if (!this.options.exitOnArrowDown) return false; | ||
| const { state } = editor; | ||
| const { selection, doc } = state; | ||
| const { $from, empty } = selection; | ||
| if (!empty || $from.parent.type !== this.type) return false; | ||
| if (!($from.parentOffset === $from.parent.nodeSize - 2)) return false; | ||
| const after = $from.after(); | ||
| if (after === void 0) return false; | ||
| if (doc.nodeAt(after)) return editor.commands.command(({ tr }) => { | ||
| tr.setSelection(Selection.near(doc.resolve(after))); | ||
| return true; | ||
| }); | ||
| return editor.commands.exitCode(); | ||
| } | ||
| }; | ||
| }, | ||
| addInputRules() { | ||
| return [textblockTypeInputRule({ | ||
| find: backtickInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ language: match[1] }) | ||
| }), textblockTypeInputRule({ | ||
| find: tildeInputRegex, | ||
| type: this.type, | ||
| getAttributes: (match) => ({ language: match[1] }) | ||
| })]; | ||
| }, | ||
| addProseMirrorPlugins() { | ||
| return [new Plugin({ | ||
| key: new PluginKey("codeBlockVSCodeHandler"), | ||
| props: { handlePaste: (view, event) => { | ||
| if (!event.clipboardData) return false; | ||
| if (this.editor.isActive(this.type.name)) return false; | ||
| const text = event.clipboardData.getData("text/plain"); | ||
| const vscode = event.clipboardData.getData("vscode-editor-data"); | ||
| const vscodeData = vscode ? JSON.parse(vscode) : void 0; | ||
| const language = vscodeData === null || vscodeData === void 0 ? void 0 : vscodeData.mode; | ||
| if (!text || !language) return false; | ||
| const { tr, schema } = view.state; | ||
| const textNode = schema.text(text.replace(/\r\n?/g, "\n")); | ||
| tr.replaceSelectionWith(this.type.create({ language }, textNode)); | ||
| if (tr.selection.$from.parent.type !== this.type) tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2)))); | ||
| tr.setMeta("paste", true); | ||
| view.dispatch(tr); | ||
| return true; | ||
| } } | ||
| })]; | ||
| } | ||
| }); | ||
| //#endregion | ||
| //#region src/index.ts | ||
| var src_default = CodeBlock; | ||
| //#endregion | ||
| export { CodeBlock, backtickInputRegex, src_default as default, tildeInputRegex }; | ||
| // src/index.ts | ||
| var index_default = CodeBlock; | ||
| export { | ||
| CodeBlock, | ||
| backtickInputRegex, | ||
| index_default as default, | ||
| tildeInputRegex | ||
| }; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/code-block.ts","../src/index.ts"],"sourcesContent":["import { mergeAttributes, Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\n\nconst DEFAULT_TAB_SIZE = 4\n\nexport interface CodeBlockOptions {\n /**\n * Adds a prefix to language classes that are applied to code tags.\n * @default 'language-'\n */\n languageClassPrefix: string | null | undefined\n /**\n * Define whether the node should be exited on triple enter.\n * @default true\n */\n exitOnTripleEnter: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow down if there is no node after it.\n * @default true\n */\n exitOnArrowDown: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow up if there is no node before it.\n * @default true\n */\n exitOnArrowUp: boolean | null | undefined\n /**\n * The default language.\n * @default null\n * @example 'js'\n */\n defaultLanguage: string | null | undefined\n /**\n * Enable tab key for indentation in code blocks.\n * @default false\n */\n enableTabIndentation: boolean | null | undefined\n /**\n * The number of spaces to use for tab indentation.\n * @default 4\n */\n tabSize: number | null | undefined\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n * @param attributes Code block attributes\n * @example editor.commands.setCodeBlock({ language: 'javascript' })\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType\n /**\n * Toggle a code block\n * @param attributes Code block attributes\n * @example editor.commands.toggleCodeBlock({ language: 'javascript' })\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType\n }\n }\n}\n\n/**\n * Matches a code block with backticks.\n */\nexport const backtickInputRegex = /^```([a-z]+)?[\\s\\n]$/\n\n/**\n * Matches a code block with tildes.\n */\nexport const tildeInputRegex = /^~~~([a-z]+)?[\\s\\n]$/\n\n/**\n * This extension allows you to create code blocks.\n * @see https://tiptap.dev/api/nodes/code-block\n */\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n addOptions() {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: true,\n exitOnArrowDown: true,\n exitOnArrowUp: true,\n defaultLanguage: null,\n enableTabIndentation: false,\n tabSize: DEFAULT_TAB_SIZE,\n HTMLAttributes: {},\n }\n },\n\n content: 'text*',\n\n marks: '',\n\n group: 'block',\n\n code: true,\n\n defining: true,\n\n addAttributes() {\n return {\n language: {\n default: this.options.defaultLanguage,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\n\n if (!languageClassPrefix) {\n return null\n }\n\n const classNames = [...(element.firstElementChild?.classList || [])]\n const languages = classNames\n .filter(className => className.startsWith(languageClassPrefix))\n .map(className => className.replace(languageClassPrefix, ''))\n const language = languages[0]\n\n if (!language) {\n return null\n }\n\n return language\n },\n rendered: false,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n [\n 'code',\n {\n class: node.attrs.language\n ? this.options.languageClassPrefix + node.attrs.language\n : null,\n },\n 0,\n ],\n ]\n },\n\n markdownTokenName: 'code',\n\n parseMarkdown: (token, helpers) => {\n if (\n token.raw?.startsWith('```') === false &&\n token.raw?.startsWith('~~~') === false &&\n token.codeBlockStyle !== 'indented'\n ) {\n return []\n }\n\n return helpers.createNode(\n 'codeBlock',\n { language: token.lang || null },\n token.text ? [helpers.createTextNode(token.text)] : [],\n )\n },\n\n renderMarkdown: (node, h) => {\n let output = ''\n const language = node.attrs?.language || ''\n\n if (!node.content) {\n output = `\\`\\`\\`${language}\\n\\n\\`\\`\\``\n } else {\n const lines = [`\\`\\`\\`${language}`, h.renderChildren(node.content), '```']\n output = lines.join('\\n')\n }\n\n return output\n },\n\n addCommands() {\n return {\n setCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.setNode(this.name, attributes)\n },\n toggleCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.toggleNode(this.name, 'paragraph', attributes)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Alt-c': () => this.editor.commands.toggleCodeBlock(),\n\n // remove code block when at start of document or code block is empty\n Backspace: () => {\n const { empty, $anchor } = this.editor.state.selection\n const isAtStart = $anchor.pos === 1\n\n if (!empty || $anchor.parent.type.name !== this.name) {\n return false\n }\n\n if (isAtStart || !$anchor.parent.textContent.length) {\n return this.editor.commands.clearNodes()\n }\n\n return false\n },\n\n // handle tab indentation\n Tab: ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n const indent = ' '.repeat(tabSize)\n\n if (empty) {\n return editor.commands.insertContent(indent)\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const indentedText = lines.map(line => indent + line).join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(indentedText))\n return true\n })\n },\n\n // handle shift+tab reverse indentation\n 'Shift-Tab': ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n if (empty) {\n return editor.commands.command(({ tr }) => {\n const { pos } = $from\n const codeBlockStart = $from.start()\n const codeBlockEnd = $from.end()\n\n const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, '\\n', '\\n')\n const lines = allText.split('\\n')\n\n let currentLineIndex = 0\n let charCount = 0\n const relativeCursorPos = pos - codeBlockStart\n\n for (let i = 0; i < lines.length; i += 1) {\n if (charCount + lines[i].length >= relativeCursorPos) {\n currentLineIndex = i\n break\n }\n charCount += lines[i].length + 1\n }\n\n const currentLine = lines[currentLineIndex]\n const leadingSpaces = currentLine.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n\n if (spacesToRemove === 0) {\n return true\n }\n\n let lineStartPos = codeBlockStart\n for (let i = 0; i < currentLineIndex; i += 1) {\n lineStartPos += lines[i].length + 1\n }\n\n tr.delete(lineStartPos, lineStartPos + spacesToRemove)\n\n const cursorPosInLine = pos - lineStartPos\n if (cursorPosInLine <= spacesToRemove) {\n tr.setSelection(TextSelection.create(tr.doc, lineStartPos))\n }\n\n return true\n })\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const reverseIndentText = lines\n .map(line => {\n const leadingSpaces = line.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n return line.slice(spacesToRemove)\n })\n .join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(reverseIndentText))\n return true\n })\n },\n\n // exit node on triple enter\n Enter: ({ editor }) => {\n if (!this.options.exitOnTripleEnter) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n const endsWithDoubleNewline = $from.parent.textContent.endsWith('\\n\\n')\n\n if (!isAtEnd || !endsWithDoubleNewline) {\n return false\n }\n\n return editor\n .chain()\n .command(({ tr }) => {\n tr.delete($from.pos - 2, $from.pos)\n\n return true\n })\n .exitCode()\n .run()\n },\n\n // exit node on arrow up if there is no node before it\n ArrowUp: ({ editor }) => {\n if (!this.options.exitOnArrowUp) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n if ($from.parentOffset !== 0) {\n return false\n }\n\n const before = $from.before()\n\n if (before > 0) {\n return false\n }\n\n return editor.commands.insertDefaultBlock({ pos: before })\n },\n\n // exit node on arrow down\n ArrowDown: ({ editor }) => {\n if (!this.options.exitOnArrowDown) {\n return false\n }\n\n const { state } = editor\n const { selection, doc } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n\n if (!isAtEnd) {\n return false\n }\n\n const after = $from.after()\n\n if (after === undefined) {\n return false\n }\n\n const nodeAfter = doc.nodeAt(after)\n\n if (nodeAfter) {\n return editor.commands.command(({ tr }) => {\n tr.setSelection(Selection.near(doc.resolve(after)))\n return true\n })\n }\n\n return editor.commands.exitCode()\n },\n }\n },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n return [\n // this plugin creates a code block for pasted content from VS Code\n // we can also detect the copied code language\n new Plugin({\n key: new PluginKey('codeBlockVSCodeHandler'),\n props: {\n handlePaste: (view, event) => {\n if (!event.clipboardData) {\n return false\n }\n\n // don’t create a new code block within code blocks\n if (this.editor.isActive(this.type.name)) {\n return false\n }\n\n const text = event.clipboardData.getData('text/plain')\n const vscode = event.clipboardData.getData('vscode-editor-data')\n const vscodeData = vscode ? JSON.parse(vscode) : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr, schema } = view.state\n\n // prepare a text node\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n const textNode = schema.text(text.replace(/\\r\\n?/g, '\\n'))\n\n // create a code block with the text node\n // replace selection with the code block\n tr.replaceSelectionWith(this.type.create({ language }, textNode))\n\n if (tr.selection.$from.parent.type !== this.type) {\n // put cursor inside the newly created code block\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))),\n )\n }\n\n // store meta information\n // this is useful for other plugins that depends on the paste event\n // like the paste rule plugin\n tr.setMeta('paste', true)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n","import { CodeBlock } from './code-block.js'\n\nexport * from './code-block.js'\n\nexport default CodeBlock\n"],"mappings":"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","names":["_a"]} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../src/code-block.ts","../src/index.ts"],"sourcesContent":["import { mergeAttributes, Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, Selection, TextSelection } from '@tiptap/pm/state'\n\nconst DEFAULT_TAB_SIZE = 4\n\nexport interface CodeBlockOptions {\n /**\n * Adds a prefix to language classes that are applied to code tags.\n * @default 'language-'\n */\n languageClassPrefix: string | null | undefined\n /**\n * Define whether the node should be exited on triple enter.\n * @default true\n */\n exitOnTripleEnter: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow down if there is no node after it.\n * @default true\n */\n exitOnArrowDown: boolean | null | undefined\n /**\n * Define whether the node should be exited on arrow up if there is no node before it.\n * @default true\n */\n exitOnArrowUp: boolean | null | undefined\n /**\n * The default language.\n * @default null\n * @example 'js'\n */\n defaultLanguage: string | null | undefined\n /**\n * Enable tab key for indentation in code blocks.\n * @default false\n */\n enableTabIndentation: boolean | null | undefined\n /**\n * The number of spaces to use for tab indentation.\n * @default 4\n */\n tabSize: number | null | undefined\n /**\n * Custom HTML attributes that should be added to the rendered HTML tag.\n * @default {}\n * @example { class: 'foo' }\n */\n HTMLAttributes: Record<string, any>\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n * @param attributes Code block attributes\n * @example editor.commands.setCodeBlock({ language: 'javascript' })\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType\n /**\n * Toggle a code block\n * @param attributes Code block attributes\n * @example editor.commands.toggleCodeBlock({ language: 'javascript' })\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType\n }\n }\n}\n\n/**\n * Matches a code block with backticks.\n */\nexport const backtickInputRegex = /^```([a-z]+)?[\\s\\n]$/\n\n/**\n * Matches a code block with tildes.\n */\nexport const tildeInputRegex = /^~~~([a-z]+)?[\\s\\n]$/\n\n/**\n * This extension allows you to create code blocks.\n * @see https://tiptap.dev/api/nodes/code-block\n */\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n addOptions() {\n return {\n languageClassPrefix: 'language-',\n exitOnTripleEnter: true,\n exitOnArrowDown: true,\n exitOnArrowUp: true,\n defaultLanguage: null,\n enableTabIndentation: false,\n tabSize: DEFAULT_TAB_SIZE,\n HTMLAttributes: {},\n }\n },\n\n content: 'text*',\n\n marks: '',\n\n group: 'block',\n\n code: true,\n\n defining: true,\n\n addAttributes() {\n return {\n language: {\n default: this.options.defaultLanguage,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\n\n if (!languageClassPrefix) {\n return null\n }\n\n const classNames = [...(element.firstElementChild?.classList || [])]\n const languages = classNames\n .filter(className => className.startsWith(languageClassPrefix))\n .map(className => className.replace(languageClassPrefix, ''))\n const language = languages[0]\n\n if (!language) {\n return null\n }\n\n return language\n },\n rendered: false,\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ node, HTMLAttributes }) {\n return [\n 'pre',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),\n [\n 'code',\n {\n class: node.attrs.language\n ? this.options.languageClassPrefix + node.attrs.language\n : null,\n },\n 0,\n ],\n ]\n },\n\n markdownTokenName: 'code',\n\n parseMarkdown: (token, helpers) => {\n if (\n token.raw?.startsWith('```') === false &&\n token.raw?.startsWith('~~~') === false &&\n token.codeBlockStyle !== 'indented'\n ) {\n return []\n }\n\n return helpers.createNode(\n 'codeBlock',\n { language: token.lang || null },\n token.text ? [helpers.createTextNode(token.text)] : [],\n )\n },\n\n renderMarkdown: (node, h) => {\n let output = ''\n const language = node.attrs?.language || ''\n\n if (!node.content) {\n output = `\\`\\`\\`${language}\\n\\n\\`\\`\\``\n } else {\n const lines = [`\\`\\`\\`${language}`, h.renderChildren(node.content), '```']\n output = lines.join('\\n')\n }\n\n return output\n },\n\n addCommands() {\n return {\n setCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.setNode(this.name, attributes)\n },\n toggleCodeBlock:\n attributes =>\n ({ commands }) => {\n return commands.toggleNode(this.name, 'paragraph', attributes)\n },\n }\n },\n\n addKeyboardShortcuts() {\n return {\n 'Mod-Alt-c': () => this.editor.commands.toggleCodeBlock(),\n\n // remove code block when at start of document or code block is empty\n Backspace: () => {\n const { empty, $anchor } = this.editor.state.selection\n const isAtStart = $anchor.pos === 1\n\n if (!empty || $anchor.parent.type.name !== this.name) {\n return false\n }\n\n if (isAtStart || !$anchor.parent.textContent.length) {\n return this.editor.commands.clearNodes()\n }\n\n return false\n },\n\n // handle tab indentation\n Tab: ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n const indent = ' '.repeat(tabSize)\n\n if (empty) {\n return editor.commands.insertContent(indent)\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const indentedText = lines.map(line => indent + line).join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(indentedText))\n return true\n })\n },\n\n // handle shift+tab reverse indentation\n 'Shift-Tab': ({ editor }) => {\n if (!this.options.enableTabIndentation) {\n return false\n }\n\n const tabSize = this.options.tabSize ?? DEFAULT_TAB_SIZE\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if ($from.parent.type !== this.type) {\n return false\n }\n\n if (empty) {\n return editor.commands.command(({ tr }) => {\n const { pos } = $from\n const codeBlockStart = $from.start()\n const codeBlockEnd = $from.end()\n\n const allText = state.doc.textBetween(codeBlockStart, codeBlockEnd, '\\n', '\\n')\n const lines = allText.split('\\n')\n\n let currentLineIndex = 0\n let charCount = 0\n const relativeCursorPos = pos - codeBlockStart\n\n for (let i = 0; i < lines.length; i += 1) {\n if (charCount + lines[i].length >= relativeCursorPos) {\n currentLineIndex = i\n break\n }\n charCount += lines[i].length + 1\n }\n\n const currentLine = lines[currentLineIndex]\n const leadingSpaces = currentLine.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n\n if (spacesToRemove === 0) {\n return true\n }\n\n let lineStartPos = codeBlockStart\n for (let i = 0; i < currentLineIndex; i += 1) {\n lineStartPos += lines[i].length + 1\n }\n\n tr.delete(lineStartPos, lineStartPos + spacesToRemove)\n\n const cursorPosInLine = pos - lineStartPos\n if (cursorPosInLine <= spacesToRemove) {\n tr.setSelection(TextSelection.create(tr.doc, lineStartPos))\n }\n\n return true\n })\n }\n\n return editor.commands.command(({ tr }) => {\n const { from, to } = selection\n const text = state.doc.textBetween(from, to, '\\n', '\\n')\n const lines = text.split('\\n')\n const reverseIndentText = lines\n .map(line => {\n const leadingSpaces = line.match(/^ */)?.[0] || ''\n const spacesToRemove = Math.min(leadingSpaces.length, tabSize)\n return line.slice(spacesToRemove)\n })\n .join('\\n')\n\n tr.replaceWith(from, to, state.schema.text(reverseIndentText))\n return true\n })\n },\n\n // exit node on triple enter\n Enter: ({ editor }) => {\n if (!this.options.exitOnTripleEnter) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n const endsWithDoubleNewline = $from.parent.textContent.endsWith('\\n\\n')\n\n if (!isAtEnd || !endsWithDoubleNewline) {\n return false\n }\n\n return editor\n .chain()\n .command(({ tr }) => {\n tr.delete($from.pos - 2, $from.pos)\n\n return true\n })\n .exitCode()\n .run()\n },\n\n // exit node on arrow up if there is no node before it\n ArrowUp: ({ editor }) => {\n if (!this.options.exitOnArrowUp) {\n return false\n }\n\n const { state } = editor\n const { selection } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n if ($from.parentOffset !== 0) {\n return false\n }\n\n const before = $from.before()\n\n if (before > 0) {\n return false\n }\n\n return editor.commands.insertDefaultBlock({ pos: before })\n },\n\n // exit node on arrow down\n ArrowDown: ({ editor }) => {\n if (!this.options.exitOnArrowDown) {\n return false\n }\n\n const { state } = editor\n const { selection, doc } = state\n const { $from, empty } = selection\n\n if (!empty || $from.parent.type !== this.type) {\n return false\n }\n\n const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2\n\n if (!isAtEnd) {\n return false\n }\n\n const after = $from.after()\n\n if (after === undefined) {\n return false\n }\n\n const nodeAfter = doc.nodeAt(after)\n\n if (nodeAfter) {\n return editor.commands.command(({ tr }) => {\n tr.setSelection(Selection.near(doc.resolve(after)))\n return true\n })\n }\n\n return editor.commands.exitCode()\n },\n }\n },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: match => ({\n language: match[1],\n }),\n }),\n ]\n },\n\n addProseMirrorPlugins() {\n return [\n // this plugin creates a code block for pasted content from VS Code\n // we can also detect the copied code language\n new Plugin({\n key: new PluginKey('codeBlockVSCodeHandler'),\n props: {\n handlePaste: (view, event) => {\n if (!event.clipboardData) {\n return false\n }\n\n // don’t create a new code block within code blocks\n if (this.editor.isActive(this.type.name)) {\n return false\n }\n\n const text = event.clipboardData.getData('text/plain')\n const vscode = event.clipboardData.getData('vscode-editor-data')\n const vscodeData = vscode ? JSON.parse(vscode) : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr, schema } = view.state\n\n // prepare a text node\n // strip carriage return chars from text pasted as code\n // see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd\n const textNode = schema.text(text.replace(/\\r\\n?/g, '\\n'))\n\n // create a code block with the text node\n // replace selection with the code block\n tr.replaceSelectionWith(this.type.create({ language }, textNode))\n\n if (tr.selection.$from.parent.type !== this.type) {\n // put cursor inside the newly created code block\n tr.setSelection(\n TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))),\n )\n }\n\n // store meta information\n // this is useful for other plugins that depends on the paste event\n // like the paste rule plugin\n tr.setMeta('paste', true)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n","import { CodeBlock } from './code-block.js'\n\nexport * from './code-block.js'\n\nexport default CodeBlock\n"],"mappings":"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"} |
+6
-6
| { | ||
| "name": "@tiptap/extension-code-block", | ||
| "version": "3.30.2", | ||
| "version": "3.30.3", | ||
| "description": "code block extension for tiptap", | ||
@@ -42,12 +42,12 @@ "keywords": [ | ||
| "devDependencies": { | ||
| "@tiptap/core": "^3.30.2", | ||
| "@tiptap/pm": "^3.30.2" | ||
| "@tiptap/core": "^3.30.3", | ||
| "@tiptap/pm": "^3.30.3" | ||
| }, | ||
| "peerDependencies": { | ||
| "@tiptap/core": "3.30.2", | ||
| "@tiptap/pm": "3.30.2" | ||
| "@tiptap/core": "3.30.3", | ||
| "@tiptap/pm": "3.30.3" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsup" | ||
| "build": "vp pack" | ||
| } | ||
| } |
13
18.18%83600
-7.53%1012
-17.05%