JSPM

  • Created
  • Published
  • Downloads 123
  • Score
    100M100P100Q89232F
  • License MIT

Generate scss/sass from your design tokens schema (requires @cobalt-ui/cli)

Package Exports

  • @cobalt-ui/plugin-sass
  • @cobalt-ui/plugin-sass/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@cobalt-ui/plugin-sass) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@cobalt-ui/plugin-sass

Generate Sass output for Cobalt from design tokens.

Setup

npm i -D @cobalt-ui/plugin-sass
// tokens.config.mjs
import pluginSass from '@cobalt-ui/plugin-sass';

/** @type import('@cobalt-ui/core').Config */
export default {
  plugins: [
    pluginSass({
      /** set the filename inside outDir */
      filename: './index.scss',
      /** use indented syntax? (.sass format) */
      indentedSyntax: false,
      /** embed file tokens? */
      embedFiles: false,
      /** handle specific token types */
      transform(token, mode) {
        // Replace "sans-serif" with "Brand Sans" for font tokens
        if (token.$type === 'font') {
          return token.$value.replace('sans-serif', 'Brand Sans');
        }
      },
    }),
  ],
};

Usage

Single Tokens

Use the provided token() function to get a token by its ID (separated by dots):

@use '../tokens' as *; // update '../tokens' to match your location of tokens/index.scss

.heading {
  color: token('color.blue');
  font-size: token('typography.size.xxl');
}

Note that a function has a few advantages over plain Sass variables:

  • ✅ The name perfectly matches your schema (no guessing!)
  • ✅ You can dynamically pull values (which you can’t do with Sass variables)
  • ✅ Use the same function to access modes

Typography

As $type: "typography" tokens contain multiple values, you’ll need to use the typography() mixin instead:

@use '../tokens' as *;

.heading {
  @include typography('typography');

  font-size: token('typography.size.xxl');
}

Note that you can override any individual property so long as it comes after the mixin.

Modes

If you take advantage of modes in your tokens, you can pass a 2nd param into tokens() with a mode name:

@use '../tokens' as *;

.heading {
  color: token('color.blue');

  body[color-mode='dark'] & {
    color: token('color.blue', 'dark');
  }
}

⚠️ Note that modes are designed to gracefully fall back. So if a certain value isn’t defined on a mode, it will fall back to the default, rather than throwing an error.

List modes

To see which modes a token has defined, use the getModes() function which returns a list. This can be used to generate styles for specific modes:

@use '../tokens' as *;

@for $mode in listModes('color.blue') {
  [data-color-mode='#{$mode}'] {
    color: token('color.blue', $mode);
  }
}

Config

Embed Files

Say you have link tokens in your tokens.json:

{
  "icon": {
    "alert": {
      "$type": "link",
      "$value": "./icon/alert.svg"
    }
  }
}

By default, consuming those will print values as-is:

.icon-alert {
  background-image: token('icon.alert');
}

// Becomes …
.icon-alert {
  background-image: url('./icon/alert.svg');
}

In some scenarios this is preferable, but in others, this may result in too many requests and may result in degraded performance. You can set embedFiles: true to generate the following instead:

.icon-alert {
  background-image: token('icon.alert');
}

// Becomes …
.icon-alert {
  background-image: url('image/svg+xml;utf8,<svg …></svg>');
}

Read more

Transform

Inside plugin options, you can specify an optional transform() function:

/** @type import('@cobalt-ui/core').Config */
export default {
  plugins: [
    pluginSass({
      transform(token, mode) {
        const oldFont = 'sans-serif';
        const newFont = 'Custom Sans';
        if (token.$type === 'font') {
          return token.$value.map((value) => (value === oldFont ? newFont : value));
        }
      },
    }),
  ],
};

Your transform will only take place if you return a truthy value, otherwise the default transformer will take place.

Custom tokens

If you have your own custom token type, e.g. my-custom-type, you’ll have to handle it within transform():

/** @type import('@cobalt-ui/core').Config */
export default {
  plugins: [
    pluginSass({
      transform(token, mode) {
        switch (token.$type) {
          case 'my-custom-type': {
            return String(token.$value);
            break;
          }
        }
      },
    }),
  ],
};