194 lines
5 KiB
Vue
194 lines
5 KiB
Vue
<template>
|
|
<div
|
|
class="textarea-question"
|
|
:class="[
|
|
(errors && errors.length) ? 'has-error' : '',
|
|
(meta?.valid && meta?.touched && !(errors && errors.length)) ? 'has-success' : ''
|
|
]">
|
|
<label
|
|
:for="inputId"
|
|
class="form-label">
|
|
{{ questionText }}
|
|
<span
|
|
v-if="!isRequired"
|
|
class="optional">(Optional)</span>
|
|
</label>
|
|
<div class="input-wrapper">
|
|
<textarea
|
|
:id="inputId"
|
|
:ref="inputId"
|
|
v-model.trim="value"
|
|
class="textarea-input"
|
|
:name="inputId"
|
|
:rows="[inputRows ?? 10]"
|
|
:placeholder="placeholderText"
|
|
:disabled="isDisabled"
|
|
:required="isRequired"
|
|
:maxlength="maxLength"
|
|
:validationRules="validationRules"
|
|
@change="validationRules ? handleChange : () => {}"
|
|
@blur="validationRules ? handleBlur : () => {}"
|
|
@paste="trimOnPaste"
|
|
@drop="trimOnPaste">
|
|
</textarea>
|
|
</div>
|
|
<p
|
|
v-if="characterCount == 0"
|
|
class="character-count">
|
|
{{ maxLength }} characters allowed
|
|
</p>
|
|
<p
|
|
v-else
|
|
class="character-count">
|
|
{{ maxLength - characterCount }} characters left
|
|
</p>
|
|
<div
|
|
v-show="errorMessage"
|
|
id="error-message"
|
|
class="row my-1 form-test-error">
|
|
<span
|
|
class="d-inline-flex mt-0"
|
|
role="alert">{{ errorMessage }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { useField } from 'vee-validate';
|
|
|
|
export default {
|
|
name: 'textarea-question',
|
|
props: {
|
|
placeholderText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
inputId: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
modelValue: String,
|
|
isDisabled: Boolean,
|
|
isRequired: Boolean,
|
|
validationRules: String,
|
|
cmsWidgetName: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
maxLength: {
|
|
type: String,
|
|
default: '300'
|
|
},
|
|
inputRows: Number
|
|
},
|
|
emits: ['update:modelValue'],
|
|
setup(props) {
|
|
const propsClone = { ...props };
|
|
const { modelValue } = propsClone;
|
|
const initialValue = modelValue ?? '';
|
|
|
|
const fieldOptions = {
|
|
type: 'text',
|
|
value: modelValue,
|
|
initialValue
|
|
};
|
|
|
|
const { errorMessage, handleChange, handleBlur, validate, errors, resetField, meta } =
|
|
useField(props.inputId, props.validationRules, fieldOptions);
|
|
|
|
return {
|
|
errorMessage,
|
|
handleChange,
|
|
handleBlur,
|
|
validate,
|
|
errors,
|
|
resetField,
|
|
meta
|
|
};
|
|
},
|
|
computed: {
|
|
/**
|
|
* @summary Returns the number of characters in the textarea field.
|
|
* @returns {number} The number of characters.
|
|
*/
|
|
characterCount() {
|
|
return this?.modelValue?.length ?? 0;
|
|
},
|
|
/**
|
|
* @summary Returns the CMS text associated with the question.
|
|
* @returns {string} QuestionText from cms data.
|
|
*/
|
|
questionText() {
|
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
|
},
|
|
value: {
|
|
get() {
|
|
return this.modelValue;
|
|
},
|
|
set(newValue) {
|
|
this.$emit('update:modelValue', newValue);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* @summary Removes whitespace from the end of pasted content.
|
|
* @param {event} evt - Browser event
|
|
*/
|
|
trimOnPaste(evt) {
|
|
evt.stopPropagation();
|
|
evt.preventDefault();
|
|
|
|
const data = evt.type === 'paste' ? (evt.clipboardData || window.clipboardData) : evt.dataTransfer;
|
|
const value = data.getData('Text')?.trim();
|
|
|
|
this.$emit('update:modelValue', this.modelValue + value);
|
|
}
|
|
}
|
|
};
|
|
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.textarea-question {
|
|
label {
|
|
color: $black;
|
|
font-weight: 600;
|
|
}
|
|
.form-test-error span{
|
|
color: $red;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.textarea-input {
|
|
padding: .625rem;
|
|
resize: none;
|
|
margin-bottom: .625rem;
|
|
width: 100%;
|
|
letter-spacing: inherit;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
line-height: 1.375rem;
|
|
&::placeholder {
|
|
color: $gray-500;
|
|
}
|
|
&:disabled,
|
|
&.disabled {
|
|
background-color: $gray-100;
|
|
}
|
|
}
|
|
}
|
|
|
|
.optional {
|
|
font-weight: $font-weight-normal;
|
|
color: $darker-gray;
|
|
}
|
|
|
|
.character-count {
|
|
color: #4d4e53;
|
|
font-size: 1rem;
|
|
line-height: 1.375rem;
|
|
}
|
|
</style>
|