Merge remote-tracking branch 'origin/CSR-186-strip-logic-from-components' into feature/CSR-186_add-logic-to-question-vue

This commit is contained in:
Max 2022-01-18 09:11:25 -05:00
commit 8a45b752fe
3 changed files with 22 additions and 335 deletions

View file

@ -1,123 +1,17 @@
<!-- See the component-test.vue page for example implementation -->
<template>
<!-- IMPORTANT: Refrain from using more than 4 horizontal buttons on desktop, 3 on mobile. -->
<div
v-if="isMultiSelect"
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"
@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"
:class="isFirstOrLastButton"
>
<span class="m-0" :class="[this.textPosition]">{{buttonID}}</span>
<span v-if="screenReaderOnlyText" class="sr-only">{{screenReaderOnlyText}}</span>
</label>
</div>
<div
v-else
class="col list-group list-button-horizontal d-flex flex-column mb-2"
>
<input
type="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"
:class="isFirstOrLastButton"
>
<span class="m-0" :class="textPosition">{{buttonID}}</span>
<span v-if="screenReaderOnlyText" class="sr-only">{{screenReaderOnlyText}}</span>
<loader v-if="isLoaderDisplayed" :style="{width: `${sizeInRem}rem`, height: `${sizeInRem}rem`}" :class="[loaderColor, loaderPosition]" />
<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>
</label>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useField } from 'vee-validate';
import loader from "@/ux-components/loader/loader";
export default {
name: "listButtonHorizontal",
props: {
isMultiSelect: Boolean, /* Defines use as checkbox */
groupName: String, /* Required, unique for each button GROUP */
buttonID: String, /* Required, unique for each button. Used for button id, label and <label for> */
screenReaderOnlyText: String, /* Optional, copy to be read by screenreader */
textPosition: String, /* Optional, use Bootstrap classes: text-start, text-center, text-end. Default (empty) is text-start */
loaderEnabled: Boolean, /* Optional, need to include this for loader to be used at all */
loaderColor: String, /* Specify color of loader/spinner. Options are blue, red, green, white, black. Default is blue */
loaderPosition: String, /* Specify horizontal position of loader/spinner. Options are center, right, left */
sizeInRem: Number, /* Specify size of loader/spinner in rem. Example: 1.5 (equals 24px (16x1.5)) */
totalInGroup: Number, /* Required, total number of buttons in group. Used to tell first and last in group to apply border radius. */
positionInGroup: Number, /* Required, position of button in group. Example, 1,2,3 */
isRequired: Boolean,
value: { // Field initial value
type: String,
default: ""
}
},
data() {
return {
isLoaderDisplayed: false,
};
},
methods: {
displayLoader() {
this.isLoaderDisplayed = true;
},
handleClick(value) {
this.loaderEnabled && this.displayLoader();
this.handleChange(value);
}
},
components: {
loader,
},
computed: {
isFirstOrLastButton() {
let className = "";
if (this.positionInGroup == this.totalInGroup) {
className = "last-item";
} else if (this.positionInGroup == 1) {
className = "first-item";
}
return className;
},
},
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,
};
},
name: "listButtonHorizontal"
};
</script>

View file

@ -1,103 +1,17 @@
<template>
<!-- See the component-test.vue page for example implementation -->
<div v-if="isMultiSelect" 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"
@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="[this.textPosition]">{{buttonID}}</span>
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="[this.textPosition]">{{buttonLabelSubCopy}}</span>
<span v-if="screenReaderOnlyText" class="sr-only">{{screenReaderOnlyText}}</span>
</label>
<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>
</label>
</div>
<div v-else class="list-group list-button d-flex flex-column w-100 mb-2">
<input
type="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="[this.textPosition]">{{buttonID}}</span>
<span v-if="buttonLabelSubCopy" class="m-0 small" :class="[this.textPosition]">{{buttonLabelSubCopy}}</span>
<span v-if="screenReaderOnlyText" class="sr-only">{{screenReaderOnlyText}}</span>
<loader v-if="isLoaderDisplayed" :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, /* Defines use as checkbox */
groupName: String, /* Required, unique for each button GROUP */
buttonID: [Number,String], /* Required, unique for each button. Used for button id, label and <label for> */
isRequired: Boolean, /* Optional, default is false */
screenReaderOnlyText: String, /* Optional, copy to be read by screenreader */
buttonLabelSubCopy: String, /* Optional, used for multi-line buttons */
textPosition: String, /* Optional, use Bootstrap classes: text-start, text-center, text-end. Default (empty) is text-start */
loaderEnabled: Boolean, /* Optional, need to include this for loader to be used at all */
loaderColor: String, /* Specify color of loader/spinner. Options are blue, red, green, white, black. Default is blue */
loaderPosition: String, /* Specify horizontal position of loader/spinner. Options are center, right, left */
sizeInRem: [Number,String], /* Specify size of loader/spinner in rem. Example: 1.5 (equals 24px (16x1.5)) */
value: { // Field initial value
type: String,
default: ""
}
},
data() {
return {
isLoaderDisplayed: false,
};
},
methods: {
displayLoader() {
this.isLoaderDisplayed = true;
},
handleClick(value) {
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>
@ -111,4 +25,4 @@ export default {
}
}
}
</style>
</style>

View file

@ -1,143 +1,22 @@
<template>
<!-- Heavily documented below -->
<div v-if="isMultiSelect" 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"
@click="handleChange(value)"
:data-focus-target="groupName"
/>
<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}`)" v-bind:alt="altText" />
<p class="small m-0 order-3">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy" class="fs-7 m-0 order-4">{{buttonLabelSubCopy}}</p>
</label>
</div>
<div v-else-if="isRadio" class="list-card w-100 rounded-3 d-flex align-items-center h-100">
<input
type="radio"
:id="buttonID"
:name="groupName"
:value="buttonID"
:aria-required="isRequired"
@click="handleChange(value)"
:data-focus-target="groupName"
/>
<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}`)" v-bind:alt="altText" />
<p class="small mt-2 mb-0 order-2">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy" class="fs-7 m-0 order-3">{{buttonLabelSubCopy}}</p>
</label>
</div>
<div v-else-if="isMultiSelectHorizontal" class="list-card horizontal w-100 rounded-3 d-flex align-items-center h-100">
<input
type="checkbox"
:id="buttonID"
:name="groupName"
:value="buttonLabel"
:aria-required="isRequired"
@click="handleChange(value)"
:data-focus-target="groupName"
/>
<label
:for="buttonID"
class="d-flex flex-row w-100 align-items-center py-r ps-3 pe-8 px-2 h-100"
tabindex="-1"
:class="{'checkboxTop': buttonLabelSubCopy}"
>
<img class="ms-auto order-3" v-bind:src="require(`@/assets/img/icons/${buttonImage}`)" v-bind:alt="altText" />
<div class="order-2">
<p class="m-0 small">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy" class="m-0 fs-7">{{buttonLabelSubCopy}}</p>
</div>
</label>
</div>
<div v-else-if="isRadioHorizontal" class="list-card horizontal w-100 rounded-3 d-flex align-items-center h-100">
<input
type="radio"
:id="buttonID"
:name="groupName"
:value="buttonLabel"
:aria-required="isRequired"
@click="handleChange(value)"
:data-focus-target="groupName"
/>
<label
:for="buttonID"
class="d-flex flex-row w-100 align-items-center py-r ps-3 pe-8 px-2 h-100"
tabindex="-1"
:class="{'checkboxTop': buttonLabelSubCopy}"
>
<img class="ms-auto order-3" v-bind:src="require(`@/assets/img/icons/${buttonImage}`)" v-bind:alt="altText" />
<div class="order-2">
<p class="m-0 small">{{buttonLabel}}</p>
<p v-if="buttonLabelSubCopy" class="m-0 fs-7">{{buttonLabelSubCopy}}</p>
</div>
<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>
</label>
</div>
</template>
<script>
import { toRefs } from 'vue';
import { useField } from 'vee-validate';
export default {
name: "listCard",
props: {
//Must choose one of the following four options
isMultiSelect: Boolean, //Defines use as checkbox
isRadio: Boolean, //Defines use as radio button
isMultiSelectHorizontal: Boolean, //Defines use as horizontal checkbox
isRadioHorizontal: Boolean, //Defines use as horizontal radio button
//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: ""
}
},
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,
};
},
buttonImage: String
}
};
</script>