npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@danske/sapphire-design-tokens

v41.1.0

Published

Design Tokens for the Sapphire Design System from Danske Bank A/S

Downloads

307

Readme

@danske/sapphire-design-tokens

Design tokens are atomic values like colors, sizes, border radius, transition descriptions etc. These are sometimes also called atoms, style properties, design variables, design constants. Each token represents a design decision.

We maintain these values as JSON and generate assets in different formats to be used in implementations of Sapphire (eg. css for web, json for iOS etc.). To achieve this we're using Style Dictionary.

Supported formats

  • CSS variables
  • javascript/es6 with TypeScript type declarations

Token types

A design token can be either global or semantic. You know a token type by its prefix which is one of these words, but this depends on the format. For example, in css variables we also add a sapphire prefix because of the global nature of css variables.

Global

Global tokens are the primitive values in our design language. The color palette, animation, typography, and dimension values are all recorded as global tokens. A global token is just a plain, context-agnostic name describing a value.

Examples:

  • CSS variables

    • --sapphire-global-color-dark-blue-100
    • --sapphire-global-size-generic-25
  • JS/TS

    • globalColorDarkBlue100
    • globalSizeGeneric25

Semantic

Semantic tokens relate to a specific context or abstraction. These help communicate the intended purpose of a global token. These are useful when a global token (ie. dark blue) will appear in multiple places (eg. button background color, link color etc.).

The value of semantic tokens should always be a reference to a global token.

Examples:

  • CSS variables

    • --sapphire-semantic-color-warning
    • --sapphire-semantic-size-radius-small
  • JS/TS

    • semanticColorTextPrimary
    • semanticSizeRadiusSmall

Development

Tokens are found in tokens/. All JSON files in this directory (and its subdirectories) will be processed by style-dictionary.

Each generated design tokens format is described in config.json. And each format is generated by a pipeline of transforms which can change both the name of each design token and the format of the value. Read more about transforms here.

style-dictionary recommends a certain structure to the JSON describing the tokens. Some transforms assume that structure.

We don't want to be restricted by style-dictionary's recommendation as it does not fully meet our needs. Therefore we wrote out little transform to allow us to nest things as we need them in our JSON files and still be compatible to what some of the built-in transforms expect.

JSON structure

Each JSON file should contain a root property which is one of global if it is a global token in tokens/global/, [semantic] for semantic tokens in tokens/semantic/. The value of this property should be any object that follows style-dictionary's recommendation. Though the most important are the first two layers there.

Aliasing

You can reference (alias) existing values by using the dot-notation object path (the fully articulated property name) in brackets. Note that this only applies to values; referencing a non-value property will cause unexpected results in your output.

Examples

  • tokens/global/colors.json
{
  "global": {
    "color": {
      "red": {
        "100": {
          "value": "hsl(355, 74.7%, 49.6%)"
        },
        "transparent": {
          "value": "hsla(353, 71%, 52%, 0.65)"
        }
      }
    }
  }
}
  • tokens/semantic/colors.json
{
  "semantic": {
    "color": {
      "background": {
        "action": {
          "primary": {
            "default": {
              "value": "{global.color.action.value}"
            },
            "hover": {
              "value": "{global.color.cyan.90.value}"
            },
            "focus": {
              "value": "{global.color.cyan.100.value}"
            },
            "down": {
              "value": "{global.color.cyan.100.value}"
            },
            "disabled": {
              "value": "{global.color.cyan.80.value}"
            }
          }
        }
      }
    }
  }
}

Responsive Tokens

A token can be defined to hold different values based on the breakpoints defined in the theme. Use the responsiveValue property as a sibling to the usual value which all tokens have.

The responsiveValue property must be an object where the keys are the breakpoint names and the values are the token's value for that breakpoint.

Each output format would deal with these responsive values differently.

In the css output: This will generate media queries which change the value of the css variable to the one defined for each size. References to other tokens are preserved.

In the ts-theme object output: This will have no effect, because the theme object only refers to the name of the css variable, not its value (which could change based on media queries).

In the js and json formats: The value of a token with responsiveValues will be an object which is a map from breakpoint name to the resolved value. This object will always have a base key which is the default value.

Examples

