It has more layout page linting and I have removed (really re-removed) the reduntant router parms.
200 lines
5 KiB
Vue
200 lines
5 KiB
Vue
<template>
|
|
<div
|
|
class="textarea-question"
|
|
:class="(errors && errors.length) ? 'has-error' : ''">
|
|
<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="form-control"
|
|
: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 class="character-count margin-top-8">
|
|
{{ maxLength - characterCount }}/{{ maxLength }} characters remaining
|
|
</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 } =
|
|
useField(props.inputId,
|
|
props.validationRules,
|
|
fieldOptions);
|
|
|
|
return {
|
|
errorMessage,
|
|
handleChange,
|
|
handleBlur,
|
|
validate,
|
|
errors,
|
|
resetField
|
|
};
|
|
},
|
|
computed: {
|
|
/**
|
|
* @summary Returns the number of characters in the textarea field.
|
|
* @returns {number}
|
|
*/
|
|
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: 500;
|
|
}
|
|
.form-test-error span{
|
|
color: $red;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-control {
|
|
max-height: 30rem;
|
|
border: 1px solid $gray-500;
|
|
border-radius: 0.5rem;
|
|
padding: 12px 16px;
|
|
&::placeholder {
|
|
color: $gray-500;
|
|
}
|
|
&:focus {
|
|
box-shadow: 0 0 0 2.5px $blue;
|
|
}
|
|
&:disabled,
|
|
&.disabled {
|
|
background-color: $gray-100;
|
|
&:hover {
|
|
box-shadow: 0 0 0 4px transparent;
|
|
border: 1px solid $gray-500;
|
|
}
|
|
}
|
|
&:hover {
|
|
border: 1px solid $gray-500;
|
|
box-shadow: 0 0 0 4px $blue-300;
|
|
}
|
|
}
|
|
}
|
|
|
|
.optional {
|
|
color: $gray-550;
|
|
}
|
|
|
|
.character-count {
|
|
color: $gray-600;
|
|
font-size: 12px;
|
|
margin-bottom: 0px;
|
|
}
|
|
|
|
.margin-top-8 {
|
|
margin-top: 8px;
|
|
}
|
|
</style>
|