From fa965468b480f873fa91e5e02f310df64a2c1f6b Mon Sep 17 00:00:00 2001 From: Josh Dassinger Date: Mon, 5 Jan 2026 10:42:15 -0600 Subject: [PATCH] Initial work on moving heritage button styles to NextGen button component Added button variant support Added button size support Merged button features from modal button to button component Removed modal button component Created button mixins for creating buttons Created initial button variants using mixins Moved client button customizations to mixins --- src/constants/button-sizes.js | 8 + src/constants/button-variants.js | 9 + src/digital-components/modal/modal.vue | 32 +-- .../button-question-modal.vue | 3 +- .../continue-modal/continue-modal.vue | 25 +-- .../site-footer/site-footer.vue | 6 +- .../cancel-claim-modal/cancel-claim-modal.vue | 35 +--- src/layouts/tpa-submit/tpa-submit.spec.js | 2 +- src/layouts/tpa-submit/tpa-submit.vue | 2 +- src/styles/client-customizations.scss | 192 ++---------------- src/styles/common-styles.scss | 46 +++++ src/styles/mixins/customMixins.scss | 51 +++++ .../button-main/button-main.spec.js | 152 +++++++++++++- src/ux-components/button-main/button-main.vue | 118 +++-------- .../modal-button-main.spec.js | 95 --------- .../modal-button-main/modal-button-main.vue | 121 ----------- 16 files changed, 342 insertions(+), 555 deletions(-) create mode 100644 src/constants/button-sizes.js create mode 100644 src/constants/button-variants.js delete mode 100644 src/ux-components/modal-button-main/modal-button-main.spec.js delete mode 100644 src/ux-components/modal-button-main/modal-button-main.vue diff --git a/src/constants/button-sizes.js b/src/constants/button-sizes.js new file mode 100644 index 00000000..d4f46ecc --- /dev/null +++ b/src/constants/button-sizes.js @@ -0,0 +1,8 @@ +const buttonSizes = Object.freeze({ + xs: 'xs', + sm: 'sm', + md: 'md', + lg: 'lg' +}); + +export default buttonSizes; diff --git a/src/constants/button-variants.js b/src/constants/button-variants.js new file mode 100644 index 00000000..cf73718a --- /dev/null +++ b/src/constants/button-variants.js @@ -0,0 +1,9 @@ +const buttonVariants = Object.freeze({ + primary: 'primary', + secondary: 'secondary', + success: 'success', + link: 'link', + navigation: 'navigation' +}); + +export default buttonVariants; diff --git a/src/digital-components/modal/modal.vue b/src/digital-components/modal/modal.vue index 8a4664e7..0ab74b24 100644 --- a/src/digital-components/modal/modal.vue +++ b/src/digital-components/modal/modal.vue @@ -34,30 +34,18 @@ @@ -65,7 +53,7 @@ diff --git a/src/iss-components/site-footer/site-footer.vue b/src/iss-components/site-footer/site-footer.vue index 81cb42f6..b73ab67a 100644 --- a/src/iss-components/site-footer/site-footer.vue +++ b/src/iss-components/site-footer/site-footer.vue @@ -16,7 +16,7 @@
- + variant="success" + :buttonText="modalBodyText2" + class="mt-4 w-100" + @clickEvent="returnToClaim"> +
@@ -29,10 +26,12 @@ diff --git a/src/layouts/tpa-submit/tpa-submit.spec.js b/src/layouts/tpa-submit/tpa-submit.spec.js index 9ce2cf6d..7dd6920b 100644 --- a/src/layouts/tpa-submit/tpa-submit.spec.js +++ b/src/layouts/tpa-submit/tpa-submit.spec.js @@ -169,7 +169,7 @@ describe('tpa-submit', () => { // Assert 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('mb-5'); }); diff --git a/src/layouts/tpa-submit/tpa-submit.vue b/src/layouts/tpa-submit/tpa-submit.vue index 5b3b223a..181fa0aa 100644 --- a/src/layouts/tpa-submit/tpa-submit.vue +++ b/src/layouts/tpa-submit/tpa-submit.vue @@ -32,7 +32,7 @@ class="mb-4 small text-color--darker-gray" /> diff --git a/src/styles/client-customizations.scss b/src/styles/client-customizations.scss index 26beae9f..487a63ae 100644 --- a/src/styles/client-customizations.scss +++ b/src/styles/client-customizations.scss @@ -86,52 +86,14 @@ .btn-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 { - .modal { - .modal-body { - .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-footer { - .btn:not(.navigation-link) { - background: $button-color; - color: $button-text-color; - } - } - } + .btn { + &.btn-override { + @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true); + @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true); } + } } // End Amica @@ -171,52 +133,14 @@ a.new-window-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 { - .modal { - .modal-body { - .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-footer { - .btn:not(.navigation-link) { - background: $button-color; - color: $button-text-color; - } - } - } + .btn { + &.btn-override { + @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true); + @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true); } + } } // End Nationwide @@ -256,52 +180,14 @@ a.new-window-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 { - .modal { - .modal-body { - .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-footer { - .btn:not(.navigation-link) { - background: $button-color; - color: $button-text-color; - } - } - } + .btn { + &.btn-override { + @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true); + @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true); } + } } // End Country Financial @@ -341,52 +227,14 @@ a.new-window-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 { - .modal { - .modal-body { - .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-footer { - .btn:not(.navigation-link) { - background: $button-color; - color: $button-text-color; - } - } - } + .btn { + &.btn-override { + @include heritage-btn-variant('success', $button-text-color, $button-color, transparent, true); + @include heritage-btn-variant('navigation', $button-text-color, $button-color, transparent, true); } + } } // End Travelers \ No newline at end of file diff --git a/src/styles/common-styles.scss b/src/styles/common-styles.scss index 01208d7f..fceed06e 100644 --- a/src/styles/common-styles.scss +++ b/src/styles/common-styles.scss @@ -182,4 +182,50 @@ body { :root { --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: #{$font-weight-bolder}; + 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, 20px, $heritage-btn-border-radius); + @include heritage-btn-size('md', 7px, 15px, 15px, $heritage-btn-border-radius); + @include heritage-btn-size('sm', 3px, 6px, 12px, $heritage-btn-border-radius); + @include heritage-btn-size('xs', 1px, 5px, 12px, $heritage-btn-border-radius); + + &.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; + } } \ No newline at end of file diff --git a/src/styles/mixins/customMixins.scss b/src/styles/mixins/customMixins.scss index cd3555cc..fa1c1c15 100644 --- a/src/styles/mixins/customMixins.scss +++ b/src/styles/mixins/customMixins.scss @@ -8,3 +8,54 @@ @mixin box-shadow-hover($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 + $color, + ); + } +} + +@mixin heritage-btn-size($size, $y-padding, $x-padding, $font-size, $border-radius) { + &.btn-#{$size} { + @include button-size($y-padding, $x-padding, $font-size, $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}; + } +} \ No newline at end of file diff --git a/src/ux-components/button-main/button-main.spec.js b/src/ux-components/button-main/button-main.spec.js index 95664421..bec1abf5 100644 --- a/src/ux-components/button-main/button-main.spec.js +++ b/src/ux-components/button-main/button-main.spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import { getMountOptions } from '@/helpers/unit-test-helper.js'; import buttonMain from '@/ux-components/button-main/button-main.vue'; +import buttonVariants from '@/constants/button-variants'; /** @ignore */ function setupMocks(mountOptionsMockData = {}) { @@ -12,13 +13,75 @@ function setupMocks(mountOptionsMockData = {}) { } 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(['', 'sm', 'lg'])('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 + const buttonText = 'Test Text'; const wrapper = shallowMount( buttonMain, setupMocks({ propsData: { - isPrimary: true + buttonText } }) ); @@ -27,10 +90,10 @@ describe('buttonMain.vue', () => { const button = wrapper.find('button'); // 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 const wrapper = shallowMount( buttonMain, @@ -47,4 +110,85 @@ describe('buttonMain.vue', () => { // Expect 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').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').length).toBe(1); + }); + + 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(); + }); }); diff --git a/src/ux-components/button-main/button-main.vue b/src/ux-components/button-main/button-main.vue index 6000a9f2..1a69fd51 100644 --- a/src/ux-components/button-main/button-main.vue +++ b/src/ux-components/button-main/button-main.vue @@ -1,30 +1,49 @@ diff --git a/src/ux-components/modal-button-main/modal-button-main.spec.js b/src/ux-components/modal-button-main/modal-button-main.spec.js deleted file mode 100644 index d06fc1ca..00000000 --- a/src/ux-components/modal-button-main/modal-button-main.spec.js +++ /dev/null @@ -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(); - }); -}); diff --git a/src/ux-components/modal-button-main/modal-button-main.vue b/src/ux-components/modal-button-main/modal-button-main.vue deleted file mode 100644 index 7508667e..00000000 --- a/src/ux-components/modal-button-main/modal-button-main.vue +++ /dev/null @@ -1,121 +0,0 @@ - - - - -