mitlist/fe/src/components/valerie/VTextarea.vue

140 lines
3.8 KiB
Vue

<template>
<textarea
:id="id"
:value="modelValue"
:placeholder="placeholder"
:disabled="disabled"
:required="required"
:rows="rows"
:class="textareaClasses"
:aria-invalid="error ? 'true' : null"
@input="onInput"
></textarea>
</template>
<script lang="ts">
import { defineComponent, computed, PropType } from 'vue';
export default defineComponent({
name: 'VTextarea',
props: {
modelValue: {
type: String,
required: true,
},
placeholder: {
type: String,
default: null,
},
disabled: {
type: Boolean,
default: false,
},
required: {
type: Boolean,
default: false,
},
rows: {
type: Number,
default: 3,
},
error: {
type: Boolean,
default: false,
},
id: {
type: String,
default: null,
},
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const textareaClasses = computed(() => [
'form-input', // Re-use .form-input styles from VInput if they are generic enough
'textarea', // Specific class for textarea if needed for overrides or additions
{ 'error': props.error },
]);
const onInput = (event: Event) => {
const target = event.target as HTMLTextAreaElement;
emit('update:modelValue', target.value);
};
return {
textareaClasses,
onInput,
};
},
});
</script>
<style lang="scss" scoped>
// Assuming .form-input is defined globally or imported, providing base styling.
// If VInput.vue's <style> is not scoped, .form-input might be available.
// If it is scoped, or you want VTextarea to be independent, redefine or import.
// For this example, let's assume .form-input styles from VInput might apply if global,
// or we can duplicate/abstract them.
// Minimal re-definition or import of .form-input (if not globally available)
// If VInput.scss is structured to be importable (e.g. using @use or if not scoped):
// @import 'VInput.scss'; // (path dependent) - this won't work directly with scoped SFC styles normally
// Let's add some basic .form-input like styles here for completeness,
// assuming they are not inherited or globally available from VInput.vue's styles.
// Ideally, these would be part of a shared SCSS utility file.
.form-input {
display: block;
width: 100%;
padding: 0.5em 0.75em;
font-size: 1rem;
font-family: inherit;
line-height: 1.5;
color: #212529;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
&:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
&::placeholder {
color: #6c757d;
opacity: 1;
}
&[disabled],
&[readonly] { // readonly is not a prop here, but good for general form-input style
background-color: #e9ecef;
opacity: 1;
cursor: not-allowed;
}
&.error {
border-color: #dc3545;
&:focus {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
}
}
// Textarea specific styles
.textarea {
// Override line-height if needed, or ensure it works well with multi-line text.
// line-height: 1.5; // Usually inherited correctly from .form-input
// May add min-height or resize behavior if desired:
// resize: vertical; // Allow vertical resize, disable horizontal
min-height: calc(1.5em * var(--v-textarea-rows, 3) + 1em + 2px); // Approx based on rows, padding, border
}
// CSS variable for rows to potentially influence height if needed by .textarea class
// This is an alternative way to use props.rows in CSS if you need more complex calculations.
// For direct attribute binding like :rows="rows", this is not strictly necessary.
// :style="{ '--v-textarea-rows': rows }" could be bound to the textarea element.
</style>