diff --git a/CHANGELOG.md b/CHANGELOG.md index 43e6587ce2d..e5723098bac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Unreleased ### Improvements/Changes - Layout: Improve layout margins and typographical consistency across several content pages. (#5880, #5884, #5887, #5888) - Typography: Updated monospace font to Roboto Mono for consistency across login.gov sites. (#5891) +- Icons: Replaced custom button icons using U.S. Web Design system icons. (#5904) ### Accessibility diff --git a/app/assets/images/ico-download.svg b/app/assets/images/ico-download.svg deleted file mode 100644 index bf23b5f8651..00000000000 --- a/app/assets/images/ico-download.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/images/ico-print.svg b/app/assets/images/ico-print.svg deleted file mode 100644 index 83278594b97..00000000000 --- a/app/assets/images/ico-print.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/images/ico-refresh.svg b/app/assets/images/ico-refresh.svg deleted file mode 100644 index 2c0081eaba6..00000000000 --- a/app/assets/images/ico-refresh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/stylesheets/components/_icon.scss b/app/assets/stylesheets/components/_icon.scss index 5314c2f3fe2..950369f8307 100644 --- a/app/assets/stylesheets/components/_icon.scss +++ b/app/assets/stylesheets/components/_icon.scss @@ -1,24 +1,18 @@ -.ico { - &::before { - background-repeat: no-repeat; - background-size: 1rem; - content: ''; - display: inline-block; - height: 1rem; - margin: -0.125rem 0.5rem -0.125rem 0; - width: 1rem; +// Upstream: https://github.com/uswds/uswds/pull/4493 +.usa-icon { + .usa-button > &:first-child { + // Note: This diverges from the upstream pull request in a couple ways: + // 1. There should not be any margins offsetting to account for line height, since Login.gov + // Design System normalizes button line height to 1. + // 2. Float is replaced by `vertical-align`, since otherwise it will have the effect of having + // the icon appear to the far edge of the button, rather than next to the text. + vertical-align: bottom; + margin-right: 0.25rem; } - &.ico-download::before { - background-image: url('ico-download.svg'); - } - - &.ico-refresh::before { - background-image: url('ico-refresh.svg'); - } - - &.ico-print::before { - background-image: url('ico-print.svg'); + .usa-button:not(.usa-button--unstyled) > &:first-child { + margin-left: -0.5rem; + margin-right: 0.5rem; } } diff --git a/app/assets/stylesheets/print.scss b/app/assets/stylesheets/print.scss index 0749d805c36..8292aa80dea 100644 --- a/app/assets/stylesheets/print.scss +++ b/app/assets/stylesheets/print.scss @@ -3,8 +3,7 @@ footer, .usa-button, .usa-radio__input--bordered, - .usa-checkbox__input--bordered, - .ico { + .usa-checkbox__input--bordered { display: none; } } diff --git a/app/components/button_component.html.erb b/app/components/button_component.html.erb index 762ac4b710b..2c95172424a 100644 --- a/app/components/button_component.html.erb +++ b/app/components/button_component.html.erb @@ -1 +1,6 @@ -<%= button_tag(content, **tag_options, type: tag_type, class: css_class) %> +<%= action.call( + safe_join([icon_content, content&.strip].compact), + **tag_options, + type: tag_type, + class: css_class, + ) %> diff --git a/app/components/button_component.rb b/app/components/button_component.rb index ad6ea90ac22..46d08ce8833 100644 --- a/app/components/button_component.rb +++ b/app/components/button_component.rb @@ -1,9 +1,16 @@ class ButtonComponent < BaseComponent - attr_reader :type, :outline, :tag_options + attr_reader :action, :icon, :outline, :tag_options DEFAULT_BUTTON_TYPE = :button - def initialize(outline: false, **tag_options) + def initialize( + action: ->(content, **tag_options) { button_tag(content, **tag_options) }, + icon: nil, + outline: false, + **tag_options + ) + @action = action + @icon = icon @outline = outline @tag_options = tag_options end @@ -17,4 +24,8 @@ def css_class def tag_type tag_options.fetch(:type, DEFAULT_BUTTON_TYPE) end + + def icon_content + render IconComponent.new(icon: icon) if icon + end end diff --git a/app/components/clipboard_button_component.rb b/app/components/clipboard_button_component.rb index 4dce02116b9..4c0fd6bcfd2 100644 --- a/app/components/clipboard_button_component.rb +++ b/app/components/clipboard_button_component.rb @@ -2,10 +2,9 @@ class ClipboardButtonComponent < ButtonComponent attr_reader :clipboard_text, :tag_options def initialize(clipboard_text:, **tag_options) - super(**tag_options) + super(**tag_options, icon: :content_copy) @clipboard_text = clipboard_text - @tag_options = tag_options end def call @@ -13,11 +12,6 @@ def call end def content - safe_join( - [ - render(IconComponent.new(icon: :content_copy, class: 'position-absolute')), - content_tag(:span, t('links.copy'), class: 'padding-left-3'), - ], - ) + t('links.copy') end end diff --git a/app/views/idv/otp_verification/show.html.erb b/app/views/idv/otp_verification/show.html.erb index b5baca05f4e..f88159564bb 100644 --- a/app/views/idv/otp_verification/show.html.erb +++ b/app/views/idv/otp_verification/show.html.erb @@ -36,11 +36,14 @@ <% end %> -<%= button_to idv_resend_otp_path, - method: :post, - class: 'usa-button usa-button--outline ico ico-refresh margin-bottom-4' do %> - <%= t('links.two_factor_authentication.get_another_code') %> -<% end %> +<%= render ButtonComponent.new( + action: ->(content, **tag_options) do + button_to(idv_resend_otp_path, method: :post, **tag_options) { content } + end, + outline: true, + icon: :loop, + class: 'margin-bottom-4', + ).with_content(t('links.two_factor_authentication.get_another_code')) %>

