@tiptap/extension-code-block 2.0.0-beta.18 → 2.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,10 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var core = require('@tiptap/core');
6
- var prosemirrorInputrules = require('prosemirror-inputrules');
6
+ var prosemirrorState = require('prosemirror-state');
7
7
 
8
- const backtickInputRegex = /^```(?<language>[a-z]*)? $/;
9
- const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/;
8
+ const backtickInputRegex = /^```(?<language>[a-z]*)?[\s\n]$/;
9
+ const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\s\n]$/;
10
10
  const CodeBlock = core.Node.create({
11
11
  name: 'codeBlock',
12
12
  defaultOptions: {
@@ -86,14 +86,60 @@ const CodeBlock = core.Node.create({
86
86
  },
87
87
  addInputRules() {
88
88
  return [
89
- prosemirrorInputrules.textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }) => groups),
90
- prosemirrorInputrules.textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }) => groups),
89
+ core.textblockTypeInputRule({
90
+ find: backtickInputRegex,
91
+ type: this.type,
92
+ getAttributes: ({ groups }) => groups,
93
+ }),
94
+ core.textblockTypeInputRule({
95
+ find: tildeInputRegex,
96
+ type: this.type,
97
+ getAttributes: ({ groups }) => groups,
98
+ }),
99
+ ];
100
+ },
101
+ addProseMirrorPlugins() {
102
+ return [
103
+ // this plugin creates a code block for pasted content from VS Code
104
+ // we can also detect the copied code language
105
+ new prosemirrorState.Plugin({
106
+ key: new prosemirrorState.PluginKey('codeBlockVSCodeHandler'),
107
+ props: {
108
+ handlePaste: (view, event) => {
109
+ if (!event.clipboardData) {
110
+ return false;
111
+ }
112
+ // don’t create a new code block within code blocks
113
+ if (this.editor.isActive(this.type.name)) {
114
+ return false;
115
+ }
116
+ const text = event.clipboardData.getData('text/plain');
117
+ const vscode = event.clipboardData.getData('vscode-editor-data');
118
+ const vscodeData = vscode
119
+ ? JSON.parse(vscode)
120
+ : undefined;
121
+ const language = vscodeData === null || vscodeData === void 0 ? void 0 : vscodeData.mode;
122
+ if (!text || !language) {
123
+ return false;
124
+ }
125
+ const { tr } = view.state;
126
+ // create an empty code block
127
+ tr.replaceSelectionWith(this.type.create({ language }));
128
+ // put cursor inside the newly created code block
129
+ tr.setSelection(prosemirrorState.TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))));
130
+ // add text to code block
131
+ tr.insertText(text);
132
+ view.dispatch(tr);
133
+ return true;
134
+ },
135
+ },
136
+ }),
91
137
  ];
92
138
  },
93
139
  });
94
140
 
95
141
  exports.CodeBlock = CodeBlock;
96
142
  exports.backtickInputRegex = backtickInputRegex;
97
- exports['default'] = CodeBlock;
143
+ exports["default"] = CodeBlock;
98
144
  exports.tildeInputRegex = tildeInputRegex;
99
145
  //# sourceMappingURL=tiptap-extension-code-block.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tiptap-extension-code-block.cjs.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\nimport { textblockTypeInputRule } from 'prosemirror-inputrules'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)? $/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }: any) => groups),\n textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }: any) => groups),\n ]\n },\n})\n"],"names":["Node","textblockTypeInputRule"],"mappings":"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"}
