diff --git a/demos/src/Nodes/CodeBlock/React/index.html b/demos/src/Nodes/CodeBlock/React/index.html new file mode 100644 index 00000000..0896e97d --- /dev/null +++ b/demos/src/Nodes/CodeBlock/React/index.html @@ -0,0 +1,15 @@ + + +
+ + + + + + + + diff --git a/demos/src/Nodes/CodeBlock/React/index.jsx b/demos/src/Nodes/CodeBlock/React/index.jsx new file mode 100644 index 00000000..4d557fa3 --- /dev/null +++ b/demos/src/Nodes/CodeBlock/React/index.jsx @@ -0,0 +1,55 @@ +import React from 'react' +import { useEditor, EditorContent } from '@tiptap/react' +import Document from '@tiptap/extension-document' +import Paragraph from '@tiptap/extension-paragraph' +import Text from '@tiptap/extension-text' +import CodeBlock from '@tiptap/extension-code-block' +import './styles.scss' + +export default () => { + const editor = useEditor({ + extensions: [Document, Paragraph, Text, CodeBlock], + content: ` ++ That’s a boring paragraph followed by a fenced code block: +
+for (var i=1; i <= 20; i++)
+{
+ if (i % 15 == 0)
+ console.log("FizzBuzz");
+ else if (i % 3 == 0)
+ console.log("Fizz");
+ else if (i % 5 == 0)
+ console.log("Buzz");
+ else
+ console.log(i);
+}
+ + Press Command/Ctrl + Enter to leave the fenced code block and continue typing in boring paragraphs. +
+ `, + }) + + if (!editor) { + return null + } + + return ( + <> + + + +Example Text
') + cy.get('.ProseMirror').type('{selectall}') + }) + }) + + it('should parse code blocks correctly', () => { + cy.get('.ProseMirror').then(([{ editor }]) => { + editor.commands.setContent('Example Text')
+ expect(editor.getHTML()).to.eq('Example Text')
+ })
+ })
+
+ it('should parse code blocks with language correctly', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent('Example Text')
+ expect(editor.getHTML()).to.eq('Example Text')
+ })
+ })
+
+ it('the button should make the selected line a code block', () => {
+ cy.get('button:first').click()
+
+ cy.get('.ProseMirror').find('pre').should('contain', 'Example Text')
+ })
+
+ it('the button should toggle the code block', () => {
+ cy.get('button:first').click()
+
+ cy.get('.ProseMirror').find('pre').should('contain', 'Example Text')
+
+ cy.get('.ProseMirror').type('{selectall}')
+
+ cy.get('button:first').click()
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+
+ it('the keyboard shortcut should make the selected line a code block', () => {
+ cy.get('.ProseMirror')
+ .trigger('keydown', { modKey: true, altKey: true, key: 'c' })
+ .find('pre')
+ .should('contain', 'Example Text')
+ })
+
+ it('the keyboard shortcut should toggle the code block', () => {
+ cy.get('.ProseMirror')
+ .trigger('keydown', { modKey: true, altKey: true, key: 'c' })
+ .find('pre')
+ .should('contain', 'Example Text')
+
+ cy.get('.ProseMirror')
+ .type('{selectall}')
+ .trigger('keydown', { modKey: true, altKey: true, key: 'c' })
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+
+ it('should parse the language from a HTML code block', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.setContent(
+ 'body { display: none; }',
+ )
+
+ cy.get('.ProseMirror').find('pre>code.language-css').should('have.length', 1)
+ })
+ })
+
+ it('should make a code block from backtick markdown shortcuts', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror').type('``` Code').find('pre>code').should('contain', 'Code')
+ })
+ })
+
+ it('should make a code block from tilde markdown shortcuts', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror').type('~~~ Code').find('pre>code').should('contain', 'Code')
+ })
+ })
+
+ it('should make a code block for js with backticks', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror')
+ .type('```js Code')
+ .find('pre>code.language-js')
+ .should('contain', 'Code')
+ })
+ })
+
+ it('should make a code block for js with tildes', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror')
+ .type('~~~js Code')
+ .find('pre>code.language-js')
+ .should('contain', 'Code')
+ })
+ })
+
+ it('should make a code block from backtick markdown shortcuts followed by enter', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror').type('```{enter}Code').find('pre>code').should('contain', 'Code')
+ })
+ })
+
+ it('reverts the markdown shortcut when pressing backspace', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror').type('``` {backspace}')
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+ })
+
+ it('removes the code block when pressing backspace', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror pre').should('not.exist')
+
+ cy.get('.ProseMirror').type('Paragraph{enter}``` A{backspace}{backspace}')
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+ })
+
+ it('removes the code block when pressing backspace, even with blank lines', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror pre').should('not.exist')
+
+ cy.get('.ProseMirror').type('Paragraph{enter}{enter}``` A{backspace}{backspace}')
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+ })
+
+ it('removes the code block when pressing backspace, even at start of document', () => {
+ cy.get('.ProseMirror').then(([{ editor }]) => {
+ editor.commands.clearContent()
+
+ cy.get('.ProseMirror pre').should('not.exist')
+
+ cy.get('.ProseMirror').type('``` A{leftArrow}{backspace}')
+
+ cy.get('.ProseMirror pre').should('not.exist')
+ })
+ })
+})
diff --git a/demos/src/Nodes/CodeBlock/React/styles.scss b/demos/src/Nodes/CodeBlock/React/styles.scss
new file mode 100644
index 00000000..97cd3c36
--- /dev/null
+++ b/demos/src/Nodes/CodeBlock/React/styles.scss
@@ -0,0 +1,21 @@
+/* Basic editor styles */
+.ProseMirror {
+ > * + * {
+ margin-top: 0.75em;
+ }
+
+ pre {
+ background: #0d0d0d;
+ border-radius: 0.5rem;
+ color: #fff;
+ font-family: "JetBrainsMono", monospace;
+ padding: 0.75rem 1rem;
+
+ code {
+ background: none;
+ color: inherit;
+ font-size: 0.8rem;
+ padding: 0;
+ }
+ }
+}