Herman 5.0.0-beta.0

Exporting Styles to JSON

While many UX patterns will be rendered as HTML components, there are several abstract style patterns – like color-palettes and font-specimens – that never appear as components in the application.

Herman provides several annotations to help visualize these abstract patterns, but they require access to the raw Sass data. We do that using Sass maps (key:value object variables) and the export mixin to generate JSON out of Sass variables.

See the sass.jsonFile configuration to ensure that Herman has access to your exported Sass data.

Example

scss
@use 'utilities';

utilities.$herman: (
  'colors': (
    'brand-colors': (
      'brand-orange': #c75000,
      'brand-blue': #0d7fa5,
    ),
  ),
);

@include utilities.export(utilities.$herman);
css compiled
/*! json-encode: {"colors": {"brand-colors": {"brand-orange": "#c75000", "brand-blue": "#0d7fa5"}}} */

Related

@mixin export()

$herman

scss
$herman: () !default;

Use the $herman map variable to collect and organize color, font, size, and ratio values for export.

The $herman map should be structured with top-level keys for each type of data, and nested maps of the individual items to preview. Use the add mixin to automatically populate fonts, colors, sizes, and ratios from existing maps – or construct your $herman map by hand, following these guidelines…

Map structure

Each type of preview value should be nested under a key that describes what type of data is being stored:

$herman: (
  'colors': (
    /* color maps */
  ),
  'sizes': (
    /* size maps */
  ),
  'ratios': (
    /* ratio maps */
  ),
  'fonts': (
    /* font maps */
  ),
);

Colors

Each color has an access name and value. The key will be used to identify the correct data for a given color-palette, and the data includes color name:value pairs, both in string format.

'brand-colors': (
  'brand-orange': #c75000,
  'brand-blue': #0d7fa5,
)

Color values can be in any valid web-color format – hex, hsl/a, rgba/a, etc.

Sizes & Ratios

Size and ratio data is similar to colors, organized into top-level groups that may contain one or more name:value pairs:

'font-ratios': (
  'line-height': 1.4,
  'minor-seventh': 16/9,
),
'text-sizes': (
  'root': 18px,
  'large': calc(1rem + 1.5vw),
)

Ratio values can be in any valid number, and size values should be valid CSS lengths.

Fonts

Each font should have a top-level key of its own, since font-previews display a single font at a time. The data map accepts:

  • name: how the font should be referenced in CSS (if omitted, defaults to top-level key)
  • stack: optional string or list of font-stack fallbacks
  • source: link to more information on the font, or typekit/googlefonts as useful
  • formats: font format (or space-separated list of font formats) for locally-hosted fonts – valid format options are ttf, otf, woff, woff2, svg, svgz, and eot
  • <variant>: describe any number of relative paths to locally-hosted font-files, or embedded data:... font strings per variant (e.g. normal, bold italic, etc.). Multi-word variants can be space-separated or comma-separated (e.g. bold italic or bold, italic or bold,italic), and non-standard variants are also accepted (e.g. extra-bold, thin, light, etc.). Optionally, the value can also be a nested object with the following variant-specific keys:
    • path: variant-specific relative path to locally-hosted font-files
    • local: font name (or space-separated list of font names) used to look for local user fonts
    • svgid: optional suffix value for local SVG font src, e.g. font-file.svg#svgid (if omitted, defaults to name)
    • <format>: describe any number of relative paths to locally-hosted font-files, or embedded data:... font strings per format (e.g. ttf, otf, woff2, etc.)
'body-font': (
  'name': 'Source Sans Pro',
  'stack': ('Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'),
  'formats': 'woff' 'woff2' 'ttf',
  'normal': 'sans/sourcesanspro-regular-webfont',
  'italic': 'sans/sourcesanspro-italic-webfont',
  'bold': (
    'path': 'sans/sourcesanspro-bold-webfont',
    'local': 'source-sans-pro-bold',
    'ttf': 'sans-ttf/sourcesanspro-bold-webfont',
    'woff': 'data:application/x-font-woff;charset=utf-8;base64...',
  ),
)

Example

scss sample map structure
@use 'utilities';

