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"
 | 
						|
      :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
 | 
						|
      v-if="editable"
 | 
						|
      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="{ '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>
 |