Merge pull request #177 from Safelite/feature/CSR-267

Feature/csr 267
This commit is contained in:
max-dempsey 2022-02-01 09:07:34 -05:00 committed by GitHub
commit 5a3850948a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 490 additions and 128 deletions

View file

@ -19,3 +19,67 @@ describe("buttonQuestion.vue", () => {
expect(wrapper.props().modelValue).toBe("2020"); expect(wrapper.props().modelValue).toBe("2020");
}); });
}); });
describe("buttonQuestion.vue", () => {
it("Should show overflow classes on fieldset if isOverflowScrollable is true", async () => {
// Act
const wrapper = shallowMount(buttonQuestion);
await wrapper.setProps({
isOverflowScrollable: true,
});
// Assert
const fieldSet = wrapper.find('fieldset');
expect(fieldSet.classes()).toContain("overflow-scroll");
});
});
describe("buttonQuestion.vue", () => {
it("Should show appropriate classes for button type", async () => {
// Act
const wrapper = shallowMount(buttonQuestion);
await wrapper.setProps({
buttonType: "listCard",
});
// Assert
const Div = wrapper.find('fieldset div');
expect(Div.classes()).toContain("row");
});
});
describe("buttonQuestion.vue", () => {
it("Should trigger event modelValue change on select", async () => {
// Act
const wrapper = shallowMount(buttonQuestion);
await wrapper.setData({
modelValueAnswers: ["Windshield"],
chosenAnswer: "Windshield"
});
wrapper.setValue({ answer: wrapper.vm.chosenAnswer });
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{answer: "Windshield"}]);
});
});
describe("buttonQuestion.vue", () => {
it("Should trigger event modelValue change with an array of string values on select if checked is true and multiple options are chosen", async () => {
// Act
const wrapper = shallowMount(buttonQuestion);
await wrapper.setData({
modelValueAnswers: ["Windshield", "BackDoor"]
});
wrapper.vm.isItemChecked(true);
// Assert
expect(typeof wrapper.emitted()["update:modelValue"][0]).toEqual('object');
});
});
describe("buttonQuestion.vue", () => {
it("Should not trigger event modelValue change on select if checked is false", async () => {
// Act
const wrapper = shallowMount(buttonQuestion);
wrapper.vm.isItemChecked(false);
// Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([undefined]);
});
});

View file