1
+ {"version":3,"file":"tiptap-extension-code-block.cjs.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, TextSelection } from 'prosemirror-state'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)?[\\s\\n]$/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\\s\\n]$/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\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\n ? JSON.parse(vscode)\n : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr } = view.state\n\n // create an empty code block\n tr.replaceSelectionWith(this.type.create({ language }))\n\n // put cursor inside the newly created code block\n tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))))\n\n // add text to code block\n tr.insertText(text)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n"],"names":["Node","textblockTypeInputRule","Plugin","PluginKey","TextSelection"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
- import { Node } from '@tiptap/core';
2
- import { textblockTypeInputRule } from 'prosemirror-inputrules';
1
+ import { Node, textblockTypeInputRule } from '@tiptap/core';
2
+ import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
3
3
 
4
- const backtickInputRegex = /^```(?<language>[a-z]*)? $/;
5
- const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/;
4
+ const backtickInputRegex = /^```(?<language>[a-z]*)?[\s\n]$/;
5
+ const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\s\n]$/;
6
6
  const CodeBlock = Node.create({
7
7
  name: 'codeBlock',
8
8
  defaultOptions: {
@@ -82,8 +82,54 @@ const CodeBlock = Node.create({
82
82
  },
83
83
  addInputRules() {
84
84
  return [
85
- textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }) => groups),
86
- textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }) => groups),
85
+ textblockTypeInputRule({
86
+ find: backtickInputRegex,
87
+ type: this.type,
88
+ getAttributes: ({ groups }) => groups,
89
+ }),
90
+ textblockTypeInputRule({
91
+ find: tildeInputRegex,
92
+ type: this.type,
93
+ getAttributes: ({ groups }) => groups,
94
+ }),
95
+ ];
96
+ },
97
+ addProseMirrorPlugins() {
98
+ return [
99
+ // this plugin creates a code block for pasted content from VS Code
100
+ // we can also detect the copied code language
101
+ new Plugin({
102
+ key: new PluginKey('codeBlockVSCodeHandler'),
103
+ props: {
104
+ handlePaste: (view, event) => {
105
+ if (!event.clipboardData) {
106
+ return false;
107
+ }
108
+ // don’t create a new code block within code blocks
109
+ if (this.editor.isActive(this.type.name)) {
110
+ return false;
111
+ }
112
+ const text = event.clipboardData.getData('text/plain');
113
+ const vscode = event.clipboardData.getData('vscode-editor-data');
114
+ const vscodeData = vscode
115
+ ? JSON.parse(vscode)
116
+ : undefined;
117
+ const language = vscodeData === null || vscodeData === void 0 ? void 0 : vscodeData.mode;
118
+ if (!text || !language) {
119
+ return false;
120
+ }
121
+ const { tr } = view.state;
122
+ // create an empty code block
123
+ tr.replaceSelectionWith(this.type.create({ language }));
124
+ // put cursor inside the newly created code block
125
+ tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))));
126
+ // add text to code block
127
+ tr.insertText(text);
128
+ view.dispatch(tr);
129
+ return true;
130
+ },
131
+ },
132
+ }),
87
133
  ];
88
134
  },
89
135
  });
