seitime-frappe/frappe/public/js/form_builder/components/EditableInput.vue

89 lines
1.8 KiB
Vue

<script setup>
import { ref, nextTick, computed } from "vue";
import { useStore } from "../store";
let store = useStore();
const props = defineProps({
text: {
type: String,
},
placeholder: {
default: __("No Label"),
},
empty_label: {
default: __("No Label"),
},
});
let editing = ref(false);
let input_text = ref(null);
let hidden_text = ref(null);
let hidden_placeholder = ref(null);
let hidden_span_width = computed(() => {
if (hidden_text.value && props.text) {
return hidden_text.value.offsetWidth + 15 + "px";
} else if (!props.text) {
return hidden_placeholder.value.offsetWidth + 15 + "px";
}
return "40px";
});
function focus_on_label() {
if (!store.read_only) {
editing.value = true;
nextTick(() => input_text.value.focus());
}
}
defineExpose({ focus_on_label });
</script>
<template>
<div @dblclick="focus_on_label" :title="__('Double click to edit label')">
<input
v-if="editing"
class="input-text"
ref="input_text"
:disabled="store.read_only"
type="text"
:placeholder="placeholder"
:value="text"
:style="{ width: hidden_span_width }"
@input="(event) => $emit('update:modelValue', event.target.value)"
@keydown.enter="editing = false"
@blur="editing = false"
@click.stop
/>
<span v-else-if="text" v-html="text"></span>
<i v-else class="text-muted">
{{ empty_label }}
</i>
<span class="hidden-span" ref="hidden_text" v-html="text"></span>
<span class="hidden-span" ref="hidden_placeholder">{{ placeholder }}</span>
</div>
</template>
<style lang="scss" scoped>
.input-text {
border: none;
min-width: 50px;
padding: 0px !important;
&:focus {
outline: none;
background-color: inherit;
}
&::placeholder {
font-style: italic;
font-weight: normal;
}
}
.hidden-span {
visibility: hidden;
position: absolute;
width: max-content;
}
</style>