@ -4,40 +4,37 @@
<span class="text-center fs-6 fw-bold w-100">{{ questionText }}</span> <span class="text-center fs-6 fw-bold w-100">{{ questionText }}</span>
</div> </div>
<div class="w-100 d-flex justify-content-center"> <div class="w-100 d-flex justify-content-center">
<fieldset <fieldset class="w-100" :class="getFieldSetClasses" role="radiogroup" :aria-labelledby="groupName ? groupName + '-radio-group' : ''">
class="w-100" <legend class="sr-only">{{groupName}}</legend>
:class="getFieldSetClasses" <div :class="getComponentWrapperClasses">
role="radiogroup" <component
:aria-labelledby="groupName ? groupName + '-radio-group' : ''" :is="buttonType"
> v-for="answer in answers"
<legend class="sr-only">{{ groupName }}</legend> :key="answer.Name ? answer.Name : answer"
<div :class="getComponentWrapperClasses"> @mouseup="chooseAnswer(answer.Name ? answer.Name : answer)"
<component @keyup.space="chooseAnswer(answer.Name ? answer.Name : answer)"
:is="buttonType" @isChecked="isItemChecked"
v-for="answer in answers" :buttonID="answer.Name ? answer.Name : answer"
:key="answer" :value="answer.Name ? answer.Name : answer"
@mouseup="chooseAnswer(answer.Name ? answer.Name : answer)" :buttonLabel="answer.Text ? answer.Text : answer"
@keyup.space="chooseAnswer(answer.Name ? answer.Name : answer)" :buttonLabelSubCopy="answer.SubText"
:buttonID="answer.Name ? answer.Name : answer" :textPosition="textPosition"
:buttonLabel="answer.Text ? answer.Text : answer" :isMultiSelect="isMultiSelect"
:buttonLabelSubCopy="answer.SubText" :groupName="groupName"
:textPosition="textPosition" :loaderEnabled="loaderEnabled"
:isMultiSelect="isMultiSelect" :loaderColor="loaderColor"
:groupName="groupName" :loaderPosition="loaderPosition"
:loaderEnabled="loaderEnabled" :sizeInRem="sizeInRem"
:loaderColor="loaderColor" :isWide="isWide"
:loaderPosition="loaderPosition" :isRequired="isRequired"
:sizeInRem="sizeInRem" :buttonImage="answer.AnswerImageUrl"
:isWide="isWide" :buttonImageId="answer.ImageId"
:isRequired="isRequired" :altText="answer.Name ? answer.Name : answer"
:buttonImage="answer.AnswerImageUrl" screenReaderOnlyText="(opens new window)"
:buttonImageId="answer.ImageId" :colLength="this.answers.length < 3 ? '' : '-4'"
:altText="answer.Name ? answer.Name : answer" data-test="button"
screenReaderOnlyText="(opens new window)" />
:value="modelValue" </div>
data-test="button"
/>
</div>
</fieldset> </fieldset>
</div> </div>
</div> </div>
@ -79,7 +76,7 @@ export default {
isRequired: Boolean, isRequired: Boolean,
isOverflowScrollable: Boolean, isOverflowScrollable: Boolean,
isWide: Boolean, isWide: Boolean,
modelValue: String, modelValue: [Array, String],
}, },
computed: { computed: {
getFieldSetClasses() { getFieldSetClasses() {
@ -96,16 +93,34 @@ export default {
case "listButtonHorizontal": case "listButtonHorizontal":
classes = "d-flex flex-row p-0"; classes = "d-flex flex-row p-0";
break; break;
case "listCard": case 'listCard':
classes = "row g-2"; classes = 'row justify-content-center g-2'
break; break;
} }
return classes; return classes;
}, },
}, },
data(){
return {
modelValueAnswers: [],
chosenAnswer: String
}
},
created(){
if(Array.isArray(this.answers) && this.answers.length === 1) {
const onlyAnswer = typeof(this.answers[0]) === 'object' ? this.answers[0].Name : this.answers[0];
this.$emit("update:modelValue", onlyAnswer);
}
},
methods: { methods: {
chooseAnswer(answer) { chooseAnswer(answer) {
this.$emit("update:modelValue", answer); this.chosenAnswer = answer;
},
isItemChecked(val) {
// Add or remove item to array of data to emit
val ? this.modelValueAnswers.push(this.chosenAnswer) : this.modelValueAnswers.splice(this.modelValueAnswers.indexOf(this.chosenAnswer), 1);
this.$emit("update:modelValue", this.modelValueAnswers.length ? this.modelValueAnswers : undefined);
}, },
}, },
components: { components: {

View file

@ -0,0 +1,76 @@
import { shallowMount } from "@vue/test-utils";
import replaceOptionsQuestion from "@/layouts/vehicle-damage/replace-options-question/replace-options-question";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
jest.mock("@/store", () => { return {}; }, {virtual: true});
describe("replace-options-question.vue", () => {
test("Selected damage option is emitted upon selection.", async () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: ["Windshield"] });
const damageToSelect = ["Backseat"];
//Act
wrapper.setValue({ modelValue: damageToSelect });
await wrapper.vm.$nextTick();
//Assert
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([{modelValue: ["Backseat"]}]);
});
});
describe("replace-options-question.vue", () => {
test("Answers to display filtered by data from api.", async () => {
//Arrange
const { wrapper, cmsContent, replaceOptions } = setupMocks({ dataFromStoreApi: ["Windshield", "FrontDoor"]});
//Act
replaceOptionsQuestion.methods.initializeComponent.call(wrapper.vm, cmsContent, replaceOptions, "car-group");
//Assert
expect(wrapper.vm.answersToDisplay).toStrictEqual([ { Name: 'car-Windshield' }, { Name: 'car-FrontDoor' } ])
});
});
function setupMocks({
modelValueProp = ["Windshield"],
isAvailale = true,
isMultiSelect = false,
filterByVehicleCategory = false,
groupName = "damageQuestion",
cmsQuestionText = "CMS text goes here",
cmsAnswers = [{Name: "car-Windshield"}, {Name: "car-BackDoor"}, {Name: "car-FrontDoor"}],
dataFromStoreApi = [],
}) {
//Mock store
store.dispatch = jest.fn(() => dataFromStoreApi);
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
const mountOptions = getMountOptions({
store: {
dispatch: store.dispatch,
getters: store.getters,
},
});
//Mock props
mountOptions.propsData = {
modelValue: modelValueProp,
isAvailable: isAvailale,
isMultiSelect: isMultiSelect,
filterByVehicleCategory: filterByVehicleCategory
};
const wrapper = shallowMount(replaceOptionsQuestion, mountOptions);
//Mock CMS content
const cmsContent = {
groupName: groupName,
QuestionText: cmsQuestionText,
Answers: cmsAnswers,
};
const replaceOptions = dataFromStoreApi;
return { wrapper, cmsContent, replaceOptions };
}