utilities.$herman: (
  'colors': (
    'brand-colors': (
      'brand-orange': '#c75000',
      'brand-blue': '#0d7fa5',
    ),
    'status-colors': (
      'go': '#657e1b',
      'yield': '#c75000',
    ),
  ),
  'fonts': (
    'body-font': (
      'name': 'Source Sans Pro',
      'stack': ('Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'),
      'formats': 'woff' 'woff2' 'ttf',
      'normal': 'sans/sourcesanspro-regular-webfont',
      'italic': 'sans/sourcesanspro-italic-webfont',
      'bold': (
        'path': 'sans/sourcesanspro-bold-webfont',
        'local': 'source-sans-pro-bold',
        'ttf': 'sans-ttf/sourcesanspro-bold-webfont',
        'woff': 'data:application/x-font-woff;charset=utf-8;base64...',
      ),
    ),
  ),
  'sizes': (
    'text-sizes': (
      'root': '18px',
      'large': 'calc(1rem + 1.5vw)',
    ),
  ),
);

Used By

@mixin add()

@mixin export()

Encode a Sass map as a JSON-ready string, and print to CSS output as a persistent comment.

Since 4.0.0:

Name changed from herman-export

Parameters

$map: $herman (map)

Map to be encoded for JSON exporting

Example

scss
@use 'utilities';

// Export to JSON
@include utilities.export;
css compiled
/*! json-encode: {"colors": {"brand-colors": {"brand-orange": "hsl(24deg, 100%, 39%)", "brand-blue": "hsl(195deg, 85%, 35%)", "brand-pink": "#aa0e5c"}, "neutral-colors": {"light-gray": "#dedede", "gray": "#555b5e", "contrast-light": "#fff", "contrast-dark": "#3b4042"}, "theme-colors": {"theme-dark": "hsl(195deg, 85%, 35%)", "theme-light": "#cfe5ed", "background": "#fff", "text": "#3b4042", "text-light": "#555b5e", "action": "#b81e6c", "focus": "hsl(195deg, 85%, 35%)", "underline": "#edc7da", "border": "#555b5e", "border-light": "#dedede", "shadow": "rgba(85, 91, 94, 0.5)", "callout": "#cfe5ed", "slight": "#fafcfd", "code": "hsl(195deg, 85%, 35%)", "code-shadow": "rgba(13, 127, 165, 0.2)"}, "hljs-colors": {"hljs-comment": "#93a1a1", "hljs-green": "#859900", "hljs-cyan": "#2aa198", "hljs-blue": "#268bd2", "hljs-yellow": "#b58900", "hljs-orange": "#cb4b16", "hljs-red": "#dc322f", "hljs-formula": "#eee8d5"}, "demo-colors": {"brand-blue": "hsl(195deg, 85%, 35%)", "brand-pink": "hsl(330deg, 85%, 48%)"}, "demo-noncolors": {"light-gray": "#dedede", "gray": "#555b5e", "contrast-dark": "#3b4042"}}, "ratios": {"text-ratios": {"line-height": 1.4}, "demo-ratios": {"line-height": 1.4}}, "sizes": {"root-sizes": {"root": "18px", "responsive": "calc(1em + 0.125vw)", "large": "calc(1rem + 0.5vw)", "small": "0.9rem"}, "text-sizes": {"reset": "1rem", "h1": "calc(1rem + 2vw)", "h2": "calc(1rem + 1vw)", "h3": "calc(1rem + 0.5vw)", "quote": "calc(1rem + 0.5vw)", "code": "0.9rem", "footer": "0.9rem", "search": "0.9rem"}, "spacing-sizes": {"rhythm": "1.4rem", "gutter": "1.4rem", "gutter-plus": "2.1rem", "double-gutter": "2.8rem", "triple-gutter": "4.2rem", "flex-gutter": "calc(0.7rem + 2.5vw)", "spacer": "calc(4.2rem + 2.5vw)", "gutter-minus": "1.05rem", "shim": "0.7rem", "half-shim": "0.35rem", "quarter-shim": "0.175rem"}, "pattern-sizes": {"nav-underline": "4px", "nav-icon": "28px", "arrow-border": "8px", "arrow-depth": "0.7rem", "arrow-side": "1.4rem", "font-preview": "24em", "specimen-aa": "4.2rem", "color-preview": "16em", "color-swatch": "5.6rem", "footer-logo": "2.8rem"}, "layout-sizes": {"page": "50rem", "item-break": "40em", "page-break": "50em", "nav-break": "65em"}, "demo-sizes-text": {"root": "18px", "responsive": "calc(1.5em + 1vw)", "xlarge": "3rem"}, "demo-sizes-theme": {"icon": "1rem", "card": "30vw", "quote": "50%", "outline": "thin", "border": "medium", "separator": "thick"}, "demo-sizes-large": {"box": "20em", "page": "75ch"}}, "fonts": {"sans": {"name": "Source Sans Pro", "source": "https://fonts.google.com/specimen/Source+Sans+Pro", "stack": ["Source Sans Pro", "Helvetica Neue", "Helvetica", "Arial", "sans-serif"]}, "code": {"name": "Source Code Pro", "source": "https://fonts.google.com/specimen/Source+Code+Pro", "stack": ["Source Code Pro", "Consolas", "Menlo", "Monaco", "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", "monospace", "sans-serif"]}, "demo-cdn": {"name": "Source Code Pro", "source": "https://fonts.google.com/specimen/Source+Code+Pro", "stack": ["Consolas", "Menlo", "Courier New", "monospace", "sans-serif"]}, "demo-local": {"name": "rockingham", "normal": {"path": "rockingham/rockingham-regular-webfont", "local": "rockingham-regular-webfont"}, "bold": "rockingham/rockingham-bold-webfont", "italic": "rockingham/rockingham-italic-webfont", "bold italic": "rockingham/rockingham-bolditalic-webfont", "stack": "fantasy", "formats": ["woff2", "woff", "ttf"]}}} */

