diff --git a/app/assets/images/globe-blue.svg b/app/assets/images/globe-blue.svg deleted file mode 100644 index a1782e86118..00000000000 --- a/app/assets/images/globe-blue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/images/globe-white.svg b/app/assets/images/globe-white.svg deleted file mode 100644 index 88a59e3d128..00000000000 --- a/app/assets/images/globe-white.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/assets/stylesheets/components/_language-picker.scss b/app/assets/stylesheets/components/_language-picker.scss index 5910f030e92..481c220f5d2 100644 --- a/app/assets/stylesheets/components/_language-picker.scss +++ b/app/assets/stylesheets/components/_language-picker.scss @@ -43,10 +43,6 @@ } } - span { - margin: 0 units(1); - } - &::after { content: ''; display: block; @@ -84,6 +80,10 @@ } } +.language-picker__label-text { + margin: 0 units(1); +} + .language-picker__list { @include list-reset; diff --git a/app/components/icon_component.html.erb b/app/components/icon_component.html.erb index 59d6b4b5695..274a84e440e 100644 --- a/app/components/icon_component.html.erb +++ b/app/components/icon_component.html.erb @@ -1,10 +1,11 @@ <%= content_tag( - :svg, - aria: { hidden: true }, - focusable: 'false', - role: 'img', + :span, + content_tag( + :style, + "#icon-#{unique_id} { mask-image: url(#{icon_path}); -webkit-mask-image: url(#{icon_path}); }", + nonce: content_security_policy_nonce, + ), **tag_options, + id: "icon-#{unique_id}", class: css_class, - ) do %> - -<% end %> + ) -%> diff --git a/app/components/icon_component.rb b/app/components/icon_component.rb index 40250ff994a..4923b3ea551 100644 --- a/app/components/icon_component.rb +++ b/app/components/icon_component.rb @@ -255,13 +255,13 @@ def initialize(icon:, size: nil, **tag_options) end def css_class - classes = ['usa-icon', *tag_options[:class]] + classes = ['icon', 'usa-icon', *tag_options[:class]] classes << "usa-icon--size-#{size}" if size classes end def icon_path - asset_path([asset_path('sprite.svg'), '#', icon].join, host: asset_host) + @icon_path ||= asset_path("usa-icons/#{icon}.svg", host: asset_host) end private diff --git a/app/components/icon_component.scss b/app/components/icon_component.scss index 6b0bdc27e2a..2591b1d1b9c 100644 --- a/app/components/icon_component.scss +++ b/app/components/icon_component.scss @@ -3,6 +3,11 @@ @forward 'usa-icon'; +.icon { + mask-size: 100%; + background-color: currentColor; +} + $icon-min-padding: 2px; // Upstream: https://github.com/uswds/uswds/pull/4493 diff --git a/app/components/language_picker_component.html.erb b/app/components/language_picker_component.html.erb index 7caa09ead3a..5217b896379 100644 --- a/app/components/language_picker_component.html.erb +++ b/app/components/language_picker_component.html.erb @@ -7,9 +7,8 @@ expanded: false, }, ) do %> - <%= image_tag(asset_url('globe-blue.svg'), width: 12, height: 12, alt: '', class: 'tablet:display-none') %> - <%= image_tag(asset_url('globe-white.svg'), width: 12, height: 12, alt: '', class: 'display-none tablet:display-inline') %> - + <%= render IconComponent.new(icon: :language) %> + <%= t('i18n.language') %> <% end %> diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 5f734f347bc..29d2b0e5002 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -47,5 +47,5 @@ # rubocop:enable Metrics/BlockLength Rails.application.configure do config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } - config.content_security_policy_nonce_directives = ['script-src'] + config.content_security_policy_nonce_directives = ['script-src', 'style-src'] end diff --git a/spec/components/button_component_spec.rb b/spec/components/button_component_spec.rb index ce0ef65f49e..f448f220ce9 100644 --- a/spec/components/button_component_spec.rb +++ b/spec/components/button_component_spec.rb @@ -83,7 +83,7 @@ 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).to have_xpath('//style[contains(text(), "/print-")]') expect(rendered.first_element_child.xpath('./text()').text).to eq(content) end @@ -93,7 +93,7 @@ it 'trims text of the content, maintaining html safety' do rendered = render_inline ButtonComponent.new(icon: :print).with_content(content) - expect(rendered.to_html).to include('Button') + expect(rendered.to_html).to include('Button') end end @@ -103,7 +103,9 @@ it 'trims text of the content, maintaining html safety' do rendered = render_inline ButtonComponent.new(icon: :print).with_content(content) - expect(rendered.to_html).to include('<span class="example">Button</span>') + expect(rendered.to_html).to include( + '<span class="example">Button</span>', + ) end end diff --git a/spec/components/icon_component_spec.rb b/spec/components/icon_component_spec.rb index ea92deadcaa..dc1fce80ed4 100644 --- a/spec/components/icon_component_spec.rb +++ b/spec/components/icon_component_spec.rb @@ -12,9 +12,15 @@ it 'renders icon svg' do rendered = render_inline IconComponent.new(icon: :print) - expect(rendered).to have_css( - ".usa-icon use[href^='#{vc_test_request.base_url}'][href$='.svg#print']", - ) + icon = rendered.at_css('.icon.usa-icon') + id = icon.attr(:id) + inline_style = rendered.at_css('style').text.strip + + expect(icon).to be_present + expect(inline_style).to match(%r{##{id}\s{.+?}}). + and(include('-webkit-mask-image:')). + and(include('mask-image:')). + and(match(%r{url\([^)]+/print-\w+\.svg\)})) end context 'with invalid icon' do @@ -27,7 +33,7 @@ it 'adds size variant class' do rendered = render_inline IconComponent.new(icon: :print, size: 2) - expect(rendered).to have_css('.usa-icon.usa-icon--size-2') + expect(rendered).to have_css('.icon.usa-icon.usa-icon--size-2') end end @@ -35,7 +41,7 @@ it 'renders with class' do rendered = render_inline IconComponent.new(icon: :print, class: 'my-custom-class') - expect(rendered).to have_css('.usa-icon.my-custom-class') + expect(rendered).to have_css('.icon.usa-icon.my-custom-class') end end @@ -43,7 +49,7 @@ it 'renders with attributes' do rendered = render_inline IconComponent.new(icon: :print, data: { foo: 'bar' }) - expect(rendered).to have_css('.usa-icon[data-foo="bar"]') + expect(rendered).to have_css('.icon.usa-icon[data-foo="bar"]') end end @@ -55,9 +61,9 @@ it 'bypasses configured asset_host and uses domain_name instead' do rendered = render_inline IconComponent.new(icon: :print) - href = rendered.css('use').first['href'] + inline_style = rendered.at_css('style').text.strip - expect(href).to start_with(domain_name) + expect(inline_style).to match(%r{url\(#{Regexp.escape(domain_name)}}) end end end diff --git a/spec/components/icon_list_component_spec.rb b/spec/components/icon_list_component_spec.rb index 599ede1b38c..83acec19eb7 100644 --- a/spec/components/icon_list_component_spec.rb +++ b/spec/components/icon_list_component_spec.rb @@ -35,7 +35,7 @@ it 'renders items with default color' do expect(rendered).to have_css('.usa-icon-list__icon:not([class*="text-"])', count: 2) - expect(rendered).to have_css('.usa-icon use[href$=".svg#cancel"]', count: 2) + expect(rendered).to have_xpath('//style[contains(text(), "/cancel-")]') end context 'with icon or color attributes specified on parent component' do @@ -48,7 +48,7 @@ it 'passes those attributes to slotted items' do expect(rendered).to have_css('.usa-icon-list__icon.text-error', count: 2) - expect(rendered).to have_css('.usa-icon use[href$=".svg#cancel"]', count: 2) + expect(rendered).to have_xpath('//style[contains(text(), "/cancel-")]', count: 2) end end @@ -62,9 +62,9 @@ it 'renders items with their attributes' do expect(rendered).to have_css('.usa-icon-list__icon.text-success', count: 1) - expect(rendered).to have_css('.usa-icon use[href$=".svg#check_circle"]', count: 1) + expect(rendered).to have_xpath('//style[contains(text(), "/check_circle-")]', count: 1) expect(rendered).to have_css('.usa-icon-list__icon.text-error', count: 1) - expect(rendered).to have_css('.usa-icon use[href$=".svg#cancel"]', count: 1) + expect(rendered).to have_xpath('//style[contains(text(), "/cancel-")]', count: 1) end end diff --git a/spec/features/phone/add_phone_spec.rb b/spec/features/phone/add_phone_spec.rb index 9ee08661408..1b14f111958 100644 --- a/spec/features/phone/add_phone_spec.rb +++ b/spec/features/phone/add_phone_spec.rb @@ -6,7 +6,7 @@ phone = '+1 (225) 278-1234' sign_in_and_2fa_user(user) - expect(page).to have_link(t('account.index.phone_add'), normalize_ws: true, exact: true) + expect(page).to have_link(href: phone_setup_path, text: t('account.index.phone_add')) within('.sidenav') do click_on t('account.navigation.add_phone_number') end diff --git a/spec/requests/csp_spec.rb b/spec/requests/csp_spec.rb index 73440a443ac..cbe92e3b7b2 100644 --- a/spec/requests/csp_spec.rb +++ b/spec/requests/csp_spec.rb @@ -31,7 +31,7 @@ expect(content_security_policy['script-src']).to match( /'self' 'unsafe-eval' 'nonce-[\w\d=\/+]+'/, ) - expect(content_security_policy['style-src']).to eq("'self'") + expect(content_security_policy['style-src']).to match(/'self' 'nonce-[\w\d=\/+]+'/) end it 'uses logout SP to override CSP form action that will allow a redirect to the CSP' do @@ -75,7 +75,7 @@ expect(content_security_policy['script-src']).to match( /'self' 'unsafe-eval' 'nonce-[\w\d=\/+]+'/, ) - expect(content_security_policy['style-src']).to eq("'self'") + expect(content_security_policy['style-src']).to match(/'self' 'nonce-[\w\d=\/+]+'/) end it 'uses logout SP to override CSP form action that will allow a redirect to the CSP' do @@ -111,7 +111,7 @@ expect(content_security_policy['script-src']).to match( /'self' 'unsafe-eval' 'nonce-[\w\d=\/+]+'/, ) - expect(content_security_policy['style-src']).to eq("'self'") + expect(content_security_policy['style-src']).to match(/'self' 'nonce-[\w\d=\/+]+'/) end end