diff --git a/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.jsx b/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.jsx
new file mode 100644
index 00000000..486b7428
--- /dev/null
+++ b/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.jsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'
+import './CodeBlockComponent.scss'
+
+export default ({ node: { attrs: { language: defaultLanguage } }, updateAttributes, extension }) => (
+
+
+
+
+
+
+)
diff --git a/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.scss b/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.scss
new file mode 100644
index 00000000..d0b00f23
--- /dev/null
+++ b/docs/src/demos/Examples/CodeBlockLanguage/React/CodeBlockComponent.scss
@@ -0,0 +1,9 @@
+.code-block {
+ position: relative;
+
+ select {
+ position: absolute;
+ right: 0.5rem;
+ top: 0.5rem;
+ }
+}
\ No newline at end of file
diff --git a/docs/src/demos/Examples/CodeBlockLanguage/React/index.jsx b/docs/src/demos/Examples/CodeBlockLanguage/React/index.jsx
new file mode 100644
index 00000000..561c97b9
--- /dev/null
+++ b/docs/src/demos/Examples/CodeBlockLanguage/React/index.jsx
@@ -0,0 +1,71 @@
+import React from 'react'
+import { useEditor, EditorContent, ReactNodeViewRenderer } from '@tiptap/react'
+import Document from '@tiptap/extension-document'
+import Paragraph from '@tiptap/extension-paragraph'
+import Text from '@tiptap/extension-text'
+import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
+import CodeBlockComponent from './CodeBlockComponent'
+
+// load all highlight.js languages
+import lowlight from 'lowlight'
+
+// load specific languages only
+// import lowlight from 'lowlight/lib/core'
+// import javascript from 'highlight.js/lib/languages/javascript'
+// lowlight.registerLanguage('javascript', javascript)
+import './styles.scss'
+
+const MenuBar = ({ editor }) => {
+ if (!editor) {
+ return null
+ }
+
+ return (
+
+ )
+}
+
+export default () => {
+ const editor = useEditor({
+ extensions: [
+ Document,
+ Paragraph,
+ Text,
+ CodeBlockLowlight
+ .extend({
+ addNodeView() {
+ return ReactNodeViewRenderer(CodeBlockComponent)
+ },
+ })
+ .configure({ lowlight }),
+ ],
+ 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.
+
+ `,
+ })
+
+ return (
+
+
+
+
+ )
+}
diff --git a/docs/src/demos/Examples/CodeBlockLanguage/React/styles.scss b/docs/src/demos/Examples/CodeBlockLanguage/React/styles.scss
new file mode 100644
index 00000000..9b4a4c44
--- /dev/null
+++ b/docs/src/demos/Examples/CodeBlockLanguage/React/styles.scss
@@ -0,0 +1,73 @@
+/* Basic editor styles */
+.ProseMirror {
+ > * + * {
+ margin-top: 0.75em;
+ }
+
+ pre {
+ background: #0d0d0d;
+ color: #fff;
+ font-family: "JetBrainsMono", monospace;
+ padding: 0.75rem 1rem;
+ border-radius: 0.5rem;
+
+ code {
+ color: inherit;
+ padding: 0;
+ background: none;
+ font-size: 0.8rem;
+ }
+
+ .hljs-comment,
+ .hljs-quote {
+ color: #616161;
+ }
+
+ .hljs-variable,
+ .hljs-template-variable,
+ .hljs-attribute,
+ .hljs-tag,
+ .hljs-name,
+ .hljs-regexp,
+ .hljs-link,
+ .hljs-name,
+ .hljs-selector-id,
+ .hljs-selector-class {
+ color: #f98181;
+ }
+
+ .hljs-number,
+ .hljs-meta,
+ .hljs-built_in,
+ .hljs-builtin-name,
+ .hljs-literal,
+ .hljs-type,
+ .hljs-params {
+ color: #fbbc88;
+ }
+
+ .hljs-string,
+ .hljs-symbol,
+ .hljs-bullet {
+ color: #b9f18d;
+ }
+
+ .hljs-title,
+ .hljs-section {
+ color: #faf594;
+ }
+
+ .hljs-keyword,
+ .hljs-selector-tag {
+ color: #70cff8;
+ }
+
+ .hljs-emphasis {
+ font-style: italic;
+ }
+
+ .hljs-strong {
+ font-weight: 700;
+ }
+ }
+}
diff --git a/docs/src/demos/Examples/CodeBlockLanguage/CodeBlockComponent.vue b/docs/src/demos/Examples/CodeBlockLanguage/Vue/CodeBlockComponent.vue
similarity index 100%
rename from docs/src/demos/Examples/CodeBlockLanguage/CodeBlockComponent.vue
rename to docs/src/demos/Examples/CodeBlockLanguage/Vue/CodeBlockComponent.vue
diff --git a/docs/src/demos/Examples/CodeBlockLanguage/index.vue b/docs/src/demos/Examples/CodeBlockLanguage/Vue/index.vue
similarity index 100%
rename from docs/src/demos/Examples/CodeBlockLanguage/index.vue
rename to docs/src/demos/Examples/CodeBlockLanguage/Vue/index.vue
diff --git a/docs/src/docPages/examples/syntax-highlighting.md b/docs/src/docPages/examples/syntax-highlighting.md
index 03b9598a..54d9eef1 100644
--- a/docs/src/docPages/examples/syntax-highlighting.md
+++ b/docs/src/docPages/examples/syntax-highlighting.md
@@ -1,3 +1,6 @@
# Syntax highlighting
-
+
diff --git a/packages/core/src/commands/focus.ts b/packages/core/src/commands/focus.ts
index dd3aee21..cf374a41 100644
--- a/packages/core/src/commands/focus.ts
+++ b/packages/core/src/commands/focus.ts
@@ -73,7 +73,13 @@ export const focus: RawCommands['focus'] = (position = null) => ({
tr.setStoredMarks(storedMarks)
}
- view.focus()
+ // focus async because in some situations weird things happen
+ // see: https://github.com/ueberdosis/tiptap/issues/1520
+ setTimeout(() => {
+ if (!editor.isDestroyed) {
+ view.focus()
+ }
+ }, 0)
}
return true