Files
Caramel-CRM/resources/js/components/TextEditor.vue
T

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>