{
  "button": {
    "size": {
      "height": {
        "value": "{semantic.size.height.control.default.value}",
        "responsiveValue": {
          "s": "100", // you can also use hardcoded values, not only references
          "l": "{semantic.size.height.control.sm.value}"
          "m": "{semantic.size.height.control.lg.value}",
        }
      }
    }
  }
}

Breakpoints

The name and values of a theme's breakpoints should be defined as semantic tokens at semantic.size.breakpoint.

The keys in the object are the names of each breakpoint, which can be referenced in responsive tokens, and the values are pixel sizes representing the min width of the screen size.

Remember that these breakpoints are just regular tokens and they can be consumed like all other tokens are in each output.

Note on Media Queries

It is widely considered good practice to design with the smallest screen in view and define what happens as the screen size grows.

In CSS media queries this translates in the following principle: a css value outside a media query describes the UI from the smallest screen size and media queries targeting screen sizes based on "min-width" will overwrite the value as the screen size grows.

This means that if you want a token that has one value for mobile and one for large desktops you would do something like this:

{
  "button": {
    "size": {
      "height": {
        "value": "some-value-for-the-smallest-screens",
        "responsiveValue": {
          "m": "some-value-for-medium-screens-and-up"
        }
      }
    }
  }
}

Building

The build command (npm run build) consists of two parts:

  • build:tokens for generating tokens in different output formats
  • build:components for building the complimentary react components for showing tokens list.

Node.js v>12 is required for building.

Themes

This package can build multiple sets of tokens for each platform and format. One can add more tokens or overwrite a subset of the default tokens to create a completely new set of token exports. This is what it means to have a new theme in Sapphire.

The folder tokens/default/ contains the default theme, which is also the theme which all other themes can modify.

Therefore, a theme in @danske/sapphire-design-tokens is a standalone and complete set of tokens. Each token could have a value different than the same token in the default theme, but not necessarily. In fact, we forsee that most, if not all themes would only overwrite a minority of tokens from the default theme.

Creating a new theme

  1. Create a new folder in tokens/ with your theme's name which itself contains one or all three folders for each layers of tokens. The pattern is easy to observe in tokens/default/. Example: tokens/dark/global, tokens/dark/semantic
  2. Change the value of some of the tokens which you can find in tokens/default/ by creating a token in your theme with the same name but different value. It's a good idea to do this in json files that have the same name as those it overwrites from the default theme.
  3. Add any assets specific to your theme in assets/.
  4. Add your theme's source, assets and other details in themes.json. The source should refer to those json files with tokens specific to your theme. The basedOnSource should refer to those json files with tokens which the new theme extends/overwrites. The difference between source and basedOnSource is that if in source you overwrite a token from basedOnSource it won't be a build error. The assets are just copied over in the theme's build output. Example:
     {
       name: 'default-dark',
       source: ['tokens/default-dark/**/*.json'],
       basedOnSource: ['tokens/default/**/*.json'],
       assets: ['assets/fonts/'],
       cssClassName: 'sapphire-theme-default-dark',
       outputFolderName: 'default-dark'
     }
  5. Build the tokens as you normally would and check the output in build/themes/<your_theme-s_folder>/

Contrast themes

A theme can optionally be set up to be the "contrast" theme of another in themes.json. This will have an effect on the css outputted for that theme. More specifically, we generate a new selector defining the tokens for the contrast theme.

In practice, this means that the class name sapphire-theme-contrast can be used inside the DOM tree wrapped by the theme's class name. Everything under sapphire-theme-contrast will look like the contrast theme.

Example

The normal CSS output of a theme looks roughly like this:

.sapphire-theme-foo {
  // ... css variables for "foo" theme are defined here
}

If the foo theme is defined as the contrast theme of theme bar in themes.json it will instead generate something like this:

.sapphire-theme-foo {
  // ... css variables for "foo" theme are defined here
}

.sapphire-theme-foo .sapphire-theme-contrast {
  // ... css variables for "bar" theme are defined here
}

Which implies that you can simply import a theme and use its contrast from the same import without needing to know which pairs of contrast themes exist. And as a consequence, if you change the parent theme, the contrast would follow as well.

Caveats

There are a few caveats with this, but at the moment they don't hinder us:

  • If a pair of contrasting themes have different assets (fonts, images etc.) on which their respective tokens depend on, it will not work.
  • If a pair of contrasting themes have different responsive tokens they won't work.