Updated the styles for dropdown, textbox, and textarea components to more closely align with heritage design, including the icon for the dropdown component.
354 lines
10 KiB
Vue
354 lines
10 KiB
Vue
<template>
|
|
<div
|
|
class="textbox-question"
|
|
:class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
|
<label
|
|
v-if="displayQuestionText"
|
|
:for="inputId"
|
|
:aria-label="questionText"
|
|
class="form-label"
|
|
:class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']"
|
|
v-html="questionText"></label>
|
|
<div
|
|
class="input-wrapper"
|
|
:class="[
|
|
includeSearchIcon ? 'has-search-icon' : '',
|
|
includeSelectIcon ? 'has-select-icon' : ''
|
|
]">
|
|
<input
|
|
:id="inputId"
|
|
:ref="inputId"
|
|
v-model.trim="value"
|
|
v-maska
|
|
:data-maska="getMaskFromProp"
|
|
:data-maska-tokens="getTokensFromProp"
|
|
class="form-control"
|
|
:type="type"
|
|
:name="inputId"
|
|
:placeholder="placeholderText"
|
|
:aria-disabled="isDisabled"
|
|
:disabled="isDisabled"
|
|
:aria-required="isRequired"
|
|
:aria-label="questionText"
|
|
:min="min"
|
|
:max="max"
|
|
:required="isRequired"
|
|
:class="[
|
|
hasIcon ? 'has-icon' : '',
|
|
iconRight ? 'icon-right' : '',
|
|
cornerStyle === 'rounded' ? 'rounded-pill' : ''
|
|
]"
|
|
:validationRules="validationRules"
|
|
:maxlength="maxLength ? maxLength : '999'"
|
|
:data-bs-toggle="includeSelectIcon ? 'modal' : ''"
|
|
:data-bs-target="'#' + cmsWidgetName"
|
|
@change="handleChange"
|
|
@blur="handleChange"
|
|
@focus="$emit('focus', $event.target.value)"
|
|
@paste="trimOnPaste"
|
|
@drop="trimOnPaste" />
|
|
<button
|
|
v-if="includeSearchIcon"
|
|
type="submit"
|
|
aria-label="Search button"
|
|
@click="clickedSearch" />
|
|
<button
|
|
v-if="includeSelectIcon"
|
|
type="submit"
|
|
data-bs-toggle="modal"
|
|
:data-bs-target="'#' + cmsWidgetName"
|
|
aria-label="Select button" />
|
|
</div>
|
|
<div
|
|
v-show="errorMessage"
|
|
ref="errorMessageDiv"
|
|
class="row my-1 form-test-error">
|
|
<span
|
|
class="d-inline-flex mt-0"
|
|
role="alert">{{ errorMessage }}</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { useField, validate } from 'vee-validate';
|
|
|
|
export default {
|
|
name: 'textbox-question',
|
|
props: {
|
|
type: {
|
|
type: String,
|
|
default: 'text'
|
|
},
|
|
placeholderText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
displayQuestionText: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
modelValue: String,
|
|
inputId: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
isDisabled: Boolean,
|
|
isRequired: Boolean,
|
|
hasIcon: Boolean, // If input has an icon
|
|
iconRight: Boolean, // Place icon on right side of text input, otherwise default is left if hasIcon prop is used
|
|
hasError: Boolean,
|
|
mask: {
|
|
type: [String, Object],
|
|
default: ''
|
|
},
|
|
validationRules: String,
|
|
cmsWidgetName: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
maxLength: String,
|
|
questionAlignment: String, // Left or center. Left is default.
|
|
cornerStyle: String, // Rounded or square. Square is default.
|
|
includeSearchIcon: Boolean,
|
|
includeSelectIcon: Boolean,
|
|
min: String,
|
|
max: String,
|
|
disableAutoFill: Boolean
|
|
},
|
|
emits: ['focus', 'update:modelValue', 'textboxQuestionEvent.inputIdAssigned', 'click-event'],
|
|
setup(props) {
|
|
const propsClone = { ...props };
|
|
const { modelValue } = propsClone;
|
|
let initialValue;
|
|
|
|
switch (typeof modelValue) {
|
|
case 'number':
|
|
initialValue = modelValue;
|
|
break;
|
|
default:
|
|
initialValue = modelValue && modelValue.length > 0 ? modelValue : '';
|
|
break;
|
|
}
|
|
|
|
const fieldOptions = {
|
|
type: 'text',
|
|
value: modelValue,
|
|
initialValue
|
|
};
|
|
|
|
// eslint-disable-next-line no-shadow
|
|
const { errorMessage, handleBlur, handleChange, meta, validate, errors } =
|
|
useField(props.inputId, props.validationRules, fieldOptions);
|
|
|
|
return {
|
|
errorMessage,
|
|
handleBlur,
|
|
handleChange,
|
|
validate,
|
|
meta,
|
|
errors
|
|
};
|
|
},
|
|
computed: {
|
|
questionText() {
|
|
return this.getCmsContent(this.cmsWidgetName, 'QuestionText');
|
|
},
|
|
value: {
|
|
get() {
|
|
return this.modelValue;
|
|
},
|
|
set(newValue) {
|
|
this.$emit('update:modelValue', newValue);
|
|
}
|
|
},
|
|
getMaskFromProp() {
|
|
if (this.mask) {
|
|
if (this.mask.mask) {
|
|
return this.mask.mask;
|
|
}
|
|
return this.mask;
|
|
}
|
|
return null;
|
|
},
|
|
getTokensFromProp() {
|
|
if (this.mask?.tokens) {
|
|
return `{ '${this.mask.tokens.token}': { 'pattern': '${this.mask.tokens.pattern}' }}`;
|
|
}
|
|
return null;
|
|
}
|
|
},
|
|
watch: {
|
|
async value(newValue) {
|
|
const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation
|
|
if (result.valid) {
|
|
this.handleChange(newValue); // trigger full validation on this field only
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.$emit('textboxQuestionEvent.inputIdAssigned', this.inputId);
|
|
},
|
|
methods: {
|
|
trimOnPaste(evt) {
|
|
evt.stopPropagation();
|
|
evt.preventDefault();
|
|
|
|
const input = document.getElementById(evt.srcElement.id);
|
|
const originalValue = input.value;
|
|
const startPosition = input.selectionStart;
|
|
const endPosition = input.selectionEnd;
|
|
const selectionLength = endPosition - startPosition;
|
|
|
|
let data = null;
|
|
if (evt.type === 'paste') {
|
|
data = evt.clipboardData || window.clipboardData;
|
|
} else {
|
|
data = evt.dataTransfer;
|
|
}
|
|
|
|
const textValue = data.getData('Text');
|
|
|
|
// Insert the pasted/dropped string at the index position
|
|
const arrOriginalString = originalValue.split('');
|
|
arrOriginalString.splice(startPosition, selectionLength, textValue);
|
|
const blendedString = arrOriginalString.join('');
|
|
|
|
this.$emit('update:modelValue', blendedString);
|
|
},
|
|
clickedSearch() {
|
|
if (this.meta.valid) {
|
|
this.$emit('click-event');
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "@/styles/ux-variables-svg-strings.scss";
|
|
input[type='date']::-webkit-inner-spin-button {
|
|
display: none;
|
|
}
|
|
|
|
input[type='date']::-webkit-calendar-picker-indicator {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
right: 1px;
|
|
background-image: url($svg-calendar-picker);
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
width: 16px; // check this
|
|
height: 16px;
|
|
display: flex;
|
|
border-radius: 0 7px 7px 0;
|
|
background-color: #e4f1f7;
|
|
&:hover {
|
|
cursor: pointer;
|
|
}
|
|
padding: 15px 0;
|
|
min-width: 48px;
|
|
}
|
|
|
|
input::-webkit-date-and-time-value {
|
|
text-align: left !important;
|
|
}
|
|
|
|
.textbox-question {
|
|
label {
|
|
color: $black;
|
|
font-weight: 600;
|
|
}
|
|
span {
|
|
font-weight: 400;
|
|
font-size: 0.875rem;
|
|
color: #4d5151;
|
|
}
|
|
.form-test-error span {
|
|
color: #d4281c;
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.input-wrapper {
|
|
position: relative;
|
|
&.has-search-icon {
|
|
input[type='text'] {
|
|
border-radius: $border-radius;
|
|
}
|
|
button[type='submit'] {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
right: 0;
|
|
background-image: url($svg-search-icon);
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
border-radius: 0 $border-radius-lg $border-radius-lg 0;
|
|
background-color: $blue-100;
|
|
width: 2.75rem;
|
|
height: 100%;
|
|
border: 1px solid $gray-500;
|
|
border-left: none;
|
|
display: flex;
|
|
}
|
|
}
|
|
&.has-select-icon {
|
|
button[type='submit'] {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
right: 1rem;
|
|
background-image: url($svg-select-icon);
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-color: transparent;
|
|
width: 1rem;
|
|
height: 100%;
|
|
border: 0px;
|
|
border-left: none;
|
|
display: flex;
|
|
}
|
|
}
|
|
}
|
|
input {
|
|
&.has-icon {
|
|
background-image: url(~@/assets/img/icons/location-pin.svg);
|
|
background-repeat: no-repeat;
|
|
background-position: 0.75rem 50%;
|
|
background-size: auto 1rem;
|
|
padding: 0 0.75rem 0 2.5rem;
|
|
&.icon-right {
|
|
background-position: calc(100% - 0.75rem) 50%;
|
|
padding: 0 2.5rem 0 0.75rem;
|
|
}
|
|
}
|
|
}
|
|
.form-label {
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
.form-control {
|
|
border: $border-input;
|
|
border-radius: $border-radius;
|
|
min-height: 3rem;
|
|
max-height: 3rem;
|
|
padding: 0.75rem 1rem;
|
|
letter-spacing: inherit;
|
|
box-shadow: $box-shadow-input;
|
|
&::placeholder {
|
|
color: $gray-500;
|
|
}
|
|
&:focus, &:focus-within {
|
|
border: $border-input-focus;
|
|
}
|
|
&:disabled,
|
|
&.disabled {
|
|
background-color: $gray-100;
|
|
}
|
|
}
|
|
p {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|