Reworking button question

This commit is contained in:
Max 2022-01-19 15:48:38 -05:00
parent 8a45b752fe
commit e3b1272429
10 changed files with 405 additions and 45 deletions

120
package-lock.json generated
View file

@ -15,11 +15,13 @@
"core-js": "^3.6.5",
"http-status-codes": "^2.1.4",
"jest-junit": "^13.0.0",
"vee-validate": "^4.5.7",
"vue": "^3.0.0",
"vue-plugin-load-script": "^2.1.0",
"vue-router": "^4.0.11",
"vuex": "^4.0.2",
"vuex-persistedstate": "^4.1.0"
"vuex-persistedstate": "^4.1.0",
"yup": "^0.32.11"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
@ -1632,7 +1634,6 @@
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
@ -4166,6 +4167,11 @@
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
"dev": true
},
"node_modules/@types/lodash": {
"version": "4.14.178",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
"integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
},
"node_modules/@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
@ -16453,8 +16459,12 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
@ -16974,6 +16984,11 @@
"dev": true,
"optional": true
},
"node_modules/nanoclone": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
},
"node_modules/nanoid": {
"version": "3.1.30",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
@ -18974,6 +18989,11 @@
"node": ">= 6"
}
},
"node_modules/property-expr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
},
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -19352,8 +19372,7 @@
"node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"node_modules/regenerator-transform": {
"version": "0.14.5",
@ -22340,6 +22359,17 @@
"node": ">= 0.8"
}
},
"node_modules/vee-validate": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.5.7.tgz",
"integrity": "sha512-EcpvOikBP5LlRIKwULfwRDeyIaERuOJztZUPWRmSIeWpeQWD6hs9qQ8A3CmVVteqEohbUM07gV/ea8lPXCfCJQ==",
"dependencies": {
"@vue/devtools-api": "^6.0.0-beta.15"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vendors": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
@ -24319,6 +24349,28 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"node_modules/yup": {
"version": "0.32.11",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
"integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
"dependencies": {
"@babel/runtime": "^7.15.4",
"@types/lodash": "^4.14.175",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"nanoclone": "^0.2.1",
"property-expr": "^2.0.4",
"toposort": "^2.0.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/yup/node_modules/toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
}
},
"dependencies": {
@ -25421,7 +25473,6 @@
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
@ -27496,6 +27547,11 @@
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
"dev": true
},
"@types/lodash": {
"version": "4.14.178",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz",
"integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
},
"@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
@ -37445,8 +37501,12 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"lodash.debounce": {
"version": "4.0.8",
@ -37888,6 +37948,11 @@
"dev": true,
"optional": true
},
"nanoclone": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
},
"nanoid": {
"version": "3.1.30",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
@ -39538,6 +39603,11 @@
"sisteransi": "^1.0.5"
}
},
"property-expr": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -39856,8 +39926,7 @@
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"regenerator-transform": {
"version": "0.14.5",
@ -42300,6 +42369,14 @@
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
"dev": true
},
"vee-validate": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.5.7.tgz",
"integrity": "sha512-EcpvOikBP5LlRIKwULfwRDeyIaERuOJztZUPWRmSIeWpeQWD6hs9qQ8A3CmVVteqEohbUM07gV/ea8lPXCfCJQ==",
"requires": {
"@vue/devtools-api": "^6.0.0-beta.15"
}
},
"vendors": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
@ -43914,6 +43991,27 @@
"dev": true
}
}
},
"yup": {
"version": "0.32.11",
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
"integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
"requires": {
"@babel/runtime": "^7.15.4",
"@types/lodash": "^4.14.175",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"nanoclone": "^0.2.1",
"property-expr": "^2.0.4",
"toposort": "^2.0.2"
},
"dependencies": {
"toposort": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
"integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
}
}
}
}
}

View file

