Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Code block #1177

Merged
merged 12 commits into from
Oct 30, 2024
5 changes: 5 additions & 0 deletions examples/01-basic/03-all-blocks/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export default function App() {
type: "checkListItem",
content: "Check List Item",
},
{
type: "codeBlock",
props: { language: "javascript" },
content: "console.log('Hello, world!');",
},
{
type: "table",
content: {
Expand Down
12,320 changes: 7,451 additions & 4,869 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@
"uuid": "^8.3.2",
"y-prosemirror": "1.2.12",
"y-protocols": "^1.0.6",
"yjs": "^13.6.15"
"yjs": "^13.6.15",
"prosemirror-highlight": "^0.9.0",
"shiki": "^1.22.0"
},
"devDependencies": {
"@types/emoji-mart": "^3.0.14",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const acceptedMIMETypes = [
"vscode-editor-data",
"blocknote/html",
"Files",
"text/html",
Expand Down
49 changes: 49 additions & 0 deletions packages/core/src/api/clipboard/fromClipboard/handleVSCodePaste.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { BlockNoteEditor } from "../../../editor/BlockNoteEditor.js";
import {
BlockSchema,
InlineContentSchema,
StyleSchema,
} from "../../../schema/index.js";

export async function handleVSCodePaste<
BSchema extends BlockSchema,
I extends InlineContentSchema,
S extends StyleSchema
>(event: ClipboardEvent, editor: BlockNoteEditor<BSchema, I, S>) {
const view = editor.prosemirrorView;
const { schema } = view.state;

if (!event.clipboardData) {
return false;
}

const text = event.clipboardData!.getData("text/plain");
const vscode = event.clipboardData!.getData("vscode-editor-data");
YousefED marked this conversation as resolved.
Show resolved Hide resolved
const vscodeData = vscode ? JSON.parse(vscode) : undefined;
const language = vscodeData?.mode;

if (!text) {
return false;
}

if (!schema.nodes.codeBlock) {
view.pasteText(text);

return true;
}

if (!language) {
return false;
}

// strip carriage return chars from text pasted as code
// see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd
editor._tiptapEditor.view.pasteHTML(
`<pre><code class="language-${language}">${text.replace(
/\r\n?/g,
"\n"
)}</code></pre>`
);

return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { nestedListsToBlockNoteStructure } from "../../parsers/html/util/nestedLists.js";
import { acceptedMIMETypes } from "./acceptedMIMETypes.js";
import { handleFileInsertion } from "./handleFileInsertion.js";
import { handleVSCodePaste } from "./handleVSCodePaste.js";

export const createPasteFromClipboardExtension = <
BSchema extends BlockSchema,
Expand Down Expand Up @@ -43,6 +44,11 @@ export const createPasteFromClipboardExtension = <
return true;
}

if (format === "vscode-editor-data") {
handleVSCodePaste(event, editor);
return true;
}

if (format === "Files") {
handleFileInsertion(event, editor);
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<pre><code class="bn-inline-content language-javascript">console.log('Hello, world!');</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="codeBlock"><pre><code class="bn-inline-content language-javascript">console.log('Hello, world!');</code></pre></div></div></div></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<pre><code class="bn-inline-content language-javascript"></code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="codeBlock"><pre><code class="bn-inline-content language-javascript"></code></pre></div></div></div></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<pre><code class="bn-inline-content language-python">print('Hello, world!')</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="codeBlock"><pre><code class="bn-inline-content language-python">print('Hello, world!')</code></pre></div></div></div></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```javascript
console.log('Hello, world!');
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
```javascript
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```python
print('Hello, world!')
```
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,75 @@ exports[`Test BlockNote-Prosemirror conversion > Case: custom style schema > Con
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert codeBlock/defaultLanguage to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"attrs": {
"language": "javascript",
},
"content": [
{
"text": "console.log('Hello, world!');",
"type": "text",
},
],
"type": "codeBlock",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert codeBlock/empty to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"attrs": {
"language": "javascript",
},
"type": "codeBlock",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert codeBlock/python to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"attrs": {
"language": "python",
},
"content": [
{
"text": "print('Hello, world!')",
"type": "text",
},
],
"type": "codeBlock",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert complex/misc to/from prosemirror 1`] = `
{
"attrs": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/api/parsers/markdown/parseMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { HTMLToBlocks } from "../html/parseHTML.js";
// modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js
// that outputs a data-language attribute instead of a CSS class (e.g.: language-typescript)
function code(state: any, node: any) {
const value = node.value ? node.value + "\n" : "";
const value = node.value ? node.value : "";
YousefED marked this conversation as resolved.
Show resolved Hide resolved
/** @type {Properties} */
const properties: any = {};

Expand Down
27 changes: 27 additions & 0 deletions packages/core/src/api/testUtil/cases/defaultSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,33 @@ export const defaultSchemaTestCases: EditorTestCases<
},
],
},
{
name: "codeBlock/empty",
blocks: [
{
type: "codeBlock",
},
],
},
{
name: "codeBlock/defaultLanguage",
blocks: [
{
type: "codeBlock",
content: "console.log('Hello, world!');",
},
],
},
{
name: "codeBlock/python",
blocks: [
{
type: "codeBlock",
props: { language: "python" },
content: "print('Hello, world!')",
},
],
},
{
name: "file/button",
blocks: [
Expand Down
Loading
Loading