@@ -1 +1 @@
1
- {"version":3,"file":"tiptap-extension-code-block.esm.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\nimport { textblockTypeInputRule } from 'prosemirror-inputrules'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)? $/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }: any) => groups),\n textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }: any) => groups),\n ]\n },\n})\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tiptap-extension-code-block.esm.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, TextSelection } from 'prosemirror-state'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)?[\\s\\n]$/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\\s\\n]$/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\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\n ? JSON.parse(vscode)\n : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr } = view.state\n\n // create an empty code block\n tr.replaceSelectionWith(this.type.create({ language }))\n\n // put cursor inside the newly created code block\n tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))))\n\n // add text to code block\n tr.insertText(text)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/core'), require('prosemirror-inputrules')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@tiptap/core', 'prosemirror-inputrules'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['@tiptap/extension-code-block'] = {}, global.core, global.prosemirrorInputrules));
5
- }(this, (function (exports, core, prosemirrorInputrules) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/core'), require('prosemirror-state')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@tiptap/core', 'prosemirror-state'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/extension-code-block"] = {}, global.core, global.prosemirrorState));
5
+ })(this, (function (exports, core, prosemirrorState) { 'use strict';
6
6
 
7
- const backtickInputRegex = /^```(?<language>[a-z]*)? $/;
8
- const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/;
7
+ const backtickInputRegex = /^```(?<language>[a-z]*)?[\s\n]$/;
8
+ const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\s\n]$/;
9
9
  const CodeBlock = core.Node.create({
10
10
  name: 'codeBlock',
11
11
  defaultOptions: {
@@ -85,18 +85,64 @@
85
85
  },
86
86
  addInputRules() {
87
87
  return [
88
- prosemirrorInputrules.textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }) => groups),
89
- prosemirrorInputrules.textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }) => groups),
88
+ core.textblockTypeInputRule({
89
+ find: backtickInputRegex,
90
+ type: this.type,
91
+ getAttributes: ({ groups }) => groups,
92
+ }),
93
+ core.textblockTypeInputRule({
94
+ find: tildeInputRegex,
95
+ type: this.type,
96
+ getAttributes: ({ groups }) => groups,
97
+ }),
98
+ ];
99
+ },
100
+ addProseMirrorPlugins() {
101
+ return [
102
+ // this plugin creates a code block for pasted content from VS Code
103
+ // we can also detect the copied code language
104
+ new prosemirrorState.Plugin({
105
+ key: new prosemirrorState.PluginKey('codeBlockVSCodeHandler'),
106
+ props: {
107
+ handlePaste: (view, event) => {
108
+ if (!event.clipboardData) {
109
+ return false;
110
+ }
111
+ // don’t create a new code block within code blocks
112
+ if (this.editor.isActive(this.type.name)) {
113
+ return false;
114
+ }
115
+ const text = event.clipboardData.getData('text/plain');
116
+ const vscode = event.clipboardData.getData('vscode-editor-data');
117
+ const vscodeData = vscode
118
+ ? JSON.parse(vscode)
119
+ : undefined;
120
+ const language = vscodeData === null || vscodeData === void 0 ? void 0 : vscodeData.mode;
121
+ if (!text || !language) {
122
+ return false;
123
+ }
124
+ const { tr } = view.state;
125
+ // create an empty code block
126
+ tr.replaceSelectionWith(this.type.create({ language }));
127
+ // put cursor inside the newly created code block
128
+ tr.setSelection(prosemirrorState.TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))));
129
+ // add text to code block
130
+ tr.insertText(text);
131
+ view.dispatch(tr);
132
+ return true;
133
+ },
134
+ },
135
+ }),
90
136
  ];
91
137
  },
92
138
  });
93
139
 
94
140
  exports.CodeBlock = CodeBlock;
95
141
  exports.backtickInputRegex = backtickInputRegex;
96
- exports['default'] = CodeBlock;
142
+ exports["default"] = CodeBlock;
97
143
  exports.tildeInputRegex = tildeInputRegex;
98
144
 
99
145
  Object.defineProperty(exports, '__esModule', { value: true });
100
146
 
101
- })));
147
+ }));
102
148
  //# sourceMappingURL=tiptap-extension-code-block.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tiptap-extension-code-block.umd.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node } from '@tiptap/core'\nimport { textblockTypeInputRule } from 'prosemirror-inputrules'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)? $/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }: any) => groups),\n textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }: any) => groups),\n ]\n },\n})\n"],"names":["Node","textblockTypeInputRule"],"mappings":"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"}