@ -1,27 +1,33 @@
<template>
<div class="button_question">
<div class="mt-6 mb-4 d-flex">
<div :class="isVehicleQuestion ? 'button_question' : ''">
<div v-if="questionText" class="mt-6 mb-4 d-flex">
<span class="text-center fs-6 fw-bold w-100">{{
questionText
}}</span>
</div>
<div class="w-100 d-flex justify-content-center">
<fieldset class="overflow-scroll position-absolute container-fluid w-100 pt-1 px-5 py-0" role="radiogroup">
<fieldset class="w-100" :class="isVehicleQuestion ? vehicleQuestionClasses : isHorizontal ? horizontalClasses : ''" role="radiogroup" :aria-labelledby="groupName ? groupName + '-radio-group' : ''">
<legend class="sr-only">{{groupName}}</legend>
<listButton v-for="answer in answers" :key="answer"
<component :is="buttonType" v-for="answer in answers" :key="answer"
:buttonID="answer"
@mouseup="chooseAnswer(answer)"
@keyup.space="chooseAnswer(answer)"
loaderColor="blue"
loaderPosition="right"
sizeInRem="1.5"
:loaderEnabled="loaderEnabled"
:loaderColor="loaderColor"
:loaderPosition="loaderPosition"
:sizeInRem="sizeInRem"
data-test="button"
:groupName="groupName"
textPosition="text-start"
:isRequired="true"
:textPosition="textPosition"
:value="modelValue"
screenReaderOnlyText="(opens new window)"
:isMultiSelect="isMultiSelect"
:ariaLabelBy="ariaLabelBy"
:isRequired="isRequired"
:buttonImage="buttonImage"
:buttonLabel="buttonLabel"
:altText="altText"
:buttonLabelSubCopy="buttonLabelSubCopy"
/>
</fieldset>
</div>
@ -30,14 +36,52 @@
<script>
import listButton from "@/ux-components/list-button/list-button";
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
import listCard from "@/ux-components/list-card/list-card";
export default {
name: "buttonQuestion",
props: {
buttonType: {
type: String,
default: 'listButton'
},
isMultiSelect: Boolean,
questionText: String,
answers: Array,
textPosition: {
type: String,
default: 'text-center'
},
loaderEnabled: Boolean,
loaderColor: {
type: String,
default: 'blue'
},
loaderPosition: {
type: String,
default: 'right'
},
sizeInRem: {
type: [String, Number],
default: 1.5
},
modelValue: String,
groupName: String
groupName: String,
ariaLabelBy: String,
isRequired: Boolean,
isVehicleQuestion: Boolean,
isHorizontal: Boolean,
buttonImage: String,
buttonLabel: String,
altText: String,
buttonLabelSubCopy: String,
},
data() {
return {
vehicleQuestionClasses: 'container-fluid overflow-scroll position-absolute px-5 pt-1 py-0',
horizontalClasses: 'd-flex flex-row p-0'
};
},
methods: {
chooseAnswer(answer) {
@ -46,6 +90,8 @@ export default {
},
components: {
listButton,
listButtonHorizontal,
listCard
},
};
</script>

View file

@ -167,7 +167,8 @@
<fieldset>
<legend class="sr-only">Horizontal Checkbox</legend>
<listCard
isMultiSelectHorizontal
isMultiSelect
isHorizontal
buttonImage="windshield-damage.svg"
buttonLabel="Windshield"
altText=""
@ -184,7 +185,8 @@
<fieldset>
<legend class="sr-only">Checkbox no Description</legend>
<listCard
isMultiSelectHorizontal
isMultiSelect
isHorizontal
buttonImage="side-window-damage-right-all.svg"
buttonLabel="Side Window"
altText=""
@ -201,7 +203,7 @@
<fieldset>
<legend class="sr-only">Horizontal Radio Button</legend>
<listCard
isRadioHorizontal
isHorizontal
buttonImage="back-glass-damage.svg"
buttonLabel="Rear Window"
altText=""
@ -218,7 +220,7 @@
<fieldset>
<legend class="sr-only">Radio Button no Description</legend>
<listCard
isRadioHorizontal
isHorizontal
buttonImage="windshield-damage.svg"
buttonLabel="Windshield"
altText=""
@ -754,6 +756,42 @@
/>
</div>
</div>
<div class="row my-4">
<div class="col">
<h4 class="m-0 p-2 bg-light rounded">Button Question</h4>
</div>
</div>
<buttonQuestion
:answers="checkboxAnswers"
:isMultiSelect="true"
ariaLabelBy="checkbox"
groupName="checkbox-list"
questionText="List Button as checkbox"
/>
<buttonQuestion
:answers="radioAnswers"
ariaLabelBy="radio"
groupName="radio-list"
questionText="List Button as radio"
/>
<buttonQuestion
:answers="horizontalCheckboxAnswers"
buttonType="listButtonHorizontal"
:isMultiSelect="true"
:isHorizontal="true"
ariaLabelBy="checkbox"
groupName="checkbox-list-horizontal"
questionText="List Button Horizontal as checkbox"
/>
<buttonQuestion
:answers="horizontalRadioAnswers"
buttonType="listButtonHorizontal"
:isHorizontal="true"
ariaLabelBy="radio"
groupName="radio-list-horizontal"
questionText="List Button Horizontal as radio"
sizeInRem="1"
/>
</div>
</template>
@ -768,6 +806,7 @@ import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelHeader from "@/common-components/funnel-header/funnel-header";
import listButtonHorizontal from "@/ux-components/list-button-horizontal/list-button-horizontal";
import checkbox from "@/ux-components/checkbox/checkbox";
import buttonQuestion from "@/common-components/button-question/button-question"
export default {
name: "App",
components: {
@ -781,10 +820,15 @@ export default {
listButtonHorizontal,
checkbox,
funnelHeader,
buttonQuestion
},
data() {
return {
years: [2023, 2022, 2021, 2020],
checkboxAnswers: ['Checkbox Answer 1', 'Checkbox Answer 2', 'Checkbox Answer 3'],
radioAnswers: ['Radio Answer 1', 'Radio Answer 2', 'Radio Answer 3'],
horizontalCheckboxAnswers: ['HCB Answer 1', 'HCB Answer 2', 'HCB Answer 3'],
horizontalRadioAnswers: ['HR Answer 1', 'HR Answer 2', 'HR Answer 3'],
};
},
};

View file

@ -3,6 +3,9 @@
:questionText="questionText"
:answers="makes"
groupName="Choose Vehicle Make"
textPosition="text-start"
:isVehicleQuestion="true"
:loaderEnabled="true"
v-model="modelValue"
/>
</template>

View file

@ -3,6 +3,9 @@
:questionText="questionText"
:answers="models"
groupName="Choose Vehicle Model"
textPosition="text-start"
:isVehicleQuestion="true"
:loaderEnabled="true"
v-model="modelValue"
/>
</template>

View file

@ -3,6 +3,9 @@
:questionText="questionText"
:answers="styles"
groupName="Choose Vehicle Style"
textPosition="text-start"
:isVehicleQuestion="true"
:loaderEnabled="true"
v-model="modelValue"
/>
</template>

View file

@ -3,6 +3,9 @@
:questionText="questionText"
:answers="years"
groupName="Choose Vehicle Year"
:isVehicleQuestion="true"
textPosition="text-start"
:loaderEnabled="true"
v-model="modelValue"
/>
</template>

View file

@ -1,17 +1,70 @@
<template>
<div class="list-group list-button-horizontal d-flex flex-column w-100 mb-2">
<input type="checkbox" id="buttonID" name="groupName" value="buttonID" aria-required="isRequired"/>
<label tabindex="1" for="buttonID" aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
<span class="m-0">Button ID</span>
<span class="sr-only">Screenreader Text</span>
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" @click="handleClick(value)" :data-focus-target="groupName" />
<label tabindex="-1" :for="buttonID" :aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
<span class="m-0" :class="textPosition">{{buttonID}}</span>
<span v-if="screenReaderOnlyText" class="sr-only">{{screenReaderOnlyText}}</span>
<loader v-if="isLoaderDisplayed && !isMultiSelect" :style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}" :class="[loaderColor, loaderPosition]" />
</label>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useField } from 'vee-validate';
import loader from "@/ux-components/loader/loader";
export default {
name: "listButtonHorizontal"
name: "listButtonHorizontal",
props: {
isMultiSelect: Boolean,
groupName: String,
buttonID: String,
screenReaderOnlyText: String,
textPosition: String,
loaderEnabled: Boolean,
loaderColor: String,
loaderPosition: String,
sizeInRem: [Number, String],
isRequired: Boolean,
value: { // Field initial value
type: String,
default: ""
}
},
data() {
return {
isLoaderDisplayed: false,
};
},
methods: {
displayLoader() {
this.isLoaderDisplayed = true;
},
handleClick(value) {
if(this.loaderEnabled){
this.displayLoader();
}
this.handleChange(value);
}
},
components: {
loader,
},
setup(props) {
const { groupName, value } = toRefs(props);
const inputType = props.isMultiSelect ? "checkbox" : "radio";
const { checked, handleChange, errorMessage } = useField(groupName, undefined, {
type: inputType,
checkedValue: value
});
return {
checked,
handleChange,
errorMessage,
};
},
};
</script>
@ -50,11 +103,15 @@ export default {
+ p {
display: none;
}
&.first-item {
}
&:first-of-type {
label {
border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem;
}
&.last-item {
}
&:last-of-type {
label {
border-bottom-right-radius: 0.5rem;
border-top-right-radius: 0.5rem;
}

View file

@ -1,17 +1,70 @@
<template>
<div class="list-group list-button d-flex flex-column w-100 mb-2">
<input type="checkbox" id="buttonID" name="groupName" value="buttonID" aria-required="isRequired">
<label tabindex="1" for="buttonID" aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
<span class="m-0">Button ID</span>
<span class="m-0 small">Button Label Subcopy</span>
<span class="sr-only">Screenreader Text</span>
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" @click="handleClick(value)" :data-focus-target="groupName">
<label tabindex="-1" :for="buttonID" :aria-labelledby="buttonID" class="d-flex flex-column justify-content-center py-3 px-4">
<span class="m-0" :class="textPosition">{{ buttonID }}</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 && !isMultiSelect" :style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}" :class="[this.loaderColor, this.loaderPosition]" />
</label>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useField } from 'vee-validate';
import loader from "@/ux-components/loader/loader";
export default {
name: "listButton",
props: {
isMultiSelect: Boolean,
groupName: String,
buttonID: [Number,String],
isRequired: Boolean,
textPosition: String,
buttonLabelSubCopy: String,
screenReaderOnlyText: String,
loaderEnabled: Boolean,
loaderColor: String,
loaderPosition: String,
sizeInRem: [Number,String],
value: { // Field initial value
type: String,
default: ""
}
},
data() {
return {
isLoaderDisplayed: false,
};
},
methods: {
displayLoader() {
this.isLoaderDisplayed = true;
},
handleClick(value) {
if(this.loaderEnabled){
this.displayLoader();
}
this.handleChange(value);
}
},
components: {
loader,
},
setup(props) {
const { groupName, value } = toRefs(props);
const inputType = props.isMultiSelect ? "checkbox" : "radio";
const { checked, handleChange, errorMessage } = useField(groupName, undefined, {
type: inputType,
checkedValue: value
});
return {
checked,
handleChange,
errorMessage,
};
},
};
</script>

View file

@ -1,22 +1,72 @@
<template>
<!-- Heavily documented below -->
<div class="list-card w-100 rounded-3 d-flex align-items-center h-100">
<input type="checkbox" id="buttonID" name="groupName" value="buttonLabel" aria-required="isRequired"/>
<label for="buttonID" class="d-flex flex-column w-100 align-items-center pt-4 pb-2 px-2 h-100" tabindex="1">
<img class="order-1" v-bind:src="require(`@/assets/img/icons/${buttonImage}`)" alt="altText" />
<p class="small m-0 order-3">Button Label</p>
<p class="fs-7 m-0 order-4">Button Label Subcopy</p>
<div class="list-card w-100 rounded-3 d-flex align-items-center h-100" :class="isHorizontal ? 'horizontal' : ''">
<input :type="isMultiSelect ? 'checkbox' : 'radio'" :id="buttonID" :name="groupName" :value="buttonID" :aria-required="isRequired" @click="handleClick(value)" :data-focus-target="groupName" />
<label :for="buttonID" class="d-flex w-100 align-items-center px-2 h-100" :class="[isHorizontal ? rowClasses : columnClasses,isHorizontal && buttonLabelSubCopy ? 'checkboxTop' : '']" tabindex="-1">
<img :class="!isHorizontal ? 'order-1' : 'ms-auto order-3'" v-bind:src="require(`@/assets/img/icons/${buttonImage}`)" :alt="altText" />
<p v-if="!isHorizontal" class="small order-3" :class="isMultiSelect ? 'm-0' : 'mt-2 mb-0'">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy && !isHorizontal" class="fs-7 m-0 order-4">{{buttonLabelSubCopy}}</p>
<div v-if="isHorizontal" class="order-2">
<p class="m-0 small">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy" class="m-0 fs-7">{{buttonLabelSubCopy}}</p>
</div>
</label>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useField } from 'vee-validate';
export default {
name: "listCard",
props: {
buttonImage: String
}
//Must choose one of the following four options
isMultiSelect: Boolean, //Defines use as checkbox
isHorizontal: Boolean,
//end must choose
buttonImage: String,//Required: File name of image
buttonLabel: String,//Required: Label text
isRequired: Boolean, //Required: is aria-required required or not?
altText: String,//Leave empty. Screen readers read the buttonLabel text. If alt has content, it will repeat unnecessarily.
buttonID: String,//Required: Unique
groupName: String,//Rquired: Unique
buttonLabelSubCopy: String,//Optional: sub text
value: { // Field initial value
type: String,
default: ""
}
},
data(){
return {
columnClasses: "flex-column pt-4 pb-2",
rowClasses: "flex-row py-r ps-3 pe-8"
}
},
setup(props) {
const { groupName, value } = toRefs(props);
const inputType = () => { // TODO: refactor props to streamline this logic for the whole component
if (props.isMultiSelect) {
return "checkbox";
} else if (props.isRadio) {
return "radio";
} else if (props.isMultiSelectHorizontal) {
return "checkbox";
} else if (props.isRadioHorizontal) {
return "radio";
}
}
props.isMultiSelect ? "checkbox" : "radio";
const { checked, handleChange } = useField(groupName, undefined, {
type: inputType(),
checkedValue: value,
});
return {
checked,
handleChange,
};
},
};
</script>