- value logging masking type - added to other components under button-questions - added logging for radio as it was missing (only fires onchange of radio which is different than others although arguably more right...
241 lines
5.7 KiB
Vue
241 lines
5.7 KiB
Vue
<template>
|
|
<div
|
|
class="list-group list-button-horizontal d-flex flex-column w-100"
|
|
:class="[(errors.length > 0 || hasError) ? 'has-error' : '']"
|
|
@keyup.space="triggerButton()"
|
|
@keyup.up="handleKeyupArrow()"
|
|
@keyup.down="handleKeyupArrow()"
|
|
@keyup.left="handleKeyupArrow()"
|
|
@keyup.right="handleKeyupArrow()"
|
|
>
|
|
<input
|
|
:type="isMultiSelect ? 'checkbox' : 'radio'"
|
|
:id="buttonID"
|
|
:name="groupName"
|
|
:value="value"
|
|
:aria-required="isRequired"
|
|
v-model="checkValue"
|
|
@change="handleInputChange()"
|
|
/>
|
|
<label
|
|
tabindex="-1"
|
|
:for="buttonID"
|
|
:aria-label="buttonLabel"
|
|
class="d-flex flex-column justify-content-center py-3 px-4"
|
|
@mouseup="triggerButton()"
|
|
>
|
|
<span
|
|
class="m-0"
|
|
:class="textPosition"
|
|
>
|
|
{{buttonLabel}}
|
|
</span>
|
|
<span
|
|
v-if="buttonLabelSubCopy"
|
|
class="m-0 small"
|
|
:class="textPosition"
|
|
>
|
|
{{ buttonLabelSubCopy }}
|
|
</span>
|
|
<span
|
|
v-if="screenReaderOnlyText"
|
|
class="sr-only"
|
|
>
|
|
{{ screenReaderOnlyText }}
|
|
</span>
|
|
<loader
|
|
v-if="isLoaderDisplayed && selectingInitiatesLoad"
|
|
:class="[loaderColor, loaderPosition]"
|
|
/>
|
|
</label>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { useField } from "vee-validate";
|
|
import loader from "@/ux-components/loader/loader";
|
|
import { queryStrings } from "@/constants/query-strings";
|
|
|
|
export default {
|
|
name: "listButtonHorizontal",
|
|
props: {
|
|
isMultiSelect: Boolean,
|
|
groupName: String,
|
|
buttonID: String,
|
|
buttonLabel: String,
|
|
buttonLabelSubCopy: String,
|
|
screenReaderOnlyText: String,
|
|
textPosition: String,
|
|
selectingInitiatesLoad: Boolean,
|
|
loaderColor: String,
|
|
loaderPosition: String,
|
|
isRequired: Boolean,
|
|
value: {
|
|
// Field initial value
|
|
type: String,
|
|
default: "",
|
|
},
|
|
validationRules: String,
|
|
selectedValues: [Array, String],
|
|
hasError: Boolean,
|
|
valueToLogType: String,
|
|
},
|
|
data() {
|
|
return {
|
|
isLoaderDisplayed: false,
|
|
checkValue: Boolean,
|
|
};
|
|
},
|
|
created() {
|
|
if (Array.isArray(this.selectedValues)) {
|
|
this.checkValue = this.isMultiSelect
|
|
? this.selectedValues.includes(this.value)
|
|
: this.selectedValues[0];
|
|
}
|
|
},
|
|
methods: {
|
|
displayLoader() {
|
|
this.isLoaderDisplayed = true;
|
|
},
|
|
handleInputChange() {
|
|
if(!this.selectingInitiatesLoad) {
|
|
this.handleCheckChange();
|
|
}
|
|
},
|
|
handleKeyupArrow() {
|
|
if (this.isMultiSelect) {
|
|
return; // Prevent arrow keys from doing anything if element is a checkbox
|
|
}
|
|
|
|
if(!this.selectingInitiatesLoad) {
|
|
this.handleCheckChange();
|
|
}
|
|
},
|
|
triggerButton() {
|
|
if(this.selectingInitiatesLoad) {
|
|
this.displayLoader();
|
|
this.handleCheckChange();
|
|
}
|
|
|
|
this.pushEventToGA(this.$route.query[queryStrings.FMG_PAGE], this.GaActions.CLICKED, this.value.toString(), true, this.valueToLogType);
|
|
},
|
|
handleCheckChange() {
|
|
const emitEvent = {
|
|
checkValue: this.checkValue, // only read on checkboxes, on handleCheckedChanged on button-question
|
|
value: this.value.toString(),
|
|
buttonId: this.buttonID && this.buttonID.toString(),
|
|
};
|
|
|
|
this.handleChange(this.value);
|
|
this.$emit("isCheckedChanged", emitEvent);
|
|
this.$emit("update:modelValue", emitEvent);
|
|
}
|
|
},
|
|
components: {
|
|
loader,
|
|
},
|
|
setup(props) {
|
|
const inputType = props.isMultiSelect ? "checkbox" : "radio";
|
|
|
|
const fieldOptions = {
|
|
type: inputType,
|
|
checkedValue: props.value,
|
|
potentialInitialValue: props.selectedValues,
|
|
};
|
|
|
|
// Set initialValue for validation setup if pre-selected
|
|
// NOTE: props.selectedValues could be an array of strings, or an array of integers...
|
|
if (props.selectedValues && (props.selectedValues.includes(props.value) || props.selectedValues.includes(parseInt(props.value)))) {
|
|
fieldOptions['initialValue'] = fieldOptions.potentialInitialValue;
|
|
}
|
|
|
|
const {
|
|
handleChange,
|
|
errors,
|
|
} = useField(props.groupName, props.validationRules, fieldOptions);
|
|
|
|
return {
|
|
handleChange,
|
|
errors,
|
|
fieldOptions, // only need to expose this for unit test purposes
|
|
};
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.list-button-horizontal {
|
|
input[type="radio"],
|
|
input[type="checkbox"] {
|
|
position: absolute;
|
|
height: 0;
|
|
opacity: 0;
|
|
width: 0;
|
|
|
|
&:focus-visible + label {
|
|
box-shadow: 0 0 0 2.5px $blue;
|
|
z-index: 2;
|
|
}
|
|
&:focus + label {
|
|
box-shadow: 0 0 0 2.5px $blue;
|
|
z-index: 3;
|
|
}
|
|
&:checked + label {
|
|
background: $blue-100;
|
|
box-shadow: 0 0 0 1px $blue;
|
|
outline: none;
|
|
z-index: 2;
|
|
}
|
|
&:checked:focus + label {
|
|
box-shadow: 0 0 0 2.5px $blue;
|
|
}
|
|
&:checked + label p:first-child {
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
label {
|
|
outline: none;
|
|
position: relative;
|
|
background: $white;
|
|
transition: all 150ms linear;
|
|
border: 1px solid $gray-500;
|
|
border-radius: 0;
|
|
width: 100%;
|
|
color: $gray-600;
|
|
&:hover {
|
|
@include media-breakpoint-up(sm) {
|
|
box-shadow: 0 0 0 4px $blue-300;
|
|
cursor: pointer;
|
|
z-index: 4 !important;
|
|
}
|
|
}
|
|
+ p {
|
|
display: none;
|
|
}
|
|
span {
|
|
font-size: .875rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.col {
|
|
&:first-of-type {
|
|
.list-button-horizontal {
|
|
label {
|
|
border-bottom-left-radius: 0.5rem;
|
|
border-top-left-radius: 0.5rem;
|
|
z-index: 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
&:last-of-type {
|
|
.list-button-horizontal {
|
|
label {
|
|
border-bottom-right-radius: 0.5rem;
|
|
border-top-right-radius: 0.5rem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|