1
+ {"version":3,"file":"tiptap-extension-code-block.umd.js","sources":["../src/code-block.ts"],"sourcesContent":["import { Node, textblockTypeInputRule } from '@tiptap/core'\nimport { Plugin, PluginKey, TextSelection } from 'prosemirror-state'\n\nexport interface CodeBlockOptions {\n languageClassPrefix: string,\n HTMLAttributes: Record<string, any>,\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n codeBlock: {\n /**\n * Set a code block\n */\n setCodeBlock: (attributes?: { language: string }) => ReturnType,\n /**\n * Toggle a code block\n */\n toggleCodeBlock: (attributes?: { language: string }) => ReturnType,\n }\n }\n}\n\nexport const backtickInputRegex = /^```(?<language>[a-z]*)?[\\s\\n]$/\nexport const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\\s\\n]$/\n\nexport const CodeBlock = Node.create<CodeBlockOptions>({\n name: 'codeBlock',\n\n defaultOptions: {\n languageClassPrefix: 'language-',\n HTMLAttributes: {},\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: null,\n parseHTML: element => {\n const { languageClassPrefix } = this.options\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 renderHTML: attributes => {\n if (!attributes.language) {\n return null\n }\n\n return {\n class: this.options.languageClassPrefix + attributes.language,\n }\n },\n },\n }\n },\n\n parseHTML() {\n return [\n {\n tag: 'pre',\n preserveWhitespace: 'full',\n },\n ]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['pre', this.options.HTMLAttributes, ['code', HTMLAttributes, 0]]\n },\n\n addCommands() {\n return {\n setCodeBlock: attributes => ({ commands }) => {\n return commands.setNode('codeBlock', attributes)\n },\n toggleCodeBlock: attributes => ({ commands }) => {\n return commands.toggleNode('codeBlock', '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 },\n\n addInputRules() {\n return [\n textblockTypeInputRule({\n find: backtickInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\n }),\n textblockTypeInputRule({\n find: tildeInputRegex,\n type: this.type,\n getAttributes: ({ groups }) => groups,\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\n ? JSON.parse(vscode)\n : undefined\n const language = vscodeData?.mode\n\n if (!text || !language) {\n return false\n }\n\n const { tr } = view.state\n\n // create an empty code block\n tr.replaceSelectionWith(this.type.create({ language }))\n\n // put cursor inside the newly created code block\n tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))))\n\n // add text to code block\n tr.insertText(text)\n\n view.dispatch(tr)\n\n return true\n },\n },\n }),\n ]\n },\n})\n"],"names":["Node","textblockTypeInputRule","Plugin","PluginKey","TextSelection"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/extension-code-block",
3
3
  "description": "code block extension for tiptap",
4
- "version": "2.0.0-beta.18",
4
+ "version": "2.0.0-beta.21",
5
5
  "homepage": "https://tiptap.dev",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -24,12 +24,12 @@
24
24
  "@tiptap/core": "^2.0.0-beta.1"
25
25
  },
26
26
  "dependencies": {
27
- "prosemirror-inputrules": "^1.1.3"
27
+ "prosemirror-state": "^1.3.4"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
31
31
  "url": "https://github.com/ueberdosis/tiptap",
32
32
  "directory": "packages/extension-code-block"
33
33
  },
34
- "gitHead": "42e8755d87b37506d537152dbae4b0c8d497fd48"
34
+ "gitHead": "a06213f137672b1a08d76a1374002a32fd35cf23"
35
35
  }
package/src/code-block.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Node } from '@tiptap/core'
2
- import { textblockTypeInputRule } from 'prosemirror-inputrules'
1
+ import { Node, textblockTypeInputRule } from '@tiptap/core'
2
+ import { Plugin, PluginKey, TextSelection } from 'prosemirror-state'
3
3
 
4
4
  export interface CodeBlockOptions {
5
5
  languageClassPrefix: string,
@@ -21,8 +21,8 @@ declare module '@tiptap/core' {
21
21
  }
22
22
  }
23
23
 
24
- export const backtickInputRegex = /^```(?<language>[a-z]*)? $/
25
- export const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/
24
+ export const backtickInputRegex = /^```(?<language>[a-z]*)?[\s\n]$/
25
+ export const tildeInputRegex = /^~~~(?<language>[a-z]*)?[\s\n]$/
26
26
 
