Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
@use 'uswds-core' with (
// Prevent USWDS from rendering `@font-face` in every stylesheet. One stylesheet should override
// this to ensure that the `@font-face` is defined at least once.
$render-font-face: false !default;

@forward '@18f/identity-design-system/packages/uswds-core' with (
$theme-body-font-size: 'sm',
$theme-font-path: '.',
$theme-image-path: '@18f/identity-design-system/dist/assets/img',
Expand All @@ -8,6 +12,21 @@
$theme-header-min-width: 'tablet',
$theme-link-visited-color: 'primary',
$theme-style-body-element: true,
$theme-typeface-tokens:
if(
$render-font-face,
(),
(
'roboto-mono': (
cap-height: 380px,
src: false,
),
'public-sans': (
cap-height: 362px,
src: false,
),
)
),
$output-these-utilities: (
'add-list-reset',
'align-items',
Expand Down
1 change: 0 additions & 1 deletion app/assets/stylesheets/_uswds.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
@forward 'usa-skipnav';
@forward 'usa-step-indicator';
@forward 'usa-tag';
@forward 'usa-tooltip';
@forward 'usa-verification-badge';
@forward 'uswds-form-controls';
@forward 'uswds-utilities';
4 changes: 3 additions & 1 deletion app/assets/stylesheets/application.css.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@forward 'required';
@forward 'uswds-core' with (
$render-font-face: true
);
@forward 'uswds';
@forward 'design-system-waiting-room';
@forward 'components/all';
Expand Down
1 change: 0 additions & 1 deletion app/assets/stylesheets/components/all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,5 @@
@import 'spinner-button';
@import 'spinner-dots';
@import 'step-indicator';
@import 'tooltip';
@import 'troubleshooting-options';
@import 'memorable-date';
2 changes: 1 addition & 1 deletion app/assets/stylesheets/document-capture.css.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@forward 'required';
@forward 'uswds-core';
@forward '../../javascript/packages/document-capture/styles';
1 change: 0 additions & 1 deletion app/assets/stylesheets/email.css.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@forward 'required';
@use 'uswds-core' as *;
@import 'variables/app';
@import 'variables/email';
Expand Down
39 changes: 33 additions & 6 deletions app/components/base_component.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
class BaseComponent < ViewComponent::Base
def before_render
return if @rendered_scripts
@rendered_scripts = true
if helpers.respond_to?(:enqueue_component_scripts) && self.class.scripts.present?
helpers.enqueue_component_scripts(*self.class.scripts)
end
render_assets unless rendered_assets?
end

def self.scripts
@scripts ||= begin
scripts = sidecar_files(['js', 'ts']).map { |file| File.basename(file, '.*') }
scripts = sidecar_files_basenames(['js', 'ts'])
scripts.concat superclass.scripts if superclass.respond_to?(:scripts)
scripts
end
end

def self.stylesheets
@stylesheets ||= begin
stylesheets = sidecar_files_basenames(['scss'])
stylesheets.concat superclass.stylesheets if superclass.respond_to?(:stylesheets)
stylesheets
end
end

def unique_id
@unique_id ||= SecureRandom.hex(4)
end

private

attr_accessor :rendered_assets
alias_method :rendered_assets?, :rendered_assets

class << self
def sidecar_files_basenames(extensions)
sidecar_files(extensions).map { |file| File.basename(file, '.*') }
end
end

def render_assets
if helpers.respond_to?(:enqueue_component_scripts) && self.class.scripts.present?
helpers.enqueue_component_scripts(*self.class.scripts)
end

if helpers.respond_to?(:enqueue_component_stylesheets) && self.class.stylesheets.present?
helpers.enqueue_component_stylesheets(*self.class.stylesheets)
end

@rendered_assets = true
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@use 'uswds-core' as *;
@forward 'usa-tooltip';

// Workaround for tooltip styles affecting icon button appearance.
// See: https://github.com/uswds/uswds/pull/5263
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/component_preview_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ class ComponentPreviewController < ViewComponentsController
include ActionView::Helpers::AssetTagHelper
helper Lookbook::PreviewHelper
include ScriptHelper
include StylesheetHelper

helper_method :enqueue_component_scripts
alias_method :enqueue_component_scripts, :render_javascript_pack_once_tags

helper_method :enqueue_component_stylesheets
alias_method :enqueue_component_stylesheets, :render_stylesheet_once_tags
end
end
17 changes: 17 additions & 0 deletions app/helpers/stylesheet_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# rubocop:disable Rails/HelperInstanceVariable
module StylesheetHelper
def stylesheet_tag_once(*names)
@stylesheets ||= []
@stylesheets |= names
nil
end

alias_method :enqueue_component_stylesheets, :stylesheet_tag_once

def render_stylesheet_once_tags(*names)
stylesheet_tag_once(*names) if names.present?
return if @stylesheets.blank?
safe_join(@stylesheets.map { |stylesheet| stylesheet_link_tag(stylesheet) })
end
end
# rubocop:enable Rails/HelperInstanceVariable
8 changes: 8 additions & 0 deletions app/javascript/packages/build-sass/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## Unreleased

### Breaking Changes

- Changed priority for how load paths are used when resolving modules. The net effect is that any `--load-path` should take highest priority over those provided as defaults.
- Before: (1) `node_modules`, (2) default load paths, (3) custom `--load-path` load paths
- After: (1) custom `--load-path` load paths, (2) default load paths, (3) `node_modules`

## 1.3.0

### Improvements
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/packages/build-sass/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const { values: flags, positionals: fileArgs } = parseArgs({

const isWatching = flags.watch;
const outDir = flags['out-dir'];
const loadPaths = [...getDefaultLoadPaths(), ...flags['load-path']];
const loadPaths = [...flags['load-path'], ...getDefaultLoadPaths()];

/** @type {BuildOptions & SyncSassOptions} */
const options = { outDir, loadPaths, optimize: isProduction };
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/packages/build-sass/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export async function buildFile(file, options) {
const sassResult = sass.compile(file, {
style: optimize ? 'compressed' : 'expanded',
...sassOptions,
loadPaths: ['node_modules', ...loadPaths],
loadPaths: [...loadPaths, 'node_modules'],
quietDeps: true,
});

Expand Down
1 change: 1 addition & 0 deletions app/views/layouts/base.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<%= preload_link_tag font_url('public-sans/PublicSans-Bold.woff2') %>
<%= preload_link_tag font_url('public-sans/PublicSans-Regular.woff2') %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= render_stylesheet_once_tags %>
<%= csrf_meta_tags %>

<%= favicon_link_tag(
Expand Down
1 change: 1 addition & 0 deletions app/views/layouts/component_preview.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<title>Component Preview</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= render_stylesheet_once_tags %>
</head>
<body class="height-auto padding-2 <%= params.dig(:lookbook, :display, :body_class) %>">
<% if params.dig(:lookbook, :display, :form) == true %>
Expand Down
1 change: 1 addition & 0 deletions app/views/saml_idp/shared/saml_post_binding.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="utf-8" />
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= render_stylesheet_once_tags %>
<%= render_javascript_pack_once_tags 'saml-post' %>
</head>
<body>
Expand Down
1 change: 1 addition & 0 deletions app/views/shared/saml_post_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="utf-8" />
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= render_stylesheet_once_tags %>
<%= render_javascript_pack_once_tags 'saml-post' %>
</head>
<body>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"clean": "rm -rf public/packs/*",
"prebuild": "yarn run clean",
"build": "webpack && yarn generate-browsers-json",
"build:css": "build-sass app/assets/stylesheets/*.css.scss --out-dir=app/assets/builds"
"build:css": "build-sass app/assets/stylesheets/*.css.scss app/components/*.scss --load-path=app/assets/stylesheets --out-dir=app/assets/builds"
},
"dependencies": {
"@18f/identity-design-system": "^7.0.1",
Expand Down
74 changes: 74 additions & 0 deletions spec/components/base_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,80 @@ def self.sidecar_files(extensions)
end
end

context 'with sidecar stylesheet' do
class ExampleComponentWithStylesheet < BaseComponent
def call
''
end

def self.sidecar_files(extensions)
files = []
files << '/example_component_with_stylesheet.scss' if extensions.include?('scss')
files.presence || super(extensions)
end
end

class ExampleComponentWithStylesheetRenderingOtherComponentWithStylesheet < BaseComponent
def call
render(ExampleComponentWithStylesheet.new)
end

def self.sidecar_files(extensions)
if extensions.include?('scss')
['/example_component_with_stylesheet_rendering_other_component_with_stylesheet.scss']
else
super(extensions)
end
end
end

class NestedExampleComponentWithStylesheet < ExampleComponentWithStylesheet
def self.sidecar_files(extensions)
if extensions.include?('scss')
['/nested_example_component_with_stylesheet.scss']
else
super(extensions)
end
end
end

it 'adds script to class variable when rendered' do
expect(view_context).to receive(:enqueue_component_stylesheets).with(
'example_component_with_stylesheet',
)

render_inline(ExampleComponentWithStylesheet.new)
end

it 'adds own and parent scripts to class variable when rendered' do
expect(view_context).to receive(:enqueue_component_stylesheets).with(
'nested_example_component_with_stylesheet',
'example_component_with_stylesheet',
)

render_inline(NestedExampleComponentWithStylesheet.new)
end

it 'adds own and scripts of any other component it renders' do
call = 0
expect(view_context).to receive(:enqueue_component_stylesheets).twice do |*args|
call += 1
case call
when 1
expect(args).to eq [
'example_component_with_stylesheet_rendering_other_component_with_stylesheet',
]
when 2
expect(args).to eq [
'example_component_with_stylesheet',
]
end
end

render_inline(ExampleComponentWithStylesheetRenderingOtherComponentWithStylesheet.new)
end
end

describe '#unique_id' do
it 'provides a unique id' do
first_component = ExampleComponentWithScript.new
Expand Down
87 changes: 87 additions & 0 deletions spec/helpers/stylesheet_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require 'rails_helper'

RSpec.describe StylesheetHelper do
describe '#stylesheet_tag_once' do
it 'returns nil' do
output = stylesheet_tag_once('styles')

expect(output).to be_nil
end
end

describe '#render_stylesheet_once_tags' do
context 'no stylesheets enqueued' do
it 'is nil' do
expect(render_stylesheet_once_tags).to be_nil
end
end

context 'stylesheets enqueued' do
before do
stylesheet_tag_once('styles')
end

it 'prints stylesheets' do
output = render_stylesheet_once_tags

expect(output).to have_css(
'link[rel="stylesheet"][href="/stylesheets/styles.css"]',
count: 1,
visible: :all,
)
end
end

context 'same stylesheet enqueued multiple times' do
before do
stylesheet_tag_once('styles')
stylesheet_tag_once('styles')
end

it 'prints stylesheets once' do
output = render_stylesheet_once_tags

expect(output).to have_css(
'link[rel="stylesheet"][href="/stylesheets/styles.css"]',
count: 1,
visible: :all,
)
end
end

context 'multiple stylesheets enqueued' do
before do
stylesheet_tag_once('styles-a')
stylesheet_tag_once('styles-b')
end

it 'prints stylesheets once, in order' do
output = render_stylesheet_once_tags

expect(output).to have_css(
'link[rel="stylesheet"][href="/stylesheets/styles-a.css"] ~ ' \
'link[rel="stylesheet"][href="/stylesheets/styles-b.css"]',
count: 1,
visible: :all,
)
end
end

context 'with named stylesheets argument' do
before do
stylesheet_tag_once('styles-a')
end

it 'enqueues those stylesheets before printing them' do
output = render_stylesheet_once_tags('styles-b')

expect(output).to have_css(
'link[rel="stylesheet"][href="/stylesheets/styles-a.css"] ~ ' \
'link[rel="stylesheet"][href="/stylesheets/styles-b.css"]',
count: 1,
visible: :all,
)
end
end
end
end