<%= t('instructions.mfa.wrong_number') %>
diff --git a/app/views/shared/_personal_key.html.erb b/app/views/shared/_personal_key.html.erb index 72044332d02..76c55fc5dec 100644 --- a/app/views/shared/_personal_key.html.erb +++ b/app/views/shared/_personal_key.html.erb @@ -8,21 +8,20 @@

<%= render 'partials/personal_key/key', code: code %>
-<%= link_to( - idv_download_personal_key_path, - class: 'usa-button usa-button--outline margin-right-2 margin-bottom-2 tablet:margin-bottom-0', - ) do %> - <%= render IconComponent.new(icon: :file_download, class: 'position-absolute') %> - <%= t('forms.backup_code.download') %> -<% end %> -<%= button_tag( - type: :button, - data: { print: true }, - class: 'usa-button usa-button--outline margin-right-2 margin-bottom-2 tablet:margin-bottom-0', - ) do %> - <%= render IconComponent.new(icon: :print, class: 'position-absolute') %> - <%= t('users.personal_key.print') %> -<% end %> +<%= render ButtonComponent.new( + action: ->(content, **tag_options) do + link_to(idv_download_personal_key_path, **tag_options) { content } + end, + icon: :file_download, + outline: true, + class: 'margin-right-2 margin-bottom-2 tablet:margin-bottom-0', + ).with_content(t('forms.backup_code.download')) %> +<%= render ButtonComponent.new( + icon: :print, + outline: true, + data: { print: '' }, + class: 'margin-right-2 margin-bottom-2 tablet:margin-bottom-0', + ).with_content(t('users.personal_key.print')) %> <%= render ClipboardButtonComponent.new( clipboard_text: code, outline: true, diff --git a/app/views/two_factor_authentication/otp_verification/show.html.erb b/app/views/two_factor_authentication/otp_verification/show.html.erb index 68245264b85..1065c0fd314 100644 --- a/app/views/two_factor_authentication/otp_verification/show.html.erb +++ b/app/views/two_factor_authentication/otp_verification/show.html.erb @@ -36,16 +36,22 @@ ) %> <%= hidden_field_tag 'otp_make_default_number', @presenter.otp_make_default_number %> - <%= link_to( - t('links.two_factor_authentication.get_another_code'), - otp_send_path( - otp_delivery_selection_form: { - otp_delivery_preference: @presenter.otp_delivery_preference, - resend: true, - }, - ), - class: 'usa-button usa-button--outline ico ico-refresh margin-bottom-neg-1', - ) %> + <%= render ButtonComponent.new( + action: ->(content, **tag_options) do + link_to( + otp_send_path( + otp_delivery_selection_form: { + otp_delivery_preference: @presenter.otp_delivery_preference, + resend: true, + }, + ), + **tag_options, + ) { content } + end, + outline: true, + icon: :loop, + class: 'margin-bottom-neg-1', + ).with_content(t('links.two_factor_authentication.get_another_code')) %> <% end %> <% if @presenter.unconfirmed_phone? %> diff --git a/app/views/users/backup_code_setup/create.html.erb b/app/views/users/backup_code_setup/create.html.erb index d04db92e08d..51284eb0909 100644 --- a/app/views/users/backup_code_setup/create.html.erb +++ b/app/views/users/backup_code_setup/create.html.erb @@ -32,12 +32,20 @@
<% if desktop_device? %> - <%= link_to t('forms.backup_code.download'), backup_code_download_path, - class: 'usa-button usa-button--outline ico ico-download' %> + <%= render ButtonComponent.new( + action: ->(content, **tag_options) do + link_to(backup_code_download_path, **tag_options) { content } + end, + outline: true, + icon: :file_download, + ).with_content(t('forms.backup_code.download')) %> <% end %> - <%= link_to t('forms.backup_code.print'), '#', - data: { print: true }, - class: 'usa-button usa-button--outline margin-top-2 mobile-lg:margin-top-0 mobile-lg:margin-left-2 ico ico-print' -%> + <%= render ButtonComponent.new( + icon: :print, + outline: true, + data: { print: '' }, + class: 'margin-top-2 mobile-lg:margin-top-0 mobile-lg:margin-left-2', + ).with_content(t('forms.backup_code.print')) %> <%= render ClipboardButtonComponent.new( clipboard_text: @codes.join(' '), outline: true, diff --git a/spec/components/button_component_spec.rb b/spec/components/button_component_spec.rb index acc299d3f3f..5cfab596b30 100644 --- a/spec/components/button_component_spec.rb +++ b/spec/components/button_component_spec.rb @@ -1,6 +1,9 @@ require 'rails_helper' RSpec.describe ButtonComponent, type: :component do + include ActionView::Context + include ActionView::Helpers::TagHelper + let(:type) { nil } let(:outline) { false } let(:content) { 'Button' } @@ -10,7 +13,9 @@ }.compact end - subject(:rendered) { render_inline ButtonComponent.new(outline: outline, **options) { content } } + subject(:rendered) do + render_inline ButtonComponent.new(outline: outline, **options).with_content(content) + end it 'renders button content' do expect(rendered).to have_content(content) @@ -39,4 +44,29 @@ expect(rendered).to have_css('button[type=submit]') end end + + context 'with icon' do + it 'renders an icon' do + rendered = render_inline ButtonComponent.new(icon: :print).with_content(content) + + expect(rendered).to have_css('use[href$="#print"]') + expect(rendered.first_element_child.xpath('./text()').text).to eq(content) + end + end + + context 'with custom button action' do + it 'calls the action with content and tag_options' do + rendered = render_inline ButtonComponent.new( + action: ->(content, **tag_options) do + content_tag(:'lg-custom-button', **tag_options, data: { extra: '' }) { content } + end, + class: 'custom-class', + ).with_content(content) + + expect(rendered).to have_css( + 'lg-custom-button[type="button"][data-extra].custom-class', + text: content, + ) + end + end end diff --git a/spec/components/clipboard_button_component_spec.rb b/spec/components/clipboard_button_component_spec.rb index 3c4ef1e7fa1..deecb15fd6f 100644 --- a/spec/components/clipboard_button_component_spec.rb +++ b/spec/components/clipboard_button_component_spec.rb @@ -13,10 +13,14 @@ end context 'with tag options' do - let(:tag_options) { { outline: true } } + let(:tag_options) { { outline: true, data: { foo: 'bar' } } } it 'renders button given the tag options' do - expect(rendered).to have_css('button.usa-button.usa-button--outline') + expect(rendered).to have_css('button.usa-button[data-foo="bar"]') + end + + it 'respects keyword arguments of button component' do + expect(rendered).to have_css('.usa-button--outline:not([outline])') end end end