import type { CodeBlockOptions } from '@tiptap/extension-code-block'; import CodeBlock from '@tiptap/extension-code-block'; import { LowlightPlugin } from './lowlight-plugin.js'; import { ReactNodeViewRenderer } from '@tiptap/react'; export interface CodeBlockLowlightOptions extends CodeBlockOptions { /** * The lowlight instance. */ lowlight: any; view: any; } const TAB_CHAR = '\u00A0\u00A0'; /** * This extension allows you to highlight code blocks with lowlight. * @see https://tiptap.dev/api/nodes/code-block-lowlight */ export const CustomCodeBlock = CodeBlock.extend({ selectable: true, addOptions() { return { ...this.parent?.(), lowlight: {}, languageClassPrefix: 'language-', exitOnTripleEnter: true, exitOnArrowDown: true, defaultLanguage: null, HTMLAttributes: {}, view: null, }; }, addKeyboardShortcuts() { return { ...this.parent?.(), 'Mod-a': () => { if (this.editor.isActive('codeBlock')) { const { state } = this.editor; const { $from } = state.selection; let codeBlockNode = null; let codeBlockPos = null; let depth = 0; for (depth = $from.depth; depth > 0; depth--) { const node = $from.node(depth); if (node.type.name === 'codeBlock') { codeBlockNode = node; codeBlockPos = $from.start(depth) - 1; break; } } if (codeBlockNode && codeBlockPos !== null) { const codeBlockStart = codeBlockPos; const codeBlockEnd = codeBlockPos + codeBlockNode.nodeSize; const contentStart = codeBlockStart + 1; const contentEnd = codeBlockEnd - 1; this.editor.commands.setTextSelection({ from: contentStart, to: contentEnd, }); return true; } } return false; }, }; }, addNodeView() { // Force the react node view to render immediately using flush sync (https://github.com/ueberdosis/tiptap/blob/b4db352f839e1d82f9add6ee7fb45561336286d8/packages/react/src/ReactRenderer.tsx#L183-L191) this.editor.isInitialized = true; return ReactNodeViewRenderer(this.options.view); }, addProseMirrorPlugins() { return [ ...(this.parent?.() || []), LowlightPlugin({ name: this.name, lowlight: this.options.lowlight, defaultLanguage: this.options.defaultLanguage, }), ]; }, });