- Vue: ^2.6.10
- tiptap: ^1.23.1
tiptapを使っていて、困ったことがありました。
tiptapを使えば、ハイライト付きのコードブロックが簡単に実装できます。
しかし、挿入されたコードブロックからカーソルを外すには、command+Z(macだと)するか、コードブロック以外の要素をクリックするかしかないみたいでした。
これだと、エディト領域の一番下にコードブロックが作られた場合に不便です。
コードブロックが挿入されたら、その下に空行を挿入することで、上記の問題を解決したので、共有します。
editor.vue
<template>
<div class="editor" style="width: 100%;">
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive }">
<div class="menubar">
<button
class="menubar__button"
:class="{ 'is-active-button': isActive.code_block() }"
@click="startCodeBlock(commands, isActive)">
<font-awesome-icon icon="code" />
</button>
</div>
</editor-menu-bar>
<editor-content class="editor__content" :editor="editor" />
</div>
</template>
<script>
import { Editor, EditorContent, EditorMenuBar } from 'tiptap'
import { safeInsert, findBlockNodes } from 'prosemirror-utils'
import python from 'highlight.js/lib/languages/python'
import {
CodeBlock,
CodeBlockHighlight
} from 'tiptap-extensions'
export default {
components: {
EditorContent,
EditorMenuBar,
},
data() {
return {
editor: new Editor({
extensions: [
new CodeBlock(),
new CodeBlockHighlight({
languages: { python }
})
],
content: ``,
}),
}
},
beforeDestroy() {
this.editor.destroy()
},
methods: {
startCodeBlock(commands, isActive) {
commands.code_block()
if (isActive.code_block()) {
this.insertEmptyLineBelowCodeBlock()
}
},
insertEmptyLineBelowCodeBlock() {
const { schema, state, view } = this.editor
const selection = state.tr.selection
const anchorPos = selection.$anchor.pos
const blockNodes = findBlockNodes(view.state.doc)
for (const { node, pos } of blockNodes) {
// コードブロックの場所より下に何らかのnodeがある時は空行を挿入する必要がないので、return
if (anchorPos < pos) {
return
}
}
// <p>をコードブロックの下にinsertする(https://github.com/atlassian/prosemirror-utilsのsafeInsertを利用)
const p = schema.nodes.paragraph.create()
view.dispatch(safeInsert(p, anchorPos)(state.tr))
// 選択カーソルをコードブロック内に戻す
view.dispatch(view.state.tr.setSelection(selection))
}
}
}
</script>
<style>
.ProseMirror pre {
white-space: pre-wrap;
width: 100%;
}
.editor__content pre {
padding: .7rem 1rem;
border-radius: 5px;
background: #000;
color: #fff;
font-size: .8rem;
overflow-x: auto;
}
.editor__content * {
caret-color: currentColor;
}
.is-active-button {
background-color: antiquewhite
}
</style>