Skip to content

Instantly share code, notes, and snippets.

@necolas
Last active December 25, 2015 23:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save necolas/7059182 to your computer and use it in GitHub Desktop.
Save necolas/7059182 to your computer and use it in GitHub Desktop.
Workflow: SUIT CSS components, Mustache, Flight, Webdriver UI

General idea

  • Create isolated, predictable, configurable UI components.

  • Change the way that eng-design team operates by creating a workflow and audit trail that is based on reviewing modules.

  • UI component's code and appearance are reviewed at the same time, with the same scope.

  • Automatically be aware of changes to modules that depend on the one you are changing. Encourage decomposition of UI where appropriate.

  • Roll out at smallest scale first, with only partial workflow. Lower risk.

Example app directory structure

Rough idea of component-based UI organization.

.
└── ui
    ├── README.md
    ├── STYLE.md
    ├── component
    │   ├── grid
    │   │   ├── bower.json
    │   │   ├── README.md
    │   │   ├── OWNERS
    │   │   ├── css
    │   │   │   └── grid.css
    │   │   ├── template
    │   │   │   ├── core.mustache
    │   │   │   └── cell.mustache
    │   │   └── test
    │   │       └── integration
    │   │           └── spec.mustache
    │   ├── page-profile
    │   │   ├── bower.json
    │   │   ├── README.md
    │   │   ├── OWNERS
    │   │   ├── js
    │   │   │   └── page-profile.js
    │   │   ├── template
    │   │   │   └── core.mustache
    │   │   └── test
    │   │       ├── unit
    │   │       │   └── spec.js
    │   │       └── integration
    │   │           └── spec.mustache
    │   └── tweet
    │       ├── bower.json
    │       ├── README.md
    │       ├── OWNERS
    │       ├── css
    │       │   ├── tweet.editing.css
    │       │   └── tweet.css
    │       ├── js
    │       │   ├── tweet.with-promoted.js
    │       │   └── tweet.js
    │       ├── template
    │       │   ├── actions.mustache
    │       │   ├── core.mustache
    │       │   ├── context.mustache
    │       │   ├── footer.mustache
    │       │   ├── header.mustache
    │       │   └── media.mustache
    │       └── test
    │           ├── unit
    │           │   ├── with-promoted.spec.js
    │           │   └── spec.js
    │           └── integration
    │               └── spec.mustache
    └── util

SUIT

