Skip to main content

Patterns

Developer Tools

The Patterns library is a Node.js application that uses various libraries—including Express, Rollup.js, Node Sass, Nodemon, and HTML Sketch App—to run the development server and build tasks for Style, JavaScript, SVG, Views, and Sketch files. This is all managed via npm scripts in the package.json file, modules in the .app/ directory, and configuration in the config/ directory.

npm run start

This starts the Express.js development server, which uses Express to render the views in src/views. It also uses Concurrently to trigger :watch scripts for different compilation tasks as changes are detected within your project. The NODE_ENV is set to "development" which affects the the styles compilation process by only compiling the global stylesheet. It also affects script processing by disabling ESLint.

The development server renders slm templates, but it does not display markup or markdown blocks for each Pattern. These are blocks included with md{{ path/to/pattern.md }} and code{{ path/to/pattern.slm }}. To see markup and markdown, append .html to the url (ex; http://localhost:7000/developer-tools.html). Because the /dist directory is mounted as the Express server's static directory, all of the compiled files can be previewed in the browser.

npm run make {{ type }} {{ pattern }}

This is the method for creating new patterns using templates defined in the config/make.js directory. Running...

npm run make component accordion

... will generate a styles, markup (.slm), and markdown files from templates needed to add an Accordion Component to the Patterns. The parameters accepted are pattern type (“component”) and name (“accordion”). Currently the available types are element, component, object, and utility. The files will be generated and written according to these parameters;

src/{{ type }}/{{ pattern }}/{{ pattern }}.slm
src/{{ type }}/{{ pattern }}/_{{ pattern }}.scss

Once the script is run, a prompt will ask if you would like to create optional template files inlcuding a SASS configuration file for storing variables and mixins, a JavaScript file for enhanced pattern functionality, a view .slm template file for creating a page to view the pattern in the documentation, an any other custom files defined as optional in the config/make.js file (see below about adding custom templates). The content of each file is determined by the templates defined in the config/make.js file. Overwriting existing pattern files is not allowed, however, rerunning this script will ask the developer if they want to create any of the optional files defined in the optional constant in the config/make.js file.

Adding a File to an Existing Pattern

npm run make {{ type }} {{ pattern }} {{ template }}

Running this command will generate a prompt to create the specified file using templates in the config/make.js file. It will not permit overwritting existing pattern files.

Creating a New Template

Adding a custom template to be created automatically when patterns are generated via this script can be done by adding or modifying variables in the config/make.js file. For example, these are the steps that it would take to add a React template for each Pattern via the npm run make script.

Step 1: Template contents

First, the new template would be defined in the templates constant as "react" and the following template string would written to the content of any new React file;

const templates = {
  ...
  'react': [
    'class {{ Pattern }} extends React.Component {
    '  render() {',
    '    return (',
    '      <div>',
    '        Hello {this.props.name}!',
    '      </div>',
    '    );',
    '  }',
    '}',
    '\n',
    'ReactDOM.render(',
    '  <{{ Pattern }} name="World" />,',
    '  document.getElementById('js-{{ pattern }}')',
    ');'
  ].join('\n'),
  ...
};

Template Variables

Within the template string, there are a handful of variables referencing the new pattern's name that will be replaced when the template is compiled. They are denoted by double brackets {{ }};

  • {{ type }} The pattern type defined by the command. Will either be "elements", "objects", "utilities."
  • {{ prefix }} The pattern prefix, will be defined by the type and prefixes constant in config/make.js.
  • {{ pattern }} The lower case name of the pattern.
  • {{ Pattern }} The uppercase name of the pattern.

Step 2: Filename

Next, provide a filename in the files constant. Filenames use the same template variables above.

const files = {
  ...
  'react': '{{ pattern }}.jsx',
  ...
};

Step 3: Is it optional?

Next, if it is an optional template then add 'react' to the optional constant. This will generate a prompt to create the file with a yes/no question when running the make script.

const optional = [
  ...
  'react',
  ...
];

Step 4: Where to write the template

Next, if the template should written to every new pattern's dedicated directory (ex; src/{{ type }}/{{ pattern }}/) then add 'react' to the patterns constant. This is the default for most templates except views and Sass config.

const patterns = [
  ...
  'react',
  ...
];

If you do not add 'react' to the patterns constant, then you must provide a path you would like it written to in the paths constant. For the most part, pattern templates should be closely associated with their pattern so keeping them together is recommended as opposed to writing them to a different directory. However, there may be cases where this needs to be done.

const paths = {
  ...
  'react': Path.join(dirs.src, 'js', 'react'),
  ...
};
npm run predeploy

This runs all of the compilation tasks illustrated below for Styles, JavaScript, SVG, and Views with NODE_ENV set to "production".

npm run publish

This commits all of the changes in the dist/ directory to the gh-pages branch and pushes it to GitHub. The gh-pages branch is used for the publicly accessible Patterns website.

Publishing

Here are the steps to publishing updates to the npm registry. This assumes that a feature request has been approved and pulled into master.

  1. git checkout master - Change the working branch of your source to master.

  2. npm install - Install any npm dependencies from the master package.json were not captured in your source.

  3. Manually increment the package.json version number to the desired semantic version (patch, minor, major) and save the file.

  4. npm run predeploy - Build the scripts, styles, and markup of to the distribution folder with the new version number in the file.

  5. git checkout package.json - Undo the change made to the package.json file. This is temporary so that the next command can do it's work.

  6. npm version {{ patch, minor, or major }} - This will update the package.json and package-lock.json file, commit the change and tag the repo with the desired version.

  7. git push origin && git push origin {{ tag (version number with 'v' prepended to it) }} - Push changes and tag to the GitHub repository.

  8. npm publish - Publish the package to the npm registery. This will also run npm run publish which executes a script that will take the distribution directory and push it to the GitHub Pages branch for the static site documentation.

The main scripts above utilize the following scripts for complete their tasks. All of these scripts can all be run individually.

Script Description
Build (HTML)
npm run build This runs uses Slm Lang to compile pages in the src/views/ directory to dist/. There are special strings that will compile files as markdown or pre-rendered code in the build process. The string md{{ path/to/markdown.md }} will compile the path as markdown using Node Markdown. The string code{{ path/to/code.slm }} will compile the path as pre-rendered code using the Slm Lang compiler.
npm run build:watch This runs nodemon to watch for changes on src/views/ and run the build npm script.
BrowserSync
npm run sync This starts a BrowserSync server that proxies the Express application server. Configuration can be found in the npm script command.
JavaScript
npm run scripts This runs Rollup.js on JavaScript dependencies of the Patterns and src/js/ directories. Configuration can be found in the config/rollup.js file.
npm run scripts:watch This runs Rollup.js in watch mode to detect changes in all JavaScript files in the src/ directory and compiles the scripts accordingly.
Styles
npm run styles This runs all of the styles: scripts below.
npm run styles:variables This converts the JSON configuration the config/variables.js into SASS and writes it to src/styles/config/_variables.scss.
npm run styles:sass This uses Node Sass which compiles each module in the config/styles.js file.
npm run styles:postcss This uses PostCSS on to process each style module. PostCSS is configured by the config/postcss.js file.
npm run styles:watch This uses nodemon to watch for changes on all Sass files in the src/ directory and runs the styles script.
SVGs
npm run svgs This runs all of the svgs: scripts below.
npm run svgs:optimize This uses svgo to optimize SVG files in the src/svg/ directory and write them to the dist/svg/ directory. Configuration can be found in the npm script command.
npm run svgs:symbol This uses svgstore to build an SVG symbol from the optimized SVGs in the dist/svg/ directory. Configuration can be found in the npm script command.
npm run svgs:watch This uses nodemon to watch for changes on all SVG files in the src/svg/ directory and runs the svgs npm script.
Design
npm run design:sketch This uses the HTML Sketch App CLI to export all of the patterns in the dist/sketch.html to “Almost Sketch Files” to be integrated into Sketch using the HTML Sketch Plugin. Configuration can be found in the npm script command.

All scripts can be previewed in the package.json file.

The most important changes developers may need to make are to files within two directories: The src/ directory, which includes all of the pattern source including scripts, styles, and template source, and the config/ directory, which includes all of the configuration for the different node libraries and global variables for the Patterns.

Every Pattern is developed with Style, JavaScript, and Markup dependencies bundled together so they can all be exported and imported independently of the rest of the Patterns.

src/{{ pattern type }}/{{ name }}/{{ name }}.{{ extension }}

For example, all of the relevant Accordion Component dependencies live in:

src/component/accordion/accordion.slm // Markup
src/component/accordion/accordion.js // JavaScript
src/component/accordion/_accordion.scss // Styling
src/component/accordion/accordion.md // Documentation

Style Guide

JavaScript

JavaScript is written as ES6 modules that conform to a standard set by set by Rollup.js and linted by ESLint using the Google Standard. Definitions can be found in the package.json file.

If a Pattern requires targeting DOM elements by a selector, it is better to use data attributes with “js”; data-js=”accordion” or data-js=”toggle”. While using classes or ids as targets is less preferable, if it is required, it must have a “js” prefix in the name to avoid confusion: “.js-” or “#js-”.

Aria Attributes

The same principle applies to aria attributes. An example includes aria-controls which is typically set to a button element that toggles another element. It is easier to read id="aria-c-{{ element name }}" on the target element name and understand that it is influenced by another accessible control element. In this case the toggling control would have the aria-controls attribute set as "aria-c-{{ element name }}".

Styles

Styles are written accordion to a modified BEMIT standard:

.c-accordion {...}
.c-accordion--type {...}
.c-accordion__child-element {...}

Prefixes: .c- = components, .o- = objects. There are no prefixes for elements and utilities.

Templates source is written using slm-lang. Every Element, Component, and Object needs its dependant markup documented in a slm-lang template of the same name. For example, the Accordion Component template would be src/components/accordion/accordion.slm.

Documentation

Documentation is written in Markdown. When you visit a pattern in the browser, the page looks for a Markdown file that maps to the Pattern’s template source path in the dist/ directory. For example, with the Accordion Component, the src/components/accordion/accordion.slm is the template source. The corresponding documentation should live in dist/components/accordion/accordion.md. When a user visits the /accordion page, the page looks for dist/components/accordion/accordion.md and renders the documentation in the browser.

All of the Patterns source is organized into four directories: elements, components, objects, and utilities, according to the Patterns naming convention.

Elements

Elements are the smallest building blocks and include colors, icons, buttons, links, layouts, and more. They can be seen within Components and Objects. They are often customized default HTML tags (<button>, <table>, <ul>, <a>, etc.). They require smaller amounts of markup and styling to customize.

Components

Components are smaller patterns that require more complex markup and styling than elements. Often, they include multiple elements such as buttons, lists, links, etc.. Component CSS classes are denoted with the .c- prefix.

Objects

Objects are the most complex patterns and require a great deal of custom styling and markup to function. They can be global elements (<footer>) or appear only in certain views. Object CSS classes are denoted with the .o- prefix.

Utilities

Utilities are reusable single-attribute styles used to customize markup so that fewer patterns need to be written. They are not tied to any element, component, or object, but they can help override styling in certain contexts and build views more efficiently. These Patterns use the Tailwind Framework. Refer to the Tailwind Docs and Tailwind configuration file for details on available modules and usage.