27
27
  export const CodeBlock = Node.create<CodeBlockOptions>({
28
28
  name: 'codeBlock',
@@ -121,8 +121,64 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
121
121
 
122
122
  addInputRules() {
123
123
  return [
124
- textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }: any) => groups),
125
- textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }: any) => groups),
124
+ textblockTypeInputRule({
125
+ find: backtickInputRegex,
126
+ type: this.type,
127
+ getAttributes: ({ groups }) => groups,
128
+ }),
129
+ textblockTypeInputRule({
130
+ find: tildeInputRegex,
131
+ type: this.type,
132
+ getAttributes: ({ groups }) => groups,
133
+ }),
134
+ ]
135
+ },
136
+
137
+ addProseMirrorPlugins() {
138
+ return [
139
+ // this plugin creates a code block for pasted content from VS Code
140
+ // we can also detect the copied code language
141
+ new Plugin({
142
+ key: new PluginKey('codeBlockVSCodeHandler'),
143
+ props: {
144
+ handlePaste: (view, event) => {
145
+ if (!event.clipboardData) {
146
+ return false
147
+ }
148
+
149
+ // don’t create a new code block within code blocks
150
+ if (this.editor.isActive(this.type.name)) {
151
+ return false
152
+ }
153
+
154
+ const text = event.clipboardData.getData('text/plain')
155
+ const vscode = event.clipboardData.getData('vscode-editor-data')
156
+ const vscodeData = vscode
157
+ ? JSON.parse(vscode)
158
+ : undefined
159
+ const language = vscodeData?.mode
160
+
161
+ if (!text || !language) {
162
+ return false
163
+ }
164
+
165
+ const { tr } = view.state
166
+
167
+ // create an empty code block
168
+ tr.replaceSelectionWith(this.type.create({ language }))
169
+
170
+ // put cursor inside the newly created code block
171
+ tr.setSelection(TextSelection.near(tr.doc.resolve(Math.max(0, tr.selection.from - 2))))
172
+
173
+ // add text to code block
174
+ tr.insertText(text)
175
+
176
+ view.dispatch(tr)
177
+
178
+ return true
179
+ },
180
+ },
181
+ }),
126
182
  ]
127
183
  },
128
184
  })