Requires

@function encode()

@mixin add()

Add a map of colors, fonts, sizes, ratios, etc to the $herman map for JSON-export, converting values to JSON-ready strings.

Since 4.0.0:

Name changed from herman-add

Since 4.1.0:

Data supplied to utilities.add() is deeply merged instead of overridden

Since 5.0.0:

No longer accepts map-compile arguments, since there is not an obvious default between running compilation on keys vs values. Use each-value or each-key to handle compilations manually.

Parameters & Output

$type: (String)

The type of map being added, e.g. colors, fonts, sizes, or ratios.

$key: (String)

A key name for accessing this data in JSON – should match the variable name, unless key is otherwise set in the @font/@colors/@ratios/@sizes annotation

$map: (Map)

A map of name/value pairs

$args…: (Arglist)

A function to use for compiling values before export, and any additional arguments for the function

{CSS output} (code block)

Updated $herman map, ready for JSON export

Example

scss
@use 'sass:meta';
@use '~accoutrement/sass/tools';
@use 'utilities';

utilities.$herman: ();
$brand-colors: (
  'brand-blue': hsl(195, 85%, 35%),
  'light-gray': '#brand-blue' ('tint': 80%, 'desaturate': 80%),
);
$brand-compiled: utilities.each-key(
  $brand-colors,
  meta.get-function('color', $module: 'tools'),
);
@include utilities.add('colors', 'brand-colors', $brand-compiled);

@each $key, $value in utilities.$herman {
/* #{$key}: #{meta.inspect($value)} */
}
css compiled
/* colors: ("brand-colors": ("brand-blue": hsl(195deg, 85%, 35%), "light-gray": #dedede)) */

Requires

$plural-types (map) [private]

@function each-value()

Pass the values of any map through a given function (with optional arguments) and return the compiled map. This is used by add, but can also be accessed directly.

Since 4.0.0:

Name changed from herman-map-compile to compile

Since 5.0.0:

Name changed from compile to each-value

Parameters & Return

$map: (Map)

A sass map with values that need to be compiled, by running each value through a given function.

$function: (String | Function)

The function (or function name) to use in compiling values, such as Accoutrement color and size functions

$args…: (Arglist)

Pass in any additional arguments for the function

@return (String | Any)

An updated map, with values compiled by a third-party function, and converted to json-ready strings

@function each-key()

Pass the keys of any map through a given function (with optional arguments) and return the compiled map. This is used by add, but can also be accessed directly.

Since 4.0.0:

Name changed from herman-map-compile to compile

Since 5.0.0:

Name changed from compile to each-value

Parameters & Return

$map: (Map)

A sass map with values that need to be compiled, by running each key through a given function.

$function: (String | Function)

The function (or function name) to use in compiling values, such as Accoutrement color and size functions

$args…: (Arglist)

Pass in any additional arguments for the function

@return (String | Any)

An updated map, with values compiled by a third-party function, and converted to json-ready strings

Example

scss
@use 'sass:meta';
@use '~accoutrement/sass/tools';
@use 'utilities';

$brand-colors: (
  'brand-orange': hsl(24, 100%, 39%),
  'brand-blue': hsl(195, 85%, 35%),
  'light-gray': 'brand-blue' ('tint': 80%, 'desaturate': 80%),
);
$compiled: utilities.each-key($brand-colors, meta.get-function('color', $module: 'tools'));

@each $key, $value in $compiled {
/* #{$key}: #{$value} */
}
css compiled
/* brand-orange: hsl(24deg, 100%, 39%) */
/* brand-blue: hsl(195deg, 85%, 35%) */
/* light-gray: #dedede */