tiptapify
Version:
Tiptap3 editor with Vuetify3 menu implementation
107 lines (90 loc) • 2.62 kB
text/typescript
import { computePosition, flip, shift } from '@floating-ui/dom'
import { posToDOMRect, VueRenderer } from '@tiptap/vue-3'
import CommandsList from './CommandsList.vue'
const updatePosition = (editor, element) => {
const virtualElement = {
getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to),
}
computePosition(virtualElement, element, {
placement: 'bottom-start',
strategy: 'absolute',
middleware: [shift(), flip()],
}).then(({ x, y, strategy }) => {
element.style.width = 'max-content'
element.style.position = strategy
element.style.left = `${x}px`
element.style.top = `${y}px`
})
}
export default {
items: ({ query }) => {
return [
{
title: 'H1',
icon: 'FormatHeader1',
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).setNode('heading', { level: 1 }).run()
},
},
{
title: 'H2',
icon: 'FormatHeader2',
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).setNode('heading', { level: 2 }).run()
},
},
{
title: 'Bold',
icon: 'FormatBold',
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).setMark('bold').run()
},
},
{
title: 'Italic',
icon: 'FormatItalic',
command: ({ editor, range }) => {
editor.chain().focus().deleteRange(range).setMark('italic').run()
},
},
]
.filter(item => item.title.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 10)
},
render: () => {
let component
return {
onStart: props => {
component = new VueRenderer(CommandsList, {
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
component.destroy()
component.element.remove()
return true
}
return component.ref?.onKeyDown(props)
},
onExit() {
component.destroy()
component.element.remove()
},
}
},
}