View file

@ -0,0 +1,77 @@
<template>
<transition name="fade">
<div class="replace-options-question">
<buttonQuestion
v-if="isAvailable && answersToDisplay.length > 1"
:questionText="questionText"
:isMultiSelect="isMultiSelect"
:answers="answersToDisplay"
:groupName="groupName"
buttonType="listCard"
v-model="modelValue"
/>
</div>
</transition>
</template>
<script>
import buttonQuestion from "@/common-components/button-question/button-question";
import store from "@/store";
export default ({
name: "replaceOptionsQuestion",
data(){
return {
questionText: String,
answersFromCms: Array,
replaceOptions: Array,
groupName: String,
}
},
props: {
isMultiSelect: Boolean,
isAvailable: Boolean,
filterByVehicleCategory: Boolean,
modelValue: Array,
},
methods: {
initializeComponent(cmsContent, replaceOptions, groupName){
this.groupName = groupName;
this.questionText = cmsContent.QuestionText;
this.answersFromCms = cmsContent.Answers;
this.replaceOptions = replaceOptions;
}
},
computed: {
answersToDisplay(){
return Array.isArray(this.answersFromCms)
? this.answersFromCms.filter(ans =>
{
const name = ans.Name.split('-');
return this.filterByVehicleCategory ? name[0].toUpperCase() === store.getters.vehicle.category : name[0].toUpperCase() === store.getters.vehicle.category && this.replaceOptions.includes(name[1])
})
: [];
},
},
watch: {
modelValue(val) {
this.$emit("update:modelValue", val);
}
},
components: {
buttonQuestion,
}
})
</script>
<style lang="scss" scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View file

@ -3,6 +3,7 @@ import vehicleDamage from "@/layouts/vehicle-damage/vehicle-damage.vue";
import funnelHeader from "@/common-components/funnel-header/funnel-header"; import funnelHeader from "@/common-components/funnel-header/funnel-header";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import replaceOptionsQuestion from"@/layouts/vehicle-damage/replace-options-question/replace-options-question";
// Supporting Files // Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js"; import { settleAllPromises } from "@/helpers/layout-helper.js";
@ -144,7 +145,9 @@ function setupMocks({
baseMixin.methods.dispatchNonBlockingStoreAction = jest.fn(); baseMixin.methods.dispatchNonBlockingStoreAction = jest.fn();
baseMixin.methods.dispatchNonBlockingStoreAction.mockImplementation(() => { baseMixin.methods.dispatchNonBlockingStoreAction.mockImplementation(() => {
return Promise.resolve({ return Promise.resolve({
data: ["Front Window", "Back Window", "Side Window"], driverSideOptions: {
availableReplacementOptions: ["Front", "Back", "Side"],
}
}); });
}); });
const apiResponses = { const apiResponses = {
@ -159,7 +162,11 @@ function setupMocks({
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3", "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
}, },
}, },
damageOptions: ["Front Window", "Back Window", "Side Window"], damageOptions: {
driverSideOptions: {
availableReplacementOptions: ["Front", "Back", "Side"],
}
},
}; };
const apiPromise = Promise.resolve(apiResponses); const apiPromise = Promise.resolve(apiResponses);
@ -180,6 +187,11 @@ function setupMocks({
initializeComponent: jest.fn(), initializeComponent: jest.fn(),
}; };
const driverSideOptions = replaceOptionsQuestion
driverSideOptions.methods = {
initializeComponent: jest.fn(),
};
const mountOptions = getMountOptions(mountOptionsMockData); const mountOptions = getMountOptions(mountOptionsMockData);
const wrapper = shallowMount(vehicleDamage, mountOptions); const wrapper = shallowMount(vehicleDamage, mountOptions);
@ -197,5 +209,11 @@ function setupMocks({
funnelSubHeaderWrapper.vm.initializeComponent = funnelSubHeaderWrapper.vm.initializeComponent =
funnelSubHeader.methods.initializeComponent; funnelSubHeader.methods.initializeComponent;
const driverSideOptionsWrapper = wrapper.findComponent({
name: "replaceOptionsQuestion",
});
driverSideOptionsWrapper.vm.initializeComponent =
replaceOptionsQuestion.methods.initializeComponent;
return { wrapper, apiPromise }; return { wrapper, apiPromise };
} }