package/CHANGELOG.md DELETED
@@ -1,274 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file.
4
- See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
-
6
- # [2.0.0-beta.18](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.17...@tiptap/extension-code-block@2.0.0-beta.18) (2021-09-08)
7
-
8
-
9
- ### Bug Fixes
10
-
11
- * parse correct language for code blocks with multiple classes (see [#1845](https://github.com/ueberdosis/tiptap/issues/1845)) ([472f213](https://github.com/ueberdosis/tiptap/commit/472f2139c52b9e0211ccd735e937486df2cb3d30))
12
-
13
-
14
- ### Features
15
-
16
- * parseHTML for attributes should return the value instead of an object now, fix [#1863](https://github.com/ueberdosis/tiptap/issues/1863) ([8a3b47a](https://github.com/ueberdosis/tiptap/commit/8a3b47a529d28b28b50d634c6ff69b8e5aad3080))
17
-
18
-
19
-
20
-
21
-
22
- # [2.0.0-beta.17](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.16...@tiptap/extension-code-block@2.0.0-beta.17) (2021-07-26)
23
-
24
- **Note:** Version bump only for package @tiptap/extension-code-block
25
-
26
-
27
-
28
-
29
-
30
- # [2.0.0-beta.16](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.15...@tiptap/extension-code-block@2.0.0-beta.16) (2021-06-07)
31
-
32
- **Note:** Version bump only for package @tiptap/extension-code-block
33
-
34
-
35
-
36
-
37
-
38
- # [2.0.0-beta.15](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.14...@tiptap/extension-code-block@2.0.0-beta.15) (2021-05-18)
39
-
40
- **Note:** Version bump only for package @tiptap/extension-code-block
41
-
42
-
43
-
44
-
45
-
46
- # [2.0.0-beta.14](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.13...@tiptap/extension-code-block@2.0.0-beta.14) (2021-05-13)
47
-
48
- **Note:** Version bump only for package @tiptap/extension-code-block
49
-
50
-
51
-
52
-
53
-
54
- # [2.0.0-beta.13](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.12...@tiptap/extension-code-block@2.0.0-beta.13) (2021-05-07)
55
-
56
-
57
- ### Bug Fixes
58
-
59
- * revert adding exports ([bc320d0](https://github.com/ueberdosis/tiptap/commit/bc320d0b4b80b0e37a7e47a56e0f6daec6e65d98))
60
-
61
-
62
-
63
-
64
-
65
- # [2.0.0-beta.12](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.11...@tiptap/extension-code-block@2.0.0-beta.12) (2021-05-06)
66
-
67
-
68
- ### Bug Fixes
69
-
70
- * revert adding type: module ([f8d6475](https://github.com/ueberdosis/tiptap/commit/f8d6475e2151faea6f96baecdd6bd75880d50d2c))
71
-
72
-
73
-
74
-
75
-
76
- # [2.0.0-beta.11](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.10...@tiptap/extension-code-block@2.0.0-beta.11) (2021-05-06)
77
-
78
-
79
- ### Bug Fixes
80
-
81
- * add exports to package.json ([1277fa4](https://github.com/ueberdosis/tiptap/commit/1277fa47151e9c039508cdb219bdd0ffe647f4ee))
82
-
83
-
84
-
85
-
86
-
87
- # [2.0.0-beta.10](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.9...@tiptap/extension-code-block@2.0.0-beta.10) (2021-05-06)
88
-
89
- **Note:** Version bump only for package @tiptap/extension-code-block
90
-
91
-
92
-
93
-
94
-
95
- # [2.0.0-beta.9](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.8...@tiptap/extension-code-block@2.0.0-beta.9) (2021-05-05)
96
-
97
- **Note:** Version bump only for package @tiptap/extension-code-block
98
-
99
-
100
-
101
-
102
-
103
- # [2.0.0-beta.8](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.7...@tiptap/extension-code-block@2.0.0-beta.8) (2021-04-23)
104
-
105
- **Note:** Version bump only for package @tiptap/extension-code-block
106
-
107
-
108
-
109
-
110
-
111
- # [2.0.0-beta.7](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.6...@tiptap/extension-code-block@2.0.0-beta.7) (2021-04-22)
112
-
113
- **Note:** Version bump only for package @tiptap/extension-code-block
114
-
115
-
116
-
117
-
118
-
119
- # [2.0.0-beta.6](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.5...@tiptap/extension-code-block@2.0.0-beta.6) (2021-04-21)
120
-
121
-
122
- ### Bug Fixes
123
-
124
- * don’t use state in KeyboardShortcutCommand anymore ([92ced9f](https://github.com/ueberdosis/tiptap/commit/92ced9f9987d59ac672da65b2a685d296307c6b0))
125
-
126
-
127
-
128
-
129
-
130
- # [2.0.0-beta.5](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.4...@tiptap/extension-code-block@2.0.0-beta.5) (2021-04-16)
131
-
132
- **Note:** Version bump only for package @tiptap/extension-code-block
133
-
134
-
135
-
136
-
137
-
138
- # [2.0.0-beta.4](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.3...@tiptap/extension-code-block@2.0.0-beta.4) (2021-04-15)
139
-
140
- **Note:** Version bump only for package @tiptap/extension-code-block
141
-
142
-
143
-
144
-
145
-
146
- # [2.0.0-beta.3](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.2...@tiptap/extension-code-block@2.0.0-beta.3) (2021-04-11)
147
-
148
-
149
- ### Bug Fixes
150
-
151
- * remove codeblock when at start of document, fix [#262](https://github.com/ueberdosis/tiptap/issues/262) ([92f6ea2](https://github.com/ueberdosis/tiptap/commit/92f6ea25cc7623d0bd34f5a2342be6f5aae951aa))
152
-
153
-
154
-
155
-
156
-
157
- # [2.0.0-beta.2](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-beta.1...@tiptap/extension-code-block@2.0.0-beta.2) (2021-04-02)
158
-
159
- **Note:** Version bump only for package @tiptap/extension-code-block
160
-
161
-
162
-
163
-
164
-
165
- # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.11...@tiptap/extension-code-block@2.0.0-beta.1) (2021-03-05)
166
-
167
- **Note:** Version bump only for package @tiptap/extension-code-block
168
-
169
-
170
-
171
-
172
-
173
- # [2.0.0-alpha.11](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.10...@tiptap/extension-code-block@2.0.0-alpha.11) (2021-02-16)
174
-
175
- **Note:** Version bump only for package @tiptap/extension-code-block
176
-
177
-
178
-
179
-
180
-
181
- # [2.0.0-alpha.10](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.9...@tiptap/extension-code-block@2.0.0-alpha.10) (2021-02-07)
182
-
183
- **Note:** Version bump only for package @tiptap/extension-code-block
184
-
185
-
186
-
187
-
188
-
189
- # [2.0.0-alpha.9](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.8...@tiptap/extension-code-block@2.0.0-alpha.9) (2021-02-05)
190
-
191
- **Note:** Version bump only for package @tiptap/extension-code-block
192
-
193
-
194
-
195
-
196
-
197
- # [2.0.0-alpha.8](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.7...@tiptap/extension-code-block@2.0.0-alpha.8) (2021-01-29)
198
-
199
- **Note:** Version bump only for package @tiptap/extension-code-block
200
-
201
-
202
-
203
-
204
-
205
- # [2.0.0-alpha.7](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.6...@tiptap/extension-code-block@2.0.0-alpha.7) (2021-01-29)
206
-
207
- **Note:** Version bump only for package @tiptap/extension-code-block
208
-
209
-
210
-
211
-
212
-
213
- # [2.0.0-alpha.6](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.5...@tiptap/extension-code-block@2.0.0-alpha.6) (2021-01-28)
214
-
215
- **Note:** Version bump only for package @tiptap/extension-code-block
216
-
217
-
218
-
219
-
220
-
221
- # [2.0.0-alpha.5](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.4...@tiptap/extension-code-block@2.0.0-alpha.5) (2020-12-18)
222
-
223
- **Note:** Version bump only for package @tiptap/extension-code-block
224
-
225
-
226
-
227
-
228
-
229
- # [2.0.0-alpha.4](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.3...@tiptap/extension-code-block@2.0.0-alpha.4) (2020-12-02)
230
-
231
- **Note:** Version bump only for package @tiptap/extension-code-block
232
-
233
-
234
-
235
-
236
-
237
- # [2.0.0-alpha.3](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.2...@tiptap/extension-code-block@2.0.0-alpha.3) (2020-11-19)
238
-
239
- **Note:** Version bump only for package @tiptap/extension-code-block
240
-
241
-
242
-
243
-
244
-
245
- # [2.0.0-alpha.2](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@2.0.0-alpha.1...@tiptap/extension-code-block@2.0.0-alpha.2) (2020-11-19)
246
-
247
- **Note:** Version bump only for package @tiptap/extension-code-block
248
-
249
-
250
-
251
-
252
-
253
- # [2.0.0-alpha.1](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@1.0.0-alpha.2...@tiptap/extension-code-block@2.0.0-alpha.1) (2020-11-18)
254
-
255
- **Note:** Version bump only for package @tiptap/extension-code-block
256
-
257
-
258
-
259
-
260
-
261
- # [1.0.0-alpha.2](https://github.com/ueberdosis/tiptap/compare/@tiptap/extension-code-block@1.0.0-alpha.1...@tiptap/extension-code-block@1.0.0-alpha.2) (2020-11-16)
262
-
263
- **Note:** Version bump only for package @tiptap/extension-code-block
264
-
265
-
266
-
267
-
268
-
269
- # 1.0.0-alpha.1 (2020-11-16)
270
-
271
-
272
- ### Reverts
273
-
274
- * Revert "use global namespace" ([0c9ce26](https://github.com/ueberdosis/tiptap/commit/0c9ce26c02c07d88a757c01b0a9d7f9e2b0b7502))