66 lines
1.6 KiB
Vue
66 lines
1.6 KiB
Vue
<script setup>
|
|
import { nextTick, onMounted, ref, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
modelValue: { type: String, default: '' },
|
|
disabled: { type: Boolean, default: false },
|
|
sending: { type: Boolean, default: false },
|
|
placeholder: { type: String, default: '' },
|
|
});
|
|
|
|
const emit = defineEmits(['update:modelValue', 'submit', 'typing']);
|
|
|
|
const inputRef = ref(null);
|
|
|
|
function focus() {
|
|
nextTick(() => inputRef.value?.focus());
|
|
}
|
|
|
|
function onInput(e) {
|
|
emit('update:modelValue', e.target.value);
|
|
emit('typing');
|
|
}
|
|
|
|
function onKeydown(e) {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
if (!props.disabled && !props.sending && props.modelValue.trim()) {
|
|
emit('submit');
|
|
}
|
|
}
|
|
}
|
|
|
|
watch(() => props.disabled, (isDisabled, wasDisabled) => {
|
|
if (wasDisabled && !isDisabled) {
|
|
focus();
|
|
}
|
|
});
|
|
|
|
onMounted(() => {
|
|
if (!props.disabled) {
|
|
focus();
|
|
}
|
|
});
|
|
|
|
defineExpose({ focus });
|
|
</script>
|
|
|
|
<template>
|
|
<form class="chat-composer-form" @submit.prevent="emit('submit')">
|
|
<textarea
|
|
ref="inputRef"
|
|
class="comm-input chat-composer-input"
|
|
:value="modelValue"
|
|
:placeholder="placeholder"
|
|
:disabled="disabled || sending"
|
|
rows="1"
|
|
autocomplete="off"
|
|
@input="onInput"
|
|
@keydown="onKeydown"
|
|
/>
|
|
<button type="submit" class="comm-btn comm-btn-primary" :disabled="disabled || sending || !modelValue.trim()">
|
|
<i :class="sending ? 'fa fa-spinner fa-spin' : 'fa fa-paper-plane'"></i>
|
|
</button>
|
|
</form>
|
|
</template>
|