Merge branch 'develop' into feature/INSR-7754

This commit is contained in:
Katie Kroell 2026-01-08 10:19:21 -05:00
commit 3d64506791
28 changed files with 442 additions and 653 deletions

View file

@ -0,0 +1,8 @@
const buttonSizes = Object.freeze({
xs: 'xs',
sm: 'sm',
md: 'md',
lg: 'lg'
});
export default buttonSizes;

View file

@ -0,0 +1,9 @@
const buttonVariants = Object.freeze({
primary: 'primary',
secondary: 'secondary',
success: 'success',
link: 'link',
navigation: 'navigation'
});
export default buttonVariants;

View file

@ -81,7 +81,6 @@ describe('modal.vue', () => {
validate: mockValidate(true) validate: mockValidate(true)
}); });
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -89,7 +88,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Act // Act
const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' }); const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' });
@ -112,8 +110,6 @@ describe('modal.vue', () => {
meta: mockMeta(fakeMeta), meta: mockMeta(fakeMeta),
validate: mockValidate(false) validate: mockValidate(false)
}); });
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -121,7 +117,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Act // Act
const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' }); const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' });
@ -144,8 +139,6 @@ describe('modal.vue', () => {
meta: mockMeta(fakeMeta), meta: mockMeta(fakeMeta),
validate: mockValidate(true) validate: mockValidate(true)
}); });
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -153,7 +146,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Assert // Assert
expect(wrapper.vm.isFooterButtonDisabled).toBe(true); expect(wrapper.vm.isFooterButtonDisabled).toBe(true);
@ -172,8 +164,6 @@ describe('modal.vue', () => {
meta: mockMeta(fakeMeta), meta: mockMeta(fakeMeta),
validate: mockValidate(true) validate: mockValidate(true)
}); });
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -181,7 +171,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Assert // Assert
expect(wrapper.vm.isFooterButtonDisabled).toBe(true); expect(wrapper.vm.isFooterButtonDisabled).toBe(true);
@ -202,8 +191,6 @@ describe('modal.vue', () => {
}); });
const showMock = jest.spyOn(Modal.prototype, 'show'); const showMock = jest.spyOn(Modal.prototype, 'show');
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -211,7 +198,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Act // Act
wrapper.vm.openModal(); wrapper.vm.openModal();
@ -234,8 +220,6 @@ describe('modal.vue', () => {
validate: mockValidate(true) validate: mockValidate(true)
}); });
const hideMock = jest.spyOn(Modal.prototype, 'hide'); const hideMock = jest.spyOn(Modal.prototype, 'hide');
const resetButtonStyle = jest.fn();
const wrapper = shallowMount(modal, { const wrapper = shallowMount(modal, {
props: { props: {
footerButtonText, footerButtonText,
@ -243,7 +227,6 @@ describe('modal.vue', () => {
}, },
attachTo: document.body attachTo: document.body
}); });
wrapper.vm.resetButtonStyle = resetButtonStyle;
// Act // Act
wrapper.vm.openModal(); wrapper.vm.openModal();

View file

@ -11,7 +11,11 @@
'hidden.bs.modal': onModalClosed, 'hidden.bs.modal': onModalClosed,
'shown.bs.modal': onModalOpened 'shown.bs.modal': onModalOpened
}"> }">
<div class="modal-dialog modal-dialog-centered"> <div class="modal-dialog"
:class="{
'modal-dialog-edge': modalPosition === 'edge',
'modal-dialog-centered': modalPosition === 'center'
}">
<div <div
class="modal-content" class="modal-content"
role="dialog" role="dialog"
@ -34,30 +38,18 @@
<slot></slot> <slot></slot>
</div> </div>
<div class="modal-footer px-5 py-4"> <div class="modal-footer px-5 py-4">
<modalButtonMain <buttonMain
v-if="useDefaultButton"
id="modalbtn" id="modalbtn"
ref="modalButtonMain" ref="modalButtonMain"
isPrimary :variant="buttonVariant"
class="w-100" class="w-100"
:buttonText="footerButtonText" :buttonText="footerButtonText"
pushToGA
:class="[ :class="[
(isButtonDisabled || isFooterButtonDisabled) && (isButtonDisabled || isFooterButtonDisabled) &&
'form-test-invalid', 'form-test-invalid'
additionalClassesString
]" ]"
@clickEvent="validateAndEmit" /> @clickEvent="validateAndEmit" />
<button
v-if="!useDefaultButton"
class="w-100 btn d-flex align-items-center justify-content-center delay"
:class="[
(isButtonDisabled || isFooterButtonDisabled) &&
'form-test-invalid',
additionalClassesString
]"
@click="validateAndEmit">
<span class="m-0">{{ footerButtonText }}</span>
</button>
</div> </div>
</div> </div>
</div> </div>
@ -65,7 +57,7 @@
</template> </template>
<script> <script>
import modalButtonMain from '@/ux-components/modal-button-main/modal-button-main.vue'; import ButtonMain from '@/ux-components/button-main/button-main.vue';
import { Modal } from 'bootstrap'; import { Modal } from 'bootstrap';
import { useForm } from 'vee-validate'; import { useForm } from 'vee-validate';
@ -73,7 +65,7 @@ export default {
// eslint-disable-next-line vue/multi-word-component-names // eslint-disable-next-line vue/multi-word-component-names
name: 'modal', name: 'modal',
components: { components: {
modalButtonMain ButtonMain
}, },
props: { props: {
modalId: String, modalId: String,
@ -86,13 +78,13 @@ export default {
type: Function type: Function
}, },
isButtonDisabled: Boolean, isButtonDisabled: Boolean,
useDefaultButton: { buttonVariant: {
type: Boolean,
default: true
},
additionalClassesString: {
type: String, type: String,
default: null default: 'success'
},
modalPosition: {
type: String,
default: 'edge'
} }
}, },
emits: ['footer-button-event', 'isModalOpened'], emits: ['footer-button-event', 'isModalOpened'],
@ -131,8 +123,6 @@ export default {
const validationResult = await this.validate(); const validationResult = await this.validate();
if (validationResult.valid) { if (validationResult.valid) {
this.$emit('footer-button-event'); this.$emit('footer-button-event');
} else {
this.resetButtonStyle();
} }
}, },
async onKeyDown(e) { async onKeyDown(e) {
@ -141,14 +131,10 @@ export default {
this.$refs.modalButtonMain.clicked(); this.$refs.modalButtonMain.clicked();
document.getElementById(this.modalId)?.focus(); document.getElementById(this.modalId)?.focus();
}, },
resetButtonStyle() {
this.$refs.modalButtonMain?.resetButtonStyle();
},
onModalOpened() { onModalOpened() {
this.onModalOpenedCallback?.(); this.onModalOpenedCallback?.();
}, },
onModalClosed() { onModalClosed() {
this.resetButtonStyle();
this.onModalClosedCallback?.(); this.onModalClosedCallback?.();
}, },
openModal() { openModal() {
@ -214,24 +200,10 @@ export default {
} }
&.modal-component { &.modal-component {
.modal-dialog { .modal-dialog {
display: flex;
max-width: 47.9375rem; max-width: 47.9375rem;
margin: 0 auto;
@include media-breakpoint-up(md) {
width: 23.5rem;
position: absolute;
top: 0;
right: 0;
transform: translate(100%, 0);
}
.modal-content { .modal-content {
margin: 1.5rem auto 0 auto; margin: 1.5rem auto 0 auto;
box-shadow: 0px 1rem 3rem -1rem rgba(0, 0, 0, 0.25);
border-radius: 1.5rem 1.5rem 0 0;
@include media-breakpoint-up(md) {
box-shadow: none;
border-radius: 0;
margin: 0 auto;
}
.modal-body { .modal-body {
.col { .col {
max-width: 100%; max-width: 100%;
@ -257,11 +229,40 @@ export default {
} }
} }
} }
&.modal-dialog-centered { &.modal-dialog-edge {
align-items: flex-end;
min-height: 100%; min-height: 100%;
margin: 0 auto;
align-items: flex-end;
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
align-items: inherit; align-items: inherit;
width: 23.5rem;
position: absolute;
top: 0;
right: 0;
transform: translate(100%);
}
.modal-content {
box-shadow: 0px 1rem 3rem -1rem rgba(0, 0, 0, 0.25);
border-radius: 1.5rem 1.5rem 0 0;
@include media-breakpoint-up(md) {
box-shadow: none;
border-radius: 0;
margin: 0 auto;
}
}
}
&.modal-dialog-centered {
.modal-content {
box-shadow: 0px 1rem 3rem -1rem rgba(0, 0, 0, 0.25);
border-radius: 1.5rem;
overflow: auto;
}
}
}
&.show .modal-dialog {
&.modal-dialog-edge {
@include media-breakpoint-up(md) {
transform: translateY(0);
} }
} }
} }
@ -273,9 +274,6 @@ export default {
} }
} }
} }
&.show .modal-dialog {
transform: translateY(0);
}
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
&.fade { &.fade {
transition: opacity 0.25s linear; transition: opacity 0.25s linear;

View file

@ -1,7 +1,10 @@
<template> <template>
<div <div
class="textarea-question" class="textarea-question"
:class="(errors && errors.length) ? 'has-error' : ''"> :class="[
(errors && errors.length) ? 'has-error' : '',
(meta?.valid && meta?.touched && !(errors && errors.length)) ? 'has-success' : ''
]">
<label <label
:for="inputId" :for="inputId"
class="form-label"> class="form-label">
@ -84,7 +87,7 @@ export default {
initialValue initialValue
}; };
const { errorMessage, handleChange, handleBlur, validate, errors, resetField } = const { errorMessage, handleChange, handleBlur, validate, errors, resetField, meta } =
useField(props.inputId, props.validationRules, fieldOptions); useField(props.inputId, props.validationRules, fieldOptions);
return { return {
@ -93,7 +96,8 @@ export default {
handleBlur, handleBlur,
validate, validate,
errors, errors,
resetField resetField,
meta
}; };
}, },
computed: { computed: {

View file

@ -1,7 +1,10 @@
<template> <template>
<div <div
class="textbox-question" class="textbox-question"
:class="(errors && errors.length) || hasError ? 'has-error' : ''"> :class="[
((errors && errors.length) || hasError) ? 'has-error' : '',
(meta?.valid && meta?.touched && !((errors && errors.length) || hasError)) ? 'has-success' : ''
]">
<label <label
v-if="displayQuestionText" v-if="displayQuestionText"
:for="inputId" :for="inputId"
@ -271,8 +274,8 @@ input::-webkit-date-and-time-value {
} }
.form-test-error span { .form-test-error span {
color: #d4281c; color: #d4281c;
font-size: 0.875rem; font-size: 1rem;
font-weight: 500; font-weight: 400;
} }
.input-wrapper { .input-wrapper {

View file

@ -5,8 +5,7 @@
class="modal fade modal-component" class="modal fade modal-component"
tabindex="-1" tabindex="-1"
aria-labelledby="ModalComponentLabel" aria-labelledby="ModalComponentLabel"
aria-hidden="true" aria-hidden="true">
v-on="{ 'hidden.bs.modal': resetButtonStyle }">
<div class="modal-dialog modal-dialog-centered"> <div class="modal-dialog modal-dialog-centered">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -34,8 +33,7 @@
<buttonMain <buttonMain
ref="buttonMain" ref="buttonMain"
class="w-100" class="w-100"
isPrimary variant="success"
suppressLoader
:buttonText="ModalSelectButtonText" :buttonText="ModalSelectButtonText"
data-bs-dismiss="modal" data-bs-dismiss="modal"
@clickEvent="buttonClick" /> @clickEvent="buttonClick" />
@ -70,9 +68,6 @@ export default {
} }
}, },
methods: { methods: {
resetButtonStyle() {
this.$refs.buttonMain.resetButtonStyle();
}
} }
}; };
</script> </script>

View file

@ -7,19 +7,19 @@
ref="continueModal" ref="continueModal"
:headerText="modalHeaderText" :headerText="modalHeaderText"
:footerButtonText="modalFooterText" :footerButtonText="modalFooterText"
buttonVariant="primary"
@isModalOpened="setModalStatus" @isModalOpened="setModalStatus"
@footerButtonEvent="startNewReferral"> @footerButtonEvent="startNewReferral">
<p class="mb-2 subheader-text text-center"> <p class="mb-2 subheader-text text-center">
{{ modalSubHeaderText }} {{ modalSubHeaderText }}
</p> </p>
<button <buttonMain
id="btnContinueReferral" id="btnContinueReferral"
type="button" variant="success"
class="btn btn-white-blue continue-referral class="mt-2 w-100"
align-items-center justify-content-center d-inline-flex mt-2 py-3 px-4 delay w-100" :buttonText="modalBodyText"
@click="continueReferral"> @click-event="continueReferral">
{{ modalBodyText }} </buttonMain>
</button>
</modal> </modal>
</div> </div>
</transition> </transition>
@ -28,10 +28,12 @@
<script> <script>
import modal from '@/digital-components/modal/modal.vue'; import modal from '@/digital-components/modal/modal.vue';
import { getISSCookie } from '@/helpers/cookie-helper.js'; import { getISSCookie } from '@/helpers/cookie-helper.js';
import ButtonMain from '@/ux-components/button-main/button-main.vue';
export default { export default {
name: 'continue-modal', name: 'continue-modal',
components: { components: {
ButtonMain,
modal modal
}, },
emits: ['continue-previous-referral', 'start-new-referral'], emits: ['continue-previous-referral', 'start-new-referral'],
@ -80,16 +82,5 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.btn-white-blue {
border-radius: 0.5rem;
border-color: $blue;
color: $blue;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.5rem;
background-color: #ffffff;
--bs-btn-focus-shadow-rgb: 218, 72, 62;
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
</style> </style>

View file

@ -16,7 +16,7 @@
<buttonMain <buttonMain
v-if="!isForwardButtonHidden" v-if="!isForwardButtonHidden"
ref="buttonMain" ref="buttonMain"
isPrimary variant="navigation"
:buttonText="buttonText" :buttonText="buttonText"
:class=" :class="
(disableForwardAction || isForwardActionDisabled) && (disableForwardAction || isForwardActionDisabled) &&
@ -136,7 +136,7 @@ export default {
width: auto; width: auto;
justify-content: flex-end; justify-content: flex-end;
} }
.btn-primary { .btn-navigation {
width: auto; width: auto;
} }
a { a {
@ -149,7 +149,7 @@ export default {
overflow-x: visible; // needed to fix hidden footer on some iphones overflow-x: visible; // needed to fix hidden footer on some iphones
} }
div.flex-column { div.flex-column {
.btn-primary { .btn-navigation {
width: 100%; width: 100%;
justify-content: center; justify-content: center;
} }

View file

@ -8,20 +8,17 @@
ref="cancelClaimModal" ref="cancelClaimModal"
:headerText="modalHeaderText" :headerText="modalHeaderText"
:footerButtonText="modalFooterText" :footerButtonText="modalFooterText"
additionalClassesString="navigation-link" buttonVariant="link"
:useDefaultButton="false"
@isModalOpened="setModalStatus" @isModalOpened="setModalStatus"
@footerButtonEvent="cancelClaimConfirmation"> @footerButtonEvent="cancelClaimConfirmation">
<div v-html="modalBodyText"></div> <div v-html="modalBodyText"></div>
<button <buttonMain
id="btnContinueReferral" id="btnContinueReferral"
type="button" variant="success"
:aria-disabled="false" :buttonText="modalBodyText2"
class="btn btn-primary btn-override class="mt-4 w-100"
align-items-center justify-content-center d-inline-flex mt-4 py-3 px-4 delay w-100" @clickEvent="returnToClaim">
@click="returnToClaim"> </buttonMain>
{{ modalBodyText2 }}
</button>
</modal> </modal>
</div> </div>
</transition> </transition>
@ -29,10 +26,12 @@
<script> <script>
import modal from '@/digital-components/modal/modal.vue'; import modal from '@/digital-components/modal/modal.vue';
import ButtonMain from '@/ux-components/button-main/button-main.vue';
export default { export default {
name: 'cancel-claim-modal', name: 'cancel-claim-modal',
components: { components: {
ButtonMain,
modal modal
}, },
emits: ['cancel-claim-confirmation', 'return-to-claim'], emits: ['cancel-claim-confirmation', 'return-to-claim'],
@ -76,19 +75,5 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.btn {
&.btn-primary {
position: relative;
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
border: none;
border-radius: $border-radius-lg;
color: $white;
justify-content: center;
font-weight: $font-weight-bold;
letter-spacing: inherit;
@media (hover: hover) {
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
}
}
}
</style> </style>

View file

@ -2,7 +2,6 @@
<buttonQuestion <buttonQuestion
ref="policyVehiclesQuestion" ref="policyVehiclesQuestion"
v-model="selectedVehicleVin" v-model="selectedVehicleVin"
:questionText="questionText"
groupName="policyVehiclesQuestionOption" groupName="policyVehiclesQuestionOption"
buttonTypeString="listButton" buttonTypeString="listButton"
isOverflowScrollable isOverflowScrollable
@ -25,9 +24,6 @@ export default ({
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
questionText() {
return this.getCmsContent('PolicyVehiclesQuestion', 'QuestionText');
},
answers() { answers() {
const policyVehiclesAnswerFromCMS = this.getCmsContent('PolicyVehiclesQuestion', 'Answers'); const policyVehiclesAnswerFromCMS = this.getCmsContent('PolicyVehiclesQuestion', 'Answers');
const combinedVehicles = [...this.vehicles, ...policyVehiclesAnswerFromCMS]; const combinedVehicles = [...this.vehicles, ...policyVehiclesAnswerFromCMS];

View file

@ -13,11 +13,20 @@
<div class="iss-heritage-container-width"> <div class="iss-heritage-container-width">
<div class="policy-vehicles-container iss-heritage-content-container-width"> <div class="policy-vehicles-container iss-heritage-content-container-width">
<div class="select-car-form rounded text-center"> <div class="select-car-form rounded text-center">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<policyVehiclesQuestion <policyVehiclesQuestion
v-model="selectedVehicleVin" v-model="selectedVehicleVin"
cmsWidgetName="PolicyVehiclesQuestion" cmsWidgetName="PolicyVehiclesQuestion"
:vehicles="VehiclesForQuestions" :vehicles="VehiclesForQuestions"
:validationRules="rules.optionRequired" /> :validationRules="rules.optionRequired"
class="mb-2"/>
<buttonMain
:variant="buttonVariants.primary"
buttonText="Add another vehicle"
class="w-100"
@clickEvent="addAnotherVehicle" />
<alert <alert
v-if="displayNoServiceAlert" v-if="displayNoServiceAlert"
ref="AlertNoService" ref="AlertNoService"
@ -59,10 +68,15 @@ import {
} from '@/helpers/policy-vehicle-helper'; } from '@/helpers/policy-vehicle-helper';
import coverageType from '@/constants/coverage-type'; import coverageType from '@/constants/coverage-type';
import alert from '@/ux-components/alert/alert.vue'; import alert from '@/ux-components/alert/alert.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import buttonVariants from '@/constants/button-variants';
export default { export default {
name: 'policy-vehicles', name: 'policy-vehicles',
components: { components: {
buttonMain,
siteSubHeader,
siteHeader, siteHeader,
siteFooter, siteFooter,
policyVehiclesQuestion, policyVehiclesQuestion,
@ -90,7 +104,8 @@ export default {
rules: { rules: {
optionRequired: globalRules.OPTION_REQUIRED optionRequired: globalRules.OPTION_REQUIRED
}, },
displayNoServiceAlert: false displayNoServiceAlert: false,
buttonVariants
}; };
}, },
computed: { computed: {
@ -274,6 +289,10 @@ export default {
data: responseError.data data: responseError.data
}; };
} }
},
async addAnotherVehicle() {
this.selectedVehicleVin = vehicleSelectionOptions.VEHICLE_NOT_LISTED;
await this.forwardButtonAction();
} }
} }
}; };

View file

@ -101,7 +101,6 @@ export default {
this.$refs[this.ModalName]?.closeModal(); this.$refs[this.ModalName]?.closeModal();
this.$emit('buttonClick'); this.$emit('buttonClick');
} else { } else {
this.$refs[this.ModalName]?.resetButtonStyle();
this.showError = true; this.showError = true;
} }
} }

View file

@ -260,9 +260,6 @@ export default {
this.displayInvalidZipAlert = false; this.displayInvalidZipAlert = false;
this.internalModel = deepClone(this.modelValue); this.internalModel = deepClone(this.modelValue);
}, },
resetModalButtonStyle() {
this.modal.resetButtonStyle();
},
async setMobileLocation() { async setMobileLocation() {
if ( if (
this.internalModel.addressQuestions.zipCode this.internalModel.addressQuestions.zipCode
@ -273,7 +270,6 @@ export default {
if (!zipCodeData.isValid) { if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
this.resetModalButtonStyle();
} else { } else {
// retrieve mobile fee part // retrieve mobile fee part
const serviceZipCode = this.internalModel.addressQuestions.zipCode; const serviceZipCode = this.internalModel.addressQuestions.zipCode;

View file

@ -10,8 +10,7 @@ jest.mock('@/digital-components/textbox-question/textbox-question', () => ({
jest.mock('@/digital-components/modal/modal', () => ({ jest.mock('@/digital-components/modal/modal', () => ({
methods: { methods: {
closeModal: jest.fn(), closeModal: jest.fn()
resetButtonStyle: jest.fn()
} }
})); }));

View file

@ -15,6 +15,7 @@
:onModalOpenedCallback="onModalOpened" :onModalOpenedCallback="onModalOpened"
:onModalClosedCallback="onModalClosed" :onModalClosedCallback="onModalClosed"
:footerButtonText="modalFooterText" :footerButtonText="modalFooterText"
:modalPosition="'center'"
@footerButtonEvent="setZipCode"> @footerButtonEvent="setZipCode">
<serviceZipQuestion <serviceZipQuestion
ref="serviceZipCodeQuestion" ref="serviceZipCodeQuestion"
@ -127,9 +128,6 @@ export default {
closeModal() { closeModal() {
this.$refs[this.modalName].closeModal(); this.$refs[this.modalName].closeModal();
}, },
resetModalButtonStyle() {
this.$refs[this.modalName].resetButtonStyle();
},
onInputIdAssigned(inputId) { onInputIdAssigned(inputId) {
this.serviceZipCodeTextInputId = inputId; this.serviceZipCodeTextInputId = inputId;
}, },
@ -150,7 +148,6 @@ export default {
if (!zipCodeData.isValid) { if (!zipCodeData.isValid) {
this.displayInvalidZipAlert = true; this.displayInvalidZipAlert = true;
this.focusOnZipInput(); this.focusOnZipInput();
this.resetModalButtonStyle();
} else { } else {
this.internalModel.state = zipCodeData.state; this.internalModel.state = zipCodeData.state;
const serviceZipCode = this.internalModel.zipCode; const serviceZipCode = this.internalModel.zipCode;

View file

@ -169,7 +169,7 @@ describe('tpa-submit', () => {
// Assert // Assert
expect(mainButton.exists()).toBeTruthy(); expect(mainButton.exists()).toBeTruthy();
expect(mainButton.props().isPrimary).toBe(true); expect(mainButton.props().variant).toBe('success');
expect(mainButton.classes()).toContain('w-100'); expect(mainButton.classes()).toContain('w-100');
expect(mainButton.classes()).toContain('mb-5'); expect(mainButton.classes()).toContain('mb-5');
}); });

View file

@ -32,7 +32,7 @@
class="mb-4 small text-color--darker-gray" /> class="mb-4 small text-color--darker-gray" />
<buttonMain <buttonMain
ref="buttonMainOne" ref="buttonMainOne"
isPrimary variant="success"
:buttonText="forwardButtonText" :buttonText="forwardButtonText"
class="w-100 mb-5" class="w-100 mb-5"
@clickEvent="forwardButtonAction" /> @clickEvent="forwardButtonAction" />

View file

@ -86,52 +86,14 @@
.btn-link { .btn-link {
color: $link; color: $link;
} }
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
} }
&.modal-open { .btn {
.modal { &.btn-override {
.modal-body { @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true);
.btn { @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true);
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
}
.modal-footer {
.btn:not(.navigation-link) {
background: $button-color;
color: $button-text-color;
}
}
}
} }
}
} }
// End Amica // End Amica
@ -171,52 +133,14 @@
a.new-window-link { a.new-window-link {
color: $link; color: $link;
} }
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
} }
&.modal-open { .btn {
.modal { &.btn-override {
.modal-body { @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true);
.btn { @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true);
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
}
.modal-footer {
.btn:not(.navigation-link) {
background: $button-color;
color: $button-text-color;
}
}
}
} }
}
} }
// End Nationwide // End Nationwide
@ -256,52 +180,14 @@
a.new-window-link { a.new-window-link {
color: $link; color: $link;
} }
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
} }
&.modal-open { .btn {
.modal { &.btn-override {
.modal-body { @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true);
.btn { @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true);
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
}
.modal-footer {
.btn:not(.navigation-link) {
background: $button-color;
color: $button-text-color;
}
}
}
} }
}
} }
// End Country Financial // End Country Financial
@ -341,52 +227,14 @@
a.new-window-link { a.new-window-link {
color: $link; color: $link;
} }
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
} }
&.modal-open { .btn {
.modal { &.btn-override {
.modal-body { @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true);
.btn { @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true);
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
}
.modal-footer {
.btn:not(.navigation-link) {
background: $button-color;
color: $button-text-color;
}
}
}
} }
}
} }
// End Travelers // End Travelers

View file

@ -183,3 +183,49 @@ body {
:root { :root {
--iss-loader-color: white; --iss-loader-color: white;
} }
//Button Styles
$heritage-btn-border-radius: 1.40625rem; // 22.5px
$heritage-btn-height: 2.8125rem; // 45px
$heritage-btn-width: 9.0625rem; // 145px
.btn {
position: relative;
--bs-btn-font-weight: 600;
min-height: $heritage-btn-height;
min-width: $heritage-btn-width;
letter-spacing: inherit;
line-height: .94;
@include heritage-btn-variant('primary', $white, $heritage-blue-primary, transparent, true);
@include heritage-btn-variant('success', $white, $green, transparent, true);
@include heritage-btn-variant('navigation', $white, $green, transparent, true);
@include heritage-btn-variant('secondary', $white, $heritage-blue-secondary, transparent, true);
@include heritage-btn-link('link', $blue, transparent, $heritage-blue-secondary);
@include heritage-btn-size('lg', 0.625rem, 1.25rem);
@include heritage-btn-size('md', 7px, 15px);
@include heritage-btn-size('sm', 3px, 6px);
@include heritage-btn-size('xs', 1px, 5px);
&.btn-link {
--bs-btn-padding-x: 0px;
text-decoration: none;
&:hover,
&:focus {
text-decoration: underline;
}
&.disabled,
&[disabled],
fieldset[disabled] {
text-decoration: none;
}
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
}
}

View file

@ -8,3 +8,53 @@
@mixin box-shadow-hover($color) { @mixin box-shadow-hover($color) {
box-shadow: 0 0 0 4px $color; box-shadow: 0 0 0 4px $color;
} }
@mixin heritage-btn-box-shadow($color) {
box-shadow:0 0 0 3px $white,0 0 0 5.5px $color
}
@mixin heritage-btn-variant($name, $color, $background, $border-color, $box-shadow) {
&.btn-#{$name} {
@include button-variant($background,
$border-color,
$color,
#{darken($background, 10%)},
$border-color,
$color,
$background,
$border-color,
$color,
$background,
$border-color,
$color
);
@if($box-shadow) {
&:focus, &:active, &:active:focus {
@include heritage-btn-box-shadow($background);
}
}
}
&.btn-outline-#{$name} {
@include button-outline-variant($background,
$color,
$background,
$color,
$background
);
}
}
@mixin heritage-btn-size($size, $y-padding, $x-padding) {
&.btn-#{$size} {
@include button-size($y-padding, $x-padding, $font-size-base, $heritage-btn-border-radius);
}
}
@mixin heritage-btn-link($name, $color, $background, $hover-color) {
&.btn-#{$name} {
--bs-btn-color: #{$color};
--bs-btn-bg: #{$background};
--bs-btn-hover-color: #{$hover-color};
--bs-btn-active-color: #{$hover-color};
}
}

View file

@ -5,7 +5,7 @@
&.list-button, &.list-button,
&.list-button-horizontal, &.list-button-horizontal,
&.list-card { &.list-card {
&:not(.selected) { &:not(.selected):not(.no-hover) {
position: relative; position: relative;
z-index: 5; z-index: 5;
@include box-shadow-hover($blue-300); @include box-shadow-hover($blue-300);

View file

@ -217,3 +217,7 @@ $letter-spacing-primary: 0.03em;
// Borders // Borders
$border-input: 1px solid rgba(179, 180, 181); $border-input: 1px solid rgba(179, 180, 181);
$border-input-focus: 2.5px solid $blue; $border-input-focus: 2.5px solid $blue;
//Heritage
$heritage-blue-primary: #0070D1;
$heritage-blue-secondary: #167cac;

View file

@ -1,6 +1,8 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js'; import { getMountOptions } from '@/helpers/unit-test-helper.js';
import buttonMain from '@/ux-components/button-main/button-main.vue'; import buttonMain from '@/ux-components/button-main/button-main.vue';
import buttonVariants from '@/constants/button-variants';
import buttonSizes from '@/constants/button-sizes';
/** @ignore */ /** @ignore */
function setupMocks(mountOptionsMockData = {}) { function setupMocks(mountOptionsMockData = {}) {
@ -12,13 +14,75 @@ function setupMocks(mountOptionsMockData = {}) {
} }
describe('buttonMain.vue', () => { describe('buttonMain.vue', () => {
it('Should return btn-primary class', async () => { describe.each([...Object.keys(buttonVariants)])('Button Variants', (variant) => {
test(`Should return btn-${variant} class`, () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
variant
}
})
);
// Assert
const button = wrapper.find('button');
// Expect
expect(button.attributes('class')).toContain(`btn-${variant}`);
});
});
describe.each([...Object.keys(buttonVariants)])('Button Outline Variants', (variant) => {
test(`Should return btn-outline-${variant} class`, () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
variant,
isOutline: true
}
})
);
// Assert
const button = wrapper.find('button');
// Expect
expect(button.attributes('class')).toContain(`btn-outline-${variant}`);
});
});
describe.each([...Object.keys(buttonSizes)])('Button Sizes', (size) => {
test(`Should return btn-${size} class`, () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
size
}
})
);
// Assert
const button = wrapper.find('button');
// Expect
expect(button.attributes('class')).toContain(`btn-${size}`);
});
});
it('Should return button text', async () => {
// Act // Act
const buttonText = 'Test Text';
const wrapper = shallowMount( const wrapper = shallowMount(
buttonMain, buttonMain,
setupMocks({ setupMocks({
propsData: { propsData: {
isPrimary: true buttonText
} }
}) })
); );
@ -27,10 +91,10 @@ describe('buttonMain.vue', () => {
const button = wrapper.find('button'); const button = wrapper.find('button');
// Expect // Expect
expect(button.attributes('class')).toContain('btn-primary'); expect(button.text()).toContain(buttonText);
}); });
it('Should return aria-disabled state', async () => { it('Should return disabled state', async () => {
// Act // Act
const wrapper = shallowMount( const wrapper = shallowMount(
buttonMain, buttonMain,
@ -47,4 +111,85 @@ describe('buttonMain.vue', () => {
// Expect // Expect
expect(button.attributes()['aria-disabled']).toEqual('true'); expect(button.attributes()['aria-disabled']).toEqual('true');
}); });
it('Should emit click-event', async () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
isDisabled: false
}
})
);
// Assert
const button = wrapper.find('button');
await button.trigger('click');
// Expect
expect(wrapper.emitted('click-event').length).toBe(1);
});
it('Should not emit click-event when disabled', async () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
isDisabled: true
}
})
);
// Assert
const button = wrapper.find('button');
await button.trigger('click');
// Expect
expect(wrapper.emitted('click-event')).toBeUndefined();
});
it('Should emit GA event when clicked', async () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
pushToGA: true
}
})
);
const spy = jest.spyOn(wrapper.vm, 'pushEventToGA');
// Assert
const button = wrapper.find('button');
await button.trigger('click');
// Expect
expect(spy).toHaveBeenCalled();
});
it('Should not emit GA event when clicked', async () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
pushToGA: false
}
})
);
const spy = jest.spyOn(wrapper.vm, 'pushEventToGA');
// Assert
const button = wrapper.find('button');
await button.trigger('click');
// Expect
expect(spy).not.toHaveBeenCalled();
});
}); });

View file

@ -1,31 +1,50 @@
<template> <template>
<button <button
:aria-disabled="isDisabled" :aria-disabled="isDisabled"
class="btn d-flex btn-override align-items-center justify-content-center py-3 px-4 delay" class="btn d-flex align-items-center justify-content-center delay"
:class="[ :class="[getVariant, `btn-${size}`, canOverride ? 'btn-override' : '']"
isPrimary ? 'btn-primary' : 'btn-secondary',
isFloat ? 'float-end' : '',
]"
@click="clicked"> @click="clicked">
<span class="m-0">{{ buttonText }}</span> <span class="m-0">{{ buttonText }}</span>
</button> </button>
</template> </template>
<script> <script>
import buttonVariants from '@/constants/button-variants';
import buttonSizes from '@/constants/button-sizes';
export default { export default {
name: 'button-main', name: 'button-main',
props: { props: {
isPrimary: Boolean, variant: { type: String, default: 'primary', validator: (val) => Object.keys(buttonVariants).includes(val) },
size: { type: String, default: 'md', validator: (val) => Object.keys(buttonSizes).includes(val) },
buttonText: String, buttonText: String,
isDisabled: Boolean, isDisabled: Boolean,
loaderPosition: String, isOutline: Boolean,
isFloat: Boolean, pushToGA: Boolean,
suppressLoader: Boolean canOverride: { type: Boolean, required: false, default: true }
}, },
emits: ['click-event'], emits: ['click-event'],
computed: {
getVariant() {
if (this.isOutline) {
return `btn-outline-${this.variant}`;
}
return `btn-${this.variant}`;
}
},
methods: { methods: {
clicked() { clicked() {
if (!this.isDisabled) { if (!this.isDisabled) {
if (this.pushToGA) {
this.pushEventToGA(
this.$route.query[this.queryStrings.ISS_PAGE],
this.GaActions.CLICKED,
this.buttonText,
true
);
}
this.$emit('click-event'); this.$emit('click-event');
} }
} }
@ -34,86 +53,5 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$border-radius-heritage: 1.40625rem; // 22.5px
$button-height-heritage: 2.8125rem; // 45px
$button-width-heritage: 9.0625rem; // 145px
.btn {
&.btn-primary {
position: relative;
background: #0c7e47;
padding-left: 2rem;
padding-right: 2rem;
min-height: $button-height-heritage;
min-width: $button-width-heritage;
border: none;
border-radius: $border-radius-heritage;
color: $white;
justify-content: center;
font-weight: 600;
letter-spacing: inherit;
&:focus {
// Keyboard focus for accessibility
outline: none;
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #0c7e47;
}
&:hover {
// Keyboard focus for accessibility
color: #fff;
background-color: #084f2d;
border-color: #042f1a;
}
&:active {
outline: none;
background-color: #0c7e47;
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #0c7e47;
}
&:disabled {
background: red;
color: $gray-600 !important;
border: none;
border-radius: $border-radius-heritage;
cursor: pointer;
pointer-events: all;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
}
}
&.btn-secondary {
position: relative;
background: transparent;
border: 1px solid $blue;
border-radius: $border-radius-heritage;
color: $blue;
font-weight: 500;
transition: all 150ms linear;
&:hover {
color: $white;
@include blue-gradient;
}
&:focus, // Mouse, touch, stylus focus
&:focus-visible {
// Keyboard focus for accessibility
outline: none;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
color: $white;
@include blue-gradient;
}
&:disabled {
background: transparent;
color: $gray-550 !important;
font-weight: 400;
border: 1px solid $gray-550;
border-radius: $border-radius-heritage;
cursor: pointer;
pointer-events: all;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
}
}
}
</style> </style>

View file

@ -2,7 +2,7 @@
<baseInputButton <baseInputButton
v-bind="$props" v-bind="$props"
v-model="selectedValue" v-model="selectedValue"
buttonWrapperClasses="list-group base-input-button list-button rounded-3 d-flex flex-column w-100 mb-2"> buttonWrapperClasses="list-group base-input-button list-button no-hover d-flex flex-column w-100 mb-2">
<div <div
:aria-label="buttonLabel" :aria-label="buttonLabel"
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4"> class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
@ -67,6 +67,12 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$heritage-border-radius: 60px;
$heritage-border-color: #CACBCC;
$heritage-box-shadow: 0 1px 5px rgba($black, 0.2);
$heritage-checked-background-color: #e7f1f6;
$heritage-checked-border-color: #0070d1;
.loader { .loader {
position: absolute; position: absolute;
} }
@ -75,26 +81,11 @@ export default {
input[type="radio"], input[type="radio"],
input[type="checkbox"] { input[type="checkbox"] {
position: static; //override bootstrap position: static; //override bootstrap
&:focus-visible + .list-button-content {
box-shadow: 0 0 0 2.5px $blue;
}
&:focus + .list-button-content {
box-shadow: 0 0 0 2.5px $blue;
}
&:checked + .list-button-content { &:checked + .list-button-content {
color: $black; background: $heritage-checked-background-color;
font-weight: 500; border-color: $heritage-checked-border-color;
background: $blue-100;
box-shadow: 0 0 0 1px $blue; box-shadow: 0 0 0 1px $blue;
} }
&:checked:focus + .list-button-content {
box-shadow: 0 0 0 2.5px $blue;
}
&:checked + .list-button-content p,
&:checked + .list-button-content span {
font-weight: 500;
}
&:checked + .list-button-content span:nth-child(2) { &:checked + .list-button-content span:nth-child(2) {
font-weight: 400; font-weight: 400;
color: $gray-600; color: $gray-600;
@ -102,19 +93,20 @@ export default {
} }
} }
.list-button-content { .list-button-content {
color: $gray-600; color: $black;
font-weight: $font-weight-semibold;
position: relative; position: relative;
background: $white; background: $white;
transition: all 150ms linear; transition: all 150ms linear;
border-radius: $border-radius-lg; border-radius: $heritage-border-radius;
border: 1px solid $gray-500; border: 1px solid $heritage-border-color;
box-shadow: $heritage-box-shadow;
width: 100%; width: 100%;
outline: none; outline: none;
span { span {
&.small { &.small {
font-size: 0.75rem; color: $darker-gray;
color: $gray-550;
} }
} }
} }

View file

@ -1,95 +0,0 @@
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { nextTick } from 'vue';
import modalButtonMain from '@/ux-components/modal-button-main/modal-button-main.vue';
/** @ignore */
function setupMocks(mountOptionsMockData = {}) {
const defaultMountOptions = { route: { query: { issPage: 'page-name' } } };
const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData));
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
return allMountOptions;
}
describe('modal-button-main.vue', () => {
it('Should return btn-primary class', () => {
// Arrange/Act
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
isPrimary: true
}
})
);
const button = wrapper.find('button');
// Assert
expect(button.attributes('class')).toContain('btn-primary');
});
it('Should return aria-disabled state', () => {
// Arrange/Act
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
isDisabled: true
}
})
);
const button = wrapper.find('button');
// Assert
expect(button.attributes()['aria-disabled']).toEqual('true');
});
it("Should emit 'click-event' event when clicking if the button is enabled", async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true,
isDisabled: false
}
})
);
const buttonElement = wrapper.find('button');
// Act
buttonElement.trigger('click');
await nextTick();
// Assert
expect(wrapper.emitted('click-event')).toBeTruthy();
});
it("Should not emit 'click-event' event when clicking if the button is disabled", async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true,
isDisabled: true
}
})
);
const buttonElement = wrapper.find('button');
// Act
buttonElement.trigger('click');
await nextTick();
// Assert
expect(wrapper.emitted('click-event')).toBeFalsy();
});
});

View file

@ -1,121 +0,0 @@
<template>
<button
type="button"
:aria-disabled="isDisabled"
class="btn d-flex btn-override align-items-center justify-content-center py-3 px-4 delay"
:class="[
isPrimary ? 'btn-primary' : 'btn-secondary',
isFloat ? 'float-end' : '',
]"
@click="clicked">
<span class="m-0">{{ buttonText }}</span>
</button>
</template>
<script>
export default {
name: 'modal-button-main',
props: {
isPrimary: Boolean,
buttonText: String,
isDisabled: Boolean,
loaderColor: String,
loaderPosition: String,
isFloat: Boolean,
suppressLoader: Boolean
},
emits: ['click-event'],
methods: {
clicked() {
this.pushEventToGA(
this.$route.query[this.queryStrings.ISS_PAGE],
this.GaActions.CLICKED,
this.buttonText,
true
);
if (!this.isDisabled) {
this.$emit('click-event');
}
}
}
};
</script>
<style lang="scss" scoped>
.btn {
&.btn-primary {
position: relative;
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
border: none;
border-radius: $border-radius-lg;
color: $white;
justify-content: center;
font-weight: 500;
letter-spacing: inherit;
@media (hover: hover) {
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
}
// Mouse, touch, stylus focus
&:focus-visible {
// Keyboard focus for accessibility
outline: none;
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
color: $white;
background: linear-gradient(270deg, rgba(6, 87, 124, 1) 0%, rgba(6, 87, 124, 1) 100%);
}
&:disabled {
background: $gray-200 !important;
background: linear-gradient(270deg, $gray-200 0%, $gray-200 100%) !important;
color: $gray-600 !important;
font-weight: 400;
height: 48px;
border: none;
border-radius: $border-radius-lg;
cursor: pointer;
pointer-events: all;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
}
}
&.btn-secondary {
position: relative;
background: transparent;
border: 1px solid $blue;
border-radius: $border-radius-lg;
color: $blue;
font-weight: 500;
transition: all 150ms linear;
height: 3rem;
&:hover {
color: $white;
@include blue-gradient;
}
&:focus, // Mouse, touch, stylus focus
&:focus-visible {
// Keyboard focus for accessibility
outline: none;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
color: $white;
@include blue-gradient;
}
&:disabled {
background: transparent;
color: $gray-550 !important;
font-weight: 400;
height: 48px;
border: 1px solid $gray-550;
border-radius: $border-radius-lg;
cursor: pointer;
pointer-events: all;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
}
}
}
</style>