View file

@ -1,9 +1,12 @@
<template> <template>
<div class="container-fluid shadow rounded-3 p-0 position-relative"> <div class="container-fluid shadow rounded-3 p-2 position-relative">
<funnelHeader ref="funnelHeader" /> <funnelHeader ref="funnelHeader" />
<vehicleBanner ref="vehicleBanner" /> <vehicleBanner ref="vehicleBanner" />
<funnelSubHeader ref="funnelSubHeader" /> <funnelSubHeader
</div> ref="funnelSubHeader"
/>
<replaceOptionsQuestion ref="driverSideOptions" isAvailable isMultiSelect />
</div>
</template> </template>
<script> <script>
@ -11,6 +14,7 @@
import funnelHeader from "@/common-components/funnel-header/funnel-header"; import funnelHeader from "@/common-components/funnel-header/funnel-header";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import replaceOptionsQuestion from"@/layouts/vehicle-damage/replace-options-question/replace-options-question";
// Supporting files // Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
@ -54,7 +58,11 @@ export default {
vm.$refs.funnelSubHeader.initializeComponent( vm.$refs.funnelSubHeader.initializeComponent(
resultMap.cmsContent.FunnelSubHeaderWidget resultMap.cmsContent.FunnelSubHeaderWidget
); );
// use resultMap.damageOptions for damage options vm.$refs.driverSideOptions.initializeComponent(
resultMap.cmsContent.DriverSideReplaceOptionsQuestion, resultMap.damageOptions.driverSideOptions.availableReplacementOptions, 'DriverSideReplaceOptionsQuestion'
);
//console.log(resultMap) for damageOptions and cms content data
}); });
}, },
methods: { methods: {
@ -66,6 +74,7 @@ export default {
funnelHeader, funnelHeader,
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
replaceOptionsQuestion,
}, },
}; };
</script> </script>

View file

@ -28,6 +28,7 @@ export default {
props: { props: {
modelValue: String, modelValue: String,
}, },
emits: ['update:modelValue'],
components: { components: {
buttonQuestion, buttonQuestion,
}, },

View file

@ -3,7 +3,6 @@ const navigationScenarios = {
SELECTED_MODEL: "SELECTED_MODEL", SELECTED_MODEL: "SELECTED_MODEL",
SELECTED_MAKE: "SELECTED_MAKE", SELECTED_MAKE: "SELECTED_MAKE",
SELECTED_STYLE: "SELECTED_STYLE", SELECTED_STYLE: "SELECTED_STYLE",
VEHICLE_DAMAGE: "VEHICLE_DAMAGE",
CLICKED_BACK: "CLICKED_BACK", CLICKED_BACK: "CLICKED_BACK",
}; };

View file

@ -11,6 +11,7 @@
:value="buttonID" :value="buttonID"
:aria-required="isRequired" :aria-required="isRequired"
:data-focus-target="groupName" :data-focus-target="groupName"
v-model="modelValue"
/> />
<label <label
tabindex="-1" tabindex="-1"
@ -18,16 +19,25 @@
:aria-labelledby="buttonID" :aria-labelledby="buttonID"
class="d-flex flex-column justify-content-center py-3 px-4" class="d-flex flex-column justify-content-center py-3 px-4"
> >
<span class="m-0" :class="textPosition">{{ buttonLabel }}</span> <span
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="textPosition">{{ class="m-0"
buttonLabelSubCopy :class="textPosition"
}}</span> >
<span v-if="screenReaderOnlyText" class="sr-only">{{ {{buttonLabel}}
screenReaderOnlyText </span>
}}</span> <span
v-if="buttonLabelSubCopy"
class="m-0 small"
:class="textPosition"
>
{{buttonLabelSubCopy}}
</span>
<span v-if="screenReaderOnlyText" class="sr-only">
{{screenReaderOnlyText}}
</span>
<loader <loader
v-if="isLoaderDisplayed && !isMultiSelect" v-if="isLoaderDisplayed && !isMultiSelect"
:style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }" :style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}"
:class="[loaderColor, loaderPosition]" :class="[loaderColor, loaderPosition]"
/> />
</label> </label>
@ -59,6 +69,7 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
modelValue: false,
}, },
data() { data() {
return { return {
@ -76,6 +87,11 @@ export default {
this.handleChange(value); this.handleChange(value);
}, },
}, },
watch: {
modelValue(){
this.$emit('isChecked', this.modelValue);
}
},
components: { components: {
loader, loader,
}, },

View file

@ -11,20 +11,33 @@
:value="buttonID" :value="buttonID"
:aria-required="isRequired" :aria-required="isRequired"
:data-focus-target="groupName" :data-focus-target="groupName"
/> v-model="modelValue"
>
<label <label
tabindex="-1" tabindex="-1"
:for="buttonID" :for="buttonID"
:aria-labelledby="buttonID" :aria-labelledby="buttonID"
class="d-flex flex-column justify-content-center py-3 px-4" class="d-flex flex-column justify-content-center py-3 px-4"
> >
<span class="m-0" :class="textPosition">{{ buttonLabel }}</span> <span
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="textPosition">{{ class="m-0"
buttonLabelSubCopy :class="textPosition"
}}</span> >
<span v-if="screenReaderOnlyText" class="sr-only">{{ {{ buttonLabel }}
screenReaderOnlyText </span>
}}</span> <span
v-if="buttonLabelSubCopy"
class="m-0 small"
:class="textPosition"
>
{{ buttonLabelSubCopy }}
</span>
<span
v-if="screenReaderOnlyText"
class="sr-only"
>
{{ screenReaderOnlyText }}
</span>
<loader <loader
v-if="isLoaderDisplayed && !isMultiSelect" v-if="isLoaderDisplayed && !isMultiSelect"
:style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }" :style="{ width: `${sizeInRem}rem`, height: `${sizeInRem}rem` }"
@ -52,12 +65,13 @@ export default {
loaderEnabled: Boolean, loaderEnabled: Boolean,
loaderColor: String, loaderColor: String,
loaderPosition: String, loaderPosition: String,
sizeInRem: [Number, String], sizeInRem: [Number,String],
value: { value: {
// Field initial value // Field initial value
type: String, type: [String, Number],
default: "", default: "",
}, },
modelValue: false
}, },
data() { data() {
return { return {
@ -75,6 +89,11 @@ export default {
this.handleChange(value); this.handleChange(value);
}, },
}, },
watch: {
modelValue(){
this.$emit('isChecked', this.modelValue);
}
},
components: { components: {
loader, loader,
}, },

View file

@ -119,4 +119,67 @@ describe("list-card.vue", () => {
expect(input.attributes()["aria-required"]).toEqual("true"); expect(input.attributes()["aria-required"]).toEqual("true");
}); });
it("Should return flex row classes if isWide is true", async () => {
// Act
const wrapper = shallowMount(listCard, {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
buttonID: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: true,
buttonLabelSubCopy: ""
},
});
// Assert
const label = wrapper.find("label");
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-row", "py-r", "ps-3", "pe-8"]);
});
it("Should return flex row classes if isWide is true and checkboxTop if buttonLabelSubCopy is true", async () => {
// Act
const wrapper = shallowMount(listCard, {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
buttonID: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: true,
buttonLabelSubCopy: "Button Subcopy"
},
});
// Assert
const label = wrapper.find("label");
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-row", "py-r", "ps-3", "pe-8", "checkboxTop"]);
});
it("Should return flex column classes if isWide is false", async () => {
// Act
const wrapper = shallowMount(listCard, {
propsData: {
isRadioHorizontal: true,
buttonLabel: "Windshield",
buttonID: "List Card Checkbox",
groupID: "radio-demo-1",
groupName: "radio 1",
buttonImage: "windshield-damage.svg",
isRequired: true,
isWide: false,
},
});
// Assert
const label = wrapper.find("label");
expect(label.classes()).toEqual(["d-flex", "w-100", "align-items-center", "px-2", "h-100", "flex-column", "pt-4", "pb-2"]);
});
}); });

View file

@ -1,12 +1,10 @@
<template> <template>
<!-- Heavily documented below --> <!-- Heavily documented below -->
<div class="col"> <div :class="'col' + colLength">
<div <div class="list-card w-100 rounded-3 d-flex align-items-center h-100"
class="list-card w-100 rounded-3 d-flex align-items-center h-100" :class="isWide ? 'horizontal' : ''"
:class="isWide ? 'horizontal' : ''" @mouseup="handleChange(value)"
@mouseup="handleClick(value)" @keyup.space="handleChange(value)">
@keyup.space="handleClick(value)"
>
<input <input
:type="isMultiSelect ? 'checkbox' : 'radio'" :type="isMultiSelect ? 'checkbox' : 'radio'"
:id="buttonID" :id="buttonID"
@ -14,28 +12,28 @@
:value="buttonID" :value="buttonID"
:aria-required="isRequired" :aria-required="isRequired"
:data-focus-target="groupName" :data-focus-target="groupName"
/> v-model="modelValue"
/>
<label <label
:for="buttonID" :for="buttonID"
class="d-flex w-100 align-items-center px-2 h-100" class="d-flex w-100 align-items-center px-2 h-100"
:class="getLabelClasses" :class="getLabelClasses" tabindex="-1"
tabindex="-1"
> >
<img <img
:id="buttonImageId" :id="buttonImageId"
:class="!isWide ? 'order-1' : 'ms-auto order-3'" :class="!isWide ? 'order-1' : 'ms-auto order-3'"
v-bind:src="require(`@/assets/img/icons/${buttonImage}`)" :src="buttonImage"
:alt="altText" :alt="altText"
/> />
<p <p
v-if="!isWide" v-if="!isWide"
class="small order-3" class="small order-3"
:class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'" :class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'"
> >
{{ buttonLabel }} {{buttonLabel}}
</p> </p>
<p v-if="buttonLabelSubCopy && !isWide" class="fs-7 m-0 order-4"> <p v-if="buttonLabelSubCopy && !isWide" class="fs-7 m-0 order-4">
{{ buttonLabelSubCopy }} {{buttonLabelSubCopy}}
</p> </p>
<div v-if="isWide" class="order-2"> <div v-if="isWide" class="order-2">
<p class="m-0 small">{{ buttonLabel }}</p> <p class="m-0 small">{{ buttonLabel }}</p>
@ -72,6 +70,8 @@ export default {
type: String, type: String,
default: "", default: "",
}, },
colLength: String,
modelValue: false,
}, },
computed: { computed: {
getLabelClasses() { getLabelClasses() {
@ -86,6 +86,11 @@ export default {
} }
}, },
}, },
watch: {
modelValue(){
this.$emit('isChecked', this.modelValue);
}
},
setup(props) { setup(props) {
const { groupName, value } = toRefs(props); const { groupName, value } = toRefs(props);
const inputType = props.isMultiSelect ? "checkbox" : "radio"; const inputType = props.isMultiSelect ? "checkbox" : "radio";