72 lines
2.1 KiB
Vue
72 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { onBeforeUnmount, onMounted, ref, watch, h, render } from 'vue';
|
|
import { Editor, EditorContent } from '@tiptap/vue-3'
|
|
import TextEditorMenu from './TextEditorMenu.vue';
|
|
import StarterKit from '@tiptap/starter-kit'
|
|
|
|
|
|
const props = defineProps<{
|
|
modelValue?: string | null | undefined
|
|
placeholder?: string | null
|
|
}>()
|
|
const editor = ref<Editor>()
|
|
const menu = ref()
|
|
const getContent = (): string => editor.value?.getHTML() || ''
|
|
const isFocused = (): boolean => editor.value?.isFocused || false
|
|
|
|
defineExpose({ editor, getContent, isFocused });
|
|
const emit = defineEmits(['update:modelValue', 'change:modelValue'])
|
|
|
|
// set editor content on prop change
|
|
watch(() => props.modelValue, (newValue, oldValue) => {
|
|
const isSame = editor.value?.getHTML() === newValue
|
|
if (isSame) return
|
|
editor.value?.commands.setContent(newValue as string)
|
|
})
|
|
|
|
onMounted(() => {
|
|
editor.value = new Editor({
|
|
extensions: [StarterKit],
|
|
content: props.modelValue,
|
|
onUpdate: () => {
|
|
if (!editor.value) return
|
|
emit('update:modelValue', editor.value.getHTML())
|
|
},
|
|
onFocus: () => {
|
|
// menu.value = h(TextEditorMenu, {
|
|
// editor: editor.value
|
|
// });
|
|
// render(menu.value, document.body)
|
|
},
|
|
onBlur: () => {
|
|
if (!editor.value) return
|
|
emit('change:modelValue', editor.value.getHTML())
|
|
|
|
// if (menu.value) {
|
|
// render(null, document.body, menu.value.el)
|
|
// menu.value = null
|
|
// }
|
|
},
|
|
})
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
editor.value?.destroy()
|
|
})
|
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<div v-bind:spellcheck="editor?.isFocused">
|
|
<TextEditorMenu :editor="editor" />
|
|
<div class="relative">
|
|
<EditorContent :editor="editor" class="editor mb-8 content" />
|
|
<!-- Placeholder -->
|
|
<div class="absolute top-0 italic text-muted-foreground pointer-events-none"
|
|
:class="{ 'hidden': !editor?.isEmpty }">{{ props.placeholder || 'Beschreibung' }}</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style></style> |