# @lmc-eu/spirit-design-tokens

> Design tokens for Spirit Design System.

⚠️ Spirit design tokens are managed with and generated by [Supernova][supernova]. DO NOT EDIT MANUALLY!

## Table of Contents

1. [Available Design Tokens](#available-design-tokens)
   1. [Global Tokens](#global-tokens)
   2. [Theme Tokens](#theme-tokens)
2. [Themes](#themes)
3. [Install](#install)
4. [Basic Usage](#basic-usage)
   1. [In Sass](#in-sass)
   2. [In JavaScript](#in-javascript)
5. [Rebranding Spirit](#rebranding-spirit)
   1. [Using Your Design Tokens with TypeScript](#using-your-design-tokens-with-typescript)
6. [FAQ](#faq)
7. [License](#license)

## Available Design Tokens

Technically, design tokens are split into two categories: Global tokens and Theme tokens.
Global tokens are shared independently on themes, while the theme tokens are specific to a particular theme.

They are all managed in our [Figma][spirit-figma] and exported to our [Supernova workspace][spirit-supernova].

⚠️ All content in `src` is generated by Supernova and should not be edited manually.

The `scss` directory contains `@tokens.scss` linking all available tokens (including both global and theme tokens).

### Global Tokens

The category consists of these groups:

- 🖼 Borders
- 🖌️ Gradients
- ⚙️ Other
- 🎱 Radii
- 🏖️ Shadows
- 📏️ Spacing
- 🔡 Typography

These tokens are shared globally and independently on themes.

### Theme Tokens

Currently, only tokens in the 🎨 Colors group are themeable.

## Themes

You can find the list of the themes in the `@themes` file and in the `scss/themes` directory.
Each theme has its own directory with the same set of design tokens, but with different values.

As of now, we support two light-mode color themes:

- Light Default (listed first in `@themes`, i.e. the default theme)
- Light on Brand

Both themes can be used anywhere on the same page and combined as needed.

### Using Themes

The `scss` directory contains `@themes.scss` linking all available themes as Sass variables.
From the technical point of view, the theming is based on CSS variables. **However, this package
does not provide the CSS variables directly at the moment.** Instead, they are generated from
the `@themes` file in the [`spirit-web`][web-docs] package.

## Install

🙋🏻‍♂️ **Hold on! Do you already use [`spirit-web`][web-docs]?** Then you don't need to
install this package because `spirit-design-tokens` is installed automatically
as a dependency of `spirit-web`.

If you want to use just `spirit-design-tokens` alone in your project, run:

```shell
yarn add @lmc-eu/spirit-design-tokens
```

or

```shell
npm install --save @lmc-eu/spirit-design-tokens
```

## Basic Usage

### In Sass

Sass (with the SCSS syntax) is the primary language for styling Spirit components.

The best way to use the design tokens is to load their path in Sass:

```shell
sass --load-path=node_modules/@lmc-eu/spirit-design-tokens/scss my-styles.scss
```

Or integrate them into your build system:

<details>
<summary>Vite example:</summary>

```javascript
// vite.config.js

// …
import { defineConfig } from 'vite';

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        includePaths: [path.resolve(__dirname, 'node_modules/@lmc-eu/spirit-design-tokens/scss')],
      },
    },
  },
});
// …
```

</details>
<details>
<summary>Webpack example with <code>sass-loader</code>:</summary>

```javascript
// webpack.config.js

// …
module: {
  rules: [
    {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            sassOptions: {
              includePaths: [
                path.resolve(__dirname, 'node_modules'),
                path.resolve(__dirname, 'node_modules/@lmc-eu/spirit-design-tokens/scss'),
              ],
            },
          },
        },
      ],
    },
  ];
}
// …
```

</details>

#### Using the `sass-embedded` Library

If you're using `sass-embedded`, you can specify the API as `legacy`, `modern`, or `modern-compiler`. More information can be found in [sass documentation][sass-embedded].

We recommend using the `modern-compiler` option.
Please note that this change also requires updating `includePaths` to `loadPaths`.

<details>
<summary>Webpack and <code>sass-embedded</code>:</summary>

```javascript
// webpack.config.js

// …
module: {
  rules: [
    {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            api: 'modern-compiler',
            sassOptions: {
              loadPaths: [
                path.resolve(__dirname, 'node_modules'),
                path.resolve(__dirname, 'node_modules/@lmc-eu/spirit-design-tokens/scss'),
              ],
            },
          },
        },
      ],
    },
  ];
}
// …
```

</details>

The [`spirit-web`][web-docs] package or your own components can simply reach token values like this:

```scss
@use 'sass:map';
@use '@tokens' as tokens;

.MyComponentThatMightGoToSpiritInFuture {
  margin-bottom: tokens.$space-300;
  font-family: map.get(tokens.$body-medium-regular, mobile, font-family);
  color: tokens.$text-primary;
}
```

For your components you can also load the token files directly:

```scss
@use 'node_modules/@lmc-eu/spirit-design-tokens/scss/@tokens' as tokens;
```

### In JavaScript

Additionally, the design tokens are also provided as a JavaScript object.

```js
import * as SpiritDesignTokens from '@lmc-eu/spirit-design-tokens';

const desktopBreakpoint = SpiritDesignTokens.breakpoints.desktop;
```

The structure is the same as in Sass.

## Rebranding Spirit

The system is designed to be easily rebranded. To do so, you need to provide
your own design tokens and use `@tokens` and `@themes` files. Then forward your tokens
to these files and set the [correct load path](#basic-usage) for your project.

Your tokens should contain the same structure as the Spirit tokens. The simplest
way to do this is to have the same structure in your Figma file and export it
using Supernova. If that's not possible, you can copy our tokens and adjust their values
to your needs. You can also add new tokens required by your design system.

### Using Your Design Tokens with TypeScript

If you want to use your own set of design tokens instead of the default ones provided by `@lmc-eu/spirit-design-tokens`,
you need to adjust your project's TypeScript configuration and your build system settings to correctly resolve imports.

Add the following paths to your `tsconfig.json`:

```json
{
  "compilerOptions": {
    "paths": {
      "@lmc-eu/spirit-design-tokens": ["path-to-your-design-tokens-directory-or-package/js"],
      "@lmc-eu/spirit-design-tokens/*": ["path-to-your-design-tokens-directory-or-package/*"]
    }
  }
}
```

Then, adjust your build system settings to correctly resolve imports.
You can see examples for different build systems below:

<details>
<summary>Webpack example</summary>
Please modify your <code>webpack.config.js</code>:

```javascript
import path from 'path';

export default config({
  resolve: {
    alias: {
      '@lmc-eu/spirit-design-tokens': path.resolve(__dirname, 'path-to-your-design-tokens-directory-or-package'),
    },
  },
});
```

</details>

<details>
<summary>Vite example</summary>
Please modify <code>vite.config.ts</code>:

```javascript
import { defineConfig } from 'vite';
import path from 'path';

export default defineConfig({
  resolve: {
    alias: {
      '@lmc-eu/spirit-design-tokens': path.resolve(__dirname, 'path-to-your-design-tokens-directory-or-package'),
    },
  },
});
```

</details>

<details>
<summary>Next.js example</summary>
Please modify <code>next.config.ts</code>:

```javascript
import type, { NextConfig } from "next";
import path, {dirname} from "path";
import { fileURLToPath } from "url";

const pathDir = dirname(fileURLToPath(import.meta.url));

const nextConfig: NextConfig = {
  transpilePackages: ['@lmc-eu/spirit-web-react'],
  reactStrictMode: true,
  sassOptions: {
    implementation: 'sass-embedded',
    includePaths: [
      path.join(pathDir, './node_modules'),
      path.join(pathDir, 'path-to-your-design-tokens-directory-or-package/scss'),
    ],
  },
  webpack: (config) => {
    config.resolve.alias['@lmc-eu/spirit-design-tokens'] = path.resolve('path-to-your-design-tokens-directory-or-package');
    return config;
  },
};

export default nextConfig;
```

</details>

## FAQ

<details>
<summary>
Why do I need to rename <code>@tokens</code> to <code>tokens</code> when @using?
</summary>

Because @using the `@tokens` module without renaming would produce an error:

```log
Error: Invalid Sass identifier "@tokens"
  ╷
1 │ @use '@tokens';
  │ ^^^^^^^^^^^^^^
```

</details>

<details>
<summary>Why is there the <code>@</code> prefix?</summary>

We prefix the `@tokens.scss` file with `@` to differentiate it from other Sass
files in the directory.

In order for developers to know the file behaves differently than usual Sass
partials, a `@` prefix is added to mark this behavior both in filesystem and
inside Sass files. As a result, it's clear why e.g. `@use 'tools'` refers to
a local file and `@use '@tokens'` does not. However, **it's only a naming
convention,** there is no special tooling or configuration for Sass partials
starting with `@`.

Imported module **needs to be renamed to be compatible with SCSS** syntax
when it's used later on. That's why `@use '@tokens' as tokens`.

Look at the following snippets and compare which one offers better
comprehensibility.

Without `@` prefix:

```scss
// _Button.scss

@use 'tools'; // Calls './_tools.scss'. You don't have to explain this to me.
@use 'tokens'; // Wait, this file doesn't exist… What's going on here? Is it
// an error?
```

With `@` prefix:

```scss
// _Button.scss

@use 'tools'; // Calls './_tools.scss'.
@use '@tokens' as tokens; // OK, './_@tokens.scss' is not here, but the at-sign
// prefix suggests a special behavior. Maybe I'll learn more in the docs?
```

</details>

<details>
<summary>How do I derive design tokens for my own design system?</summary>

<!--lint ignore no-emphasis-as-heading-->

**Creating a custom design system derived from Spirit? Great to hear that! 🎉**

While it's perfectly OK to develop custom components that may not find their way
back to Spirit, your design tokens need to **include all Spirit design tokens**
anyway, so all Spirit components you are going to reuse work correctly with your
brand.

Simply put, if you are going to build a design system based on Spirit:

1. copy and paste all design tokens from here,
2. alter their values to fit your needs,
3. feel free to add anything necessary on top of that,
4. use your design tokens in your code (and compile Spirit with them).

To make your Sass design tokens compatible with Spirit, don't forget to expose
them via Sass load path.

</details>

<details>
<summary>Do I need themes? And if so, how many?</summary>

You need at least one theme to define the default values for your design tokens.
If you want to support multiple themes, you can add more. The number of themes
is up to you and your design system requirements.

But remember, each theme should contain the same set of tokens, just with different
values. This way, you can switch between themes without changing your components.

</details>

## License

See the [LICENSE](LICENSE.md) file for information.

[spirit-figma]: https://www.figma.com/design/w9Ca4hvkuYLshsrHu1bYwT/
[spirit-supernova]: https://spirit.design/
[supernova]: https://spirit.supernova-docs.io
[web-docs]: https://github.com/lmc-eu/spirit-design-system/tree/main/packages/web#readme
[sass-embedded]: https://sass-lang.com/documentation/breaking-changes/legacy-js-api/#bundlers
