mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.8 KiB
128 lines
2.8 KiB
<template>
|
|
<div
|
|
class="group/contenteditable relative overflow-visible"
|
|
:class="{ 'flex items-center': !iconInline }"
|
|
>
|
|
<span
|
|
ref="contenteditable"
|
|
dir="auto"
|
|
:contenteditable="editable"
|
|
style="min-width: 2px"
|
|
:class="iconInline ? 'inline' : 'block'"
|
|
class="peer outline-none focus:block"
|
|
@keydown.enter.prevent="blurContenteditable"
|
|
@focus="$emit('focus', $event)"
|
|
@blur="onBlur"
|
|
>
|
|
{{ value }}
|
|
</span>
|
|
<span
|
|
v-if="withRequired"
|
|
title="Required"
|
|
class="text-red-500 peer-focus:hidden"
|
|
@click="focusContenteditable"
|
|
>
|
|
*
|
|
</span>
|
|
<IconPencil
|
|
class="cursor-pointer flex-none opacity-0 group-hover/contenteditable-container:opacity-100 group-hover/contenteditable:opacity-100 align-middle peer-focus:hidden"
|
|
:style="iconInline ? {} : { right: -(1.1 * iconWidth) + 'px' }"
|
|
title="Edit"
|
|
:class="{ invisible: !editable, 'ml-1': !withRequired, 'absolute': !iconInline, 'inline align-bottom': iconInline }"
|
|
:width="iconWidth"
|
|
:stroke-width="iconStrokeWidth"
|
|
@click="[focusContenteditable(), selectOnEditClick && selectContent()]"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { IconPencil } from '@tabler/icons-vue'
|
|
|
|
export default {
|
|
name: 'ContenteditableField',
|
|
components: {
|
|
IconPencil
|
|
},
|
|
props: {
|
|
modelValue: {
|
|
type: String,
|
|
required: false,
|
|
default: ''
|
|
},
|
|
iconInline: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false
|
|
},
|
|
iconWidth: {
|
|
type: Number,
|
|
required: false,
|
|
default: 30
|
|
},
|
|
withRequired: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false
|
|
},
|
|
selectOnEditClick: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false
|
|
},
|
|
editable: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: true
|
|
},
|
|
iconStrokeWidth: {
|
|
type: Number,
|
|
required: false,
|
|
default: 2
|
|
}
|
|
},
|
|
emits: ['update:model-value', 'focus', 'blur'],
|
|
data () {
|
|
return {
|
|
value: ''
|
|
}
|
|
},
|
|
watch: {
|
|
modelValue: {
|
|
handler (value) {
|
|
this.value = value
|
|
},
|
|
immediate: true
|
|
}
|
|
},
|
|
methods: {
|
|
selectContent () {
|
|
const el = this.$refs.contenteditable
|
|
|
|
const range = document.createRange()
|
|
|
|
range.selectNodeContents(el)
|
|
|
|
const sel = window.getSelection()
|
|
|
|
sel.removeAllRanges()
|
|
|
|
sel.addRange(range)
|
|
},
|
|
onBlur (e) {
|
|
setTimeout(() => {
|
|
this.value = this.$refs.contenteditable.innerText.trim() || this.modelValue
|
|
this.$emit('update:model-value', this.value)
|
|
this.$emit('blur', e)
|
|
}, 1)
|
|
},
|
|
focusContenteditable () {
|
|
this.$refs.contenteditable.focus()
|
|
},
|
|
blurContenteditable () {
|
|
this.$refs.contenteditable.blur()
|
|
}
|
|
}
|
|
}
|
|
</script>
|