Hide the component implementation details.

  1. Every component has a unique namespace.
  2. Every component is developed in isolation (i.e., it doesn't care where it might end up)
  3. All CSS rules in the component's CSS must start with the namespace.
  4. No rules in the component CSS may use nested-component modifiers in selectors. (i.e., don't do this .Tweetbox .Button--submit)
  5. Every component is responsible for HTML/Mustache templates with configuration options (server-side logic – #with_some_optional_part, #extra_classes - and template inheritance placeholders).

A component could be a button or an entire page. Compose components from others without having to be concerned with the inner component implementation details.

Some presentation logic and configuration will end up in the server-side views (due to the limitations of our templating engines) and JS files.

Flight

  1. If a UI component needs to undergo logical state changes in the client, then a Flight component is created to manage it and the corresponding presentation.
  2. It is bound to the UI component by the ancestral context (so, a tweetbox would have to bind the Button component to any button it wants to apply the behaviour to).
  3. The component defines events to respond to and emit.

USE BOWER to specify local dependencies, e.g., 'tweetbox' depends on '../button', '../textarea', etc. Depends on whole components; should help trace HTML/CS/JS dependencies and generate bundles with only the modules needed by a part of the UI.

Webdriver / Visual diffs

Huxley or PhantomCSS

  1. Load the dedicated visual test file in isolation with mock data.
  2. Each static state is represented.
  3. Interactive flows are carried out.
  4. Screenshots compared between master and your branch.
  5. Check that module is rendering as expected.
  6. Run tests for all modules to find out how higher-level modules are impacted.
  7. Check that modules are rendering to satisfaction (or fix them)
  8. Put up review with image diffs so teams can see how their modules are changed.
/*! suit-grid v1.0.0 | MIT License | github.com/suitcss */
/* ==========================================================================
SUIT: Grid
========================================================================== */
/**
* Core grid component
*
* DO NOT apply dimension or offset utilities to the `Grid` element. All cell
* widths and offsets should be applied to child grid cells.
*
* Example uses:
*
* <div class="Grid [Grid--alignCenter|Grid--alignRight]">
* <div class="Grid-cell [Grid-cell--center] u-size1of2"></div>
* <div class="Grid-cell u-size1of2"></div>
* <div class="Grid-cell u-size1of3"></div>
* <div class="Grid-cell u-size1of3"></div>
* </div>
*/
/* Grid container
========================================================================== */
/**
* All content must be contained within child `Grid-cell` elements.
*
* 1. Account for browser defaults of elements that might be the root node of
* the component.
* 2. Ensure consistent default alignment.
* 3. Remove inter-cell whitespace that appears between `inline-block` child
* elements.
*/
.Grid {
display: block; /* 1 */
padding: 0; /* 1 */
margin: 0; /* 1 */
text-align: left; /* 2 */
font-size: 0; /* 3 */
}
/**
* Modifier: center align all grid cells
*/
.Grid--alignCenter {
text-align: center;
}
/**
* Modifier: right align all grid cells
*/
.Grid--alignRight {
text-align: right;
}
/* Grid cell
========================================================================== */
/**
* No explicit width by default. Rely on combining `Grid-cell` with a dimension
* utility or a component class that extends 'grid'.
*
* 1. Fundamentals of the non-float grid layout.
* 2. Reset font size change made in `Grid`.
* 3. Keeps content correctly aligned with the grid direction.
* 4. Controls vertical positioning of units.
* 5. Make cells full-width by default.
*/
.Grid-cell {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: inline-block; /* 1 */
font-size: 1rem; /* 2 */
margin: 0;
padding: 0;
text-align: left; /* 3 */
vertical-align: top; /* 4 */
width: 100%; /* 5 */
}
/**
* Modifier: horizontally center one unit
* Set a specific unit to be horizontally centered. Doesn't affect
* any other units. Can still contain a child `Grid` object.
*/
.Grid-cell--center {
display: block;
margin: 0 auto;
}
<div class="Grid-cell {{cell_classes}}" {{cell_data_attrs}}>
{{$content}}{{/content}}
</div>
<div class="Grid {{grid_classes}}" {{grid_attrs}}>
{{$grid_content}}{{/grid-content}}
</div>
{{$test_component}}Grid{{/test_component}}
{{$test_css_dependencies}}
<link rel="stylesheet" href="bower_components/suit-utils-dimension/dimension.css">
<link rel="stylesheet" href="bower_components/suit-grid/grid.css">
<link rel="stylesheet" href="css/grid.css">
{{/test_css_dependencies}}
{{$test_css_inline}}
.Test-run {
padding: 10px;
}
#textWrapping {
width: 300px;
}
{{/test_css_inline}}
{{$test_suite}}
<h2 class="Test-describe">.Grid</h2>
<h3 class="Test-it">renders Grid-cell without inter-cell whitespace</h3>
<div class="Test-run">
</div>
{{/test_suite}}
<!DOCTYPE html>
<meta charset="utf-8">
<title>{{name}} [component] - SUIT</title>
<link rel="stylesheet" href="bower_components/suit-test/test.css">
{{$test_css_dependencies}}
{{/test_css_dependencies}}
<style>
{{$test_css_inline}}{{/test_css_inline}}
</style>
<div class="Test">
<h1 class="Test-title">SUIT CSS: {{name}} component tests</h1>
{{$test_suite}}<p>No tests :(</p>{{/test_suite}}
</div>
@cameronhunter
Copy link

Should the mustache names reflect the SUIT component naming conventions?

I'd call them integration tests instead of visual. It's more standard and it is, after all, testing the integration of the JS, CSS, template and data.

I like that the components are completely self-contained, tests and all. Would prefer templates over parts. I like the idea of a scala case class representing a component – unsure if it would scale as building them might be a pain.

@necolas
Copy link
Author

necolas commented Oct 21, 2013

Changed. The templates could roughly reflect the UI component structure without being as verbose as the names we use in the template code: grid/template/core, grid/template/cell

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment