|
@@ -0,0 +1,159 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <input
|
|
|
|
|
+ :id="`${id}_input`"
|
|
|
|
|
+ :value="initialValue"
|
|
|
|
|
+ type="hidden"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <trix-editor
|
|
|
|
|
+ :id="id"
|
|
|
|
|
+ ref="trixEditor"
|
|
|
|
|
+ :input="`${id}_input`"
|
|
|
|
|
+ class="trix-content"
|
|
|
|
|
+ v-bind="$attrs"
|
|
|
|
|
+ @trix-change="onTrixChange"
|
|
|
|
|
+ @trix-focus="onTrixFocus"
|
|
|
|
|
+ @trix-blur="onTrixBlur"
|
|
|
|
|
+ @trix-before-initialize="onTrixBeforeInitialize"
|
|
|
|
|
+ @trix-initialize="onTrixInitialize"
|
|
|
|
|
+ @trix-paste="onTrixPaste"
|
|
|
|
|
+ @trix-selection-change="onTrixSelectionChange"
|
|
|
|
|
+ @trix-file-accept.prevent="onTrixFileAccept"
|
|
|
|
|
+ @trix-attachment-add="onTrixAttachmentAdd"
|
|
|
|
|
+ @trix-attachment-remove="onTrixAttachmentRemove"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import Trix from "trix"
|
|
|
|
|
+
|
|
|
|
|
+defineOptions({ inheritAttrs: false })
|
|
|
|
|
+
|
|
|
|
|
+const model = defineModel()
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ id: {
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ required: false,
|
|
|
|
|
+ default: () => useId()
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ config: {
|
|
|
|
|
+ type: Object,
|
|
|
|
|
+ required: false,
|
|
|
|
|
+ default: () => {}
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits([
|
|
|
|
|
+ "blur",
|
|
|
|
|
+ "change",
|
|
|
|
|
+ "focus",
|
|
|
|
|
+ "input",
|
|
|
|
|
+ "trix-attachment-add",
|
|
|
|
|
+ "trix-attachment-remove",
|
|
|
|
|
+ "trix-before-initialize",
|
|
|
|
|
+ "trix-blur",
|
|
|
|
|
+ "trix-change",
|
|
|
|
|
+ "trix-file-accept",
|
|
|
|
|
+ "trix-focus",
|
|
|
|
|
+ "trix-initialize",
|
|
|
|
|
+ "trix-paste",
|
|
|
|
|
+ "trix-selection-change"
|
|
|
|
|
+])
|
|
|
|
|
+
|
|
|
|
|
+defineExpose({
|
|
|
|
|
+ id: props.id,
|
|
|
|
|
+ modelValue: model,
|
|
|
|
|
+ reset() {
|
|
|
|
|
+ reset()
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const trixEditor = useTemplateRef("trixEditor")
|
|
|
|
|
+const initialValue = ref(_isNull(model.value) ? "" : model.value)
|
|
|
|
|
+
|
|
|
|
|
+onBeforeMount(() => {
|
|
|
|
|
+ _merge(Trix.config, trixConfig, props.config)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+async function reset() {
|
|
|
|
|
+ if (_isNull(model.value)) {
|
|
|
|
|
+ model.value = ""
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ trixEditor.value?.editor.loadHTML(model.value)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixChange(event) {
|
|
|
|
|
+ model.value = event.target.value
|
|
|
|
|
+
|
|
|
|
|
+ emit("change", event)
|
|
|
|
|
+ emit("input", event)
|
|
|
|
|
+ emit("trix-change", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixInitialize(event) {
|
|
|
|
|
+ reset()
|
|
|
|
|
+ emit("trix-initialize", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixFocus(event) {
|
|
|
|
|
+ emit("focus", event)
|
|
|
|
|
+ emit("trix-focus", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixBlur(event) {
|
|
|
|
|
+ emit("blur", event)
|
|
|
|
|
+ emit("trix-blur", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixBeforeInitialize(event) {
|
|
|
|
|
+ emit("trix-before-initialize", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixPaste(event) {
|
|
|
|
|
+ emit("trix-paste", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixSelectionChange(event) {
|
|
|
|
|
+ emit("trix-selection-change", event)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixFileAccept(file) {
|
|
|
|
|
+ emit("trix-file-accept", file)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixAttachmentAdd(file) {
|
|
|
|
|
+ emit("trix-attachment-add", file)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onTrixAttachmentRemove(file) {
|
|
|
|
|
+ emit("trix-attachment-remove", file)
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style>
|
|
|
|
|
+@reference "~/assets/css/main.css";
|
|
|
|
|
+
|
|
|
|
|
+trix-editor {
|
|
|
|
|
+ /* textarea.root */
|
|
|
|
|
+ /* min-height: py-2 [--spacing(4)] + border [2 * 1px = 2px] + line-height [1.5rem] */
|
|
|
|
|
+ @apply max-w-full! min-h-[calc(--spacing(4)+2px+1.5rem)] appearance-none rounded-md border
|
|
|
|
|
+ border-surface-300 bg-surface-0 px-3 py-2 text-surface-700
|
|
|
|
|
+ shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] outline-hidden transition-colors
|
|
|
|
|
+ duration-200 placeholder:text-surface-500 enabled:hover:border-surface-400
|
|
|
|
|
+ enabled:focus:border-primary disabled:bg-surface-200 disabled:text-surface-500
|
|
|
|
|
+ dark:border-surface-700 dark:bg-surface-950 dark:text-surface-0
|
|
|
|
|
+ dark:placeholder:text-surface-400 dark:enabled:hover:border-surface-600
|
|
|
|
|
+ dark:disabled:bg-surface-700 dark:disabled:text-surface-400
|
|
|
|
|
+ p-invalid:border-red-400 p-invalid:placeholder:text-red-600
|
|
|
|
|
+ dark:p-invalid:border-red-300 dark:p-invalid:placeholder:text-red-400
|
|
|
|
|
+ p-small:px-2.5 p-small:py-1.5 p-small:text-sm p-large:px-3.5 p-large:py-2.5
|
|
|
|
|
+ p-large:text-lg p-fluid:w-full p-filled:bg-surface-50
|
|
|
|
|
+ dark:p-filled:bg-surface-800;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|