@swiftsolve/rove-tokens 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +3 -3
- package/README.md +88 -17
- package/package.json +1 -2
- package/src/code-tokens.json +2 -1
- package/src/figma/variables.json +10 -0
- package/text-styles.css +1 -1
- package/tokens/motion.tokens.json +8 -0
- package/tokens.css +3 -1
package/DESIGN.md
CHANGED
|
@@ -64,7 +64,7 @@ Disabled controls use `--opacity-disabled`.
|
|
|
64
64
|
### Focus and motion
|
|
65
65
|
|
|
66
66
|
- Keyboard focus is `outline: var(--focus-outline)` with `outline-offset: var(--focus-offset)`. Rows flush with a card's edge draw it inside instead, with `--focus-inset`.
|
|
67
|
-
- Animate with `--ease-out` (or `--ease-in-out`) over `--duration-fast` or `--duration-normal`. A looping pulse uses `--ease-pulse`, which is symmetric, so it fades out and back in alike.
|
|
67
|
+
- Animate with `--ease-out` (or `--ease-in-out`) over `--duration-fast` or `--duration-normal`. A panel resizing to its content springs, with `var(--duration-spring) var(--ease-spring)`: it arrives within `--duration-normal`, and its slight overshoot settles after. A looping pulse uses `--ease-pulse`, which is symmetric, so it fades out and back in alike.
|
|
68
68
|
|
|
69
69
|
### Icons
|
|
70
70
|
|
|
@@ -106,7 +106,7 @@ Names and uses, from Figma. The values are in `tokens.css`; Dark and Light diffe
|
|
|
106
106
|
- **Layout:** `--rail-item-size` 38px (rail items), `--titlebar-height` 56px (title bar)
|
|
107
107
|
- **Cards:** `--card-padding` `var(--spacing-14)` (card inset), `--card-header-padding-y` `var(--card-padding)`, `--card-header-padding-x` `var(--card-padding)`, `--card-header-min-height` 42px (compact card header), `--card-header-height` 44px (card header), `--card-body-padding` `var(--card-padding)`, `--row-padding-y` 8px (data row, above and below)
|
|
108
108
|
- **Font weights:** `--weight-regular` 400, `--weight-medium` 500, `--weight-semibold` 600
|
|
109
|
-
- **Motion:** `--duration-fast` 140ms (hovers, small changes), `--duration-normal` 220ms (panels, page changes)
|
|
109
|
+
- **Motion:** `--duration-fast` 140ms (hovers, small changes), `--duration-normal` 220ms (panels, page changes), `--duration-spring` 450ms (a spring’s full run)
|
|
110
110
|
|
|
111
111
|
### Text styles
|
|
112
112
|
|
|
@@ -135,4 +135,4 @@ What Figma variables can't hold, from `src/code-tokens.json`.
|
|
|
135
135
|
|
|
136
136
|
- **Shadows:** `--shadow-panel`, `--shadow-raised`, `--shadow-popover`
|
|
137
137
|
- **Focus:** `--focus-outline`, `--focus-inset`
|
|
138
|
-
- **Motion:** `--ease-out`, `--ease-in-out`, `--ease-pulse`
|
|
138
|
+
- **Motion:** `--ease-out`, `--ease-in-out`, `--ease-pulse`, `--ease-spring`
|
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Tokens for Rove, straight from the Rove Design System in Figma.
|
|
|
12
12
|
[](https://github.com/swiftsolve/rove-tokens/actions/workflows/presentation.yml)
|
|
13
13
|
[](https://github.com/swiftsolve/rove-tokens/tags)
|
|
14
14
|
[](https://www.figma.com/design/NoICIoyhWNOya9tOnNfEhH/Rove-Design-System)
|
|
15
|
+
|
|
15
16
|
[](https://www.designtokens.org/tr/2025.10/format/)
|
|
16
17
|
[](https://styledictionary.com/)
|
|
17
18
|
[](#-contrast)
|
|
@@ -23,22 +24,57 @@ Tokens for Rove, straight from the Rove Design System in Figma.
|
|
|
23
24
|
[📐 DESIGN.md](DESIGN.md) ·
|
|
24
25
|
[💡 Rationale](docs/rationale.md)
|
|
25
26
|
|
|
27
|
+
[📖 Tokens Storybook](https://rove.swiftsolve.net/storybook/tokens/) ·
|
|
28
|
+
[🧱 Components Storybook](https://rove.swiftsolve.net/storybook/)
|
|
29
|
+
|
|
26
30
|
</div>
|
|
27
31
|
|
|
28
32
|
---
|
|
29
33
|
|
|
30
|
-
Figma is the source of truth
|
|
34
|
+
Figma is the source of truth. A [Figma plugin](figma-plugin/) exports its variables and text styles, and this package turns them into DTCG token files, and those into CSS with [Style Dictionary](https://styledictionary.com/).
|
|
31
35
|
|
|
32
36
|
> [!TIP]
|
|
33
37
|
> **Building Rove UI?** [`DESIGN.md`](DESIGN.md) says which token to use for what, with every value. It ships in the package, so coding agents in Rove can read it from `node_modules/@swiftsolve/rove-tokens/DESIGN.md`.
|
|
34
38
|
|
|
39
|
+
## ⚙️ How it works
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
%%{init: {"themeCSS": ".cluster-label { translate: 236px 0; }", "theme": "base", "themeVariables": {"fontFamily": "Inter, -apple-system, Segoe UI, Helvetica, Arial, sans-serif", "fontSize": "14px", "primaryColor": "#151618", "primaryTextColor": "#eeeeef", "primaryBorderColor": "#2b2c2f", "lineColor": "#8e8f93", "clusterBkg": "#0b0b0c", "clusterBorder": "#3a69d5", "titleColor": "#5b8cff", "dropShadow": "none"}}}%%
|
|
43
|
+
flowchart TD
|
|
44
|
+
figma("<b>Figma file</b><br/>variables, styles"):::source
|
|
45
|
+
exports("<b>src/figma/*.json</b><br/>Figma plugin"):::file
|
|
46
|
+
code("<b>src/code‑tokens.json</b><br/>shadows, easings"):::file
|
|
47
|
+
slides("<b>Slideshow</b><br/>npm run present"):::ship
|
|
48
|
+
|
|
49
|
+
subgraph build ["npm run build"]
|
|
50
|
+
dtcg("<b>tokens/</b><br/>figma‑to‑dtcg.mjs"):::file
|
|
51
|
+
css("<b>tokens.css</b><br/>Style Dictionary"):::file
|
|
52
|
+
textCss("<b>text-styles.css</b><br/>dtcg‑to‑text‑styles.mjs"):::file
|
|
53
|
+
design("<b>DESIGN.md</b><br/>token‑reference.mjs"):::file
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
pkg("<b>npm package</b><br/>for Rove"):::ship
|
|
57
|
+
storybook("<b>Storybook</b><br/>both themes"):::ship
|
|
58
|
+
|
|
59
|
+
figma --> exports & slides
|
|
60
|
+
exports & code --> dtcg
|
|
61
|
+
dtcg --> css & textCss & design
|
|
62
|
+
build --> pkg & storybook
|
|
63
|
+
|
|
64
|
+
classDef source fill:#3a69d5,stroke:#5b8cff,color:#ffffff
|
|
65
|
+
classDef file fill:#151618,stroke:#2b2c2f,color:#eeeeef
|
|
66
|
+
classDef ship fill:#20263a,stroke:#5b8cff,color:#eeeeef
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Under each file is what writes it: a script in `scripts/tokens/`, [Style Dictionary](https://styledictionary.com/) (run by `dtcg-to-css.mjs`), or the Figma plugin, which exports the file's variables and text styles. [What's where](#️-whats-where) has the details.
|
|
70
|
+
|
|
35
71
|
## 📦 Use
|
|
36
72
|
|
|
37
73
|
```bash
|
|
38
74
|
npm install @swiftsolve/rove-tokens
|
|
39
75
|
```
|
|
40
76
|
|
|
41
|
-
The package ships `tokens.css`, `text-styles.css` and `tokens/` built. You can also install straight from a version tag (`github:swiftsolve/rove-tokens#v1.
|
|
77
|
+
The package ships `tokens.css`, `text-styles.css` and `tokens/` built. You can also install straight from a version tag (`github:swiftsolve/rove-tokens#v1.1.0`); then npm builds them on install, which needs Node 22 (see `.nvmrc`).
|
|
42
78
|
|
|
43
79
|
```css
|
|
44
80
|
@import '@swiftsolve/rove-tokens/tokens.css';
|
|
@@ -47,6 +83,8 @@ The package ships `tokens.css`, `text-styles.css` and `tokens/` built. You can a
|
|
|
47
83
|
|
|
48
84
|
Dark values sit on `:root`, Light values on `:root.theme-light`. CSS names follow the Figma names: `bg/base` is `--bg-base`, `spacing/12` is `--spacing-12`.
|
|
49
85
|
|
|
86
|
+
Every colour lives once in the Palette collection (`neutral/850`, `blue/450`; higher numbers are darker; a see-through shade adds `-a` and its opacity, `neutral/850-a10`), and the Color tokens point at it. The Palette isn't in `tokens.css`: a token that points at a shade gets the shade's value there. Figma-only collections (Icon tone, Capability level) and variables without a code syntax aren't in `tokens.css` either.
|
|
87
|
+
|
|
50
88
|
Each Figma text style becomes four tokens: `--type-<style>-size`, `-weight`, `-line-height` (a unitless ratio) and `-letter-spacing` (in `em`). `Number/Display` gives `--type-number-display-size` and so on. A size bound to a variable comes through as that variable (`var(--font-size-3xl)`).
|
|
51
89
|
|
|
52
90
|
`text-styles.css` applies a style whole: `.type-heading-large` sets the font family and all four, plus the text case (Overline is uppercase). The classes set no colour and sit in `@layer components`, so Tailwind utilities on the same element still win.
|
|
@@ -71,19 +109,34 @@ The colours meet [WCAG 2.2](https://www.w3.org/TR/WCAG22/) level AA in both them
|
|
|
71
109
|
|
|
72
110
|
## 📖 Storybook
|
|
73
111
|
|
|
74
|
-
|
|
112
|
+
Two Storybooks are hosted on rove.swiftsolve.net:
|
|
113
|
+
|
|
114
|
+
- [**Rove Tokens**](https://rove.swiftsolve.net/storybook/tokens/): every token in both themes (colour, palette, type, spacing, radius, effects, motion and layout), built from this repo's `main`.
|
|
115
|
+
- [**Rove Components**](https://rove.swiftsolve.net/storybook/): the Rove app's UI library, built from the tokens.
|
|
116
|
+
|
|
117
|
+
To run Rove Tokens locally:
|
|
75
118
|
|
|
76
119
|
```bash
|
|
77
120
|
npm run storybook
|
|
78
121
|
```
|
|
79
122
|
|
|
80
|
-
It opens on <http://localhost:6007>; the Theme menu in the toolbar switches Dark and Light. The pages read the DTCG files in `tokens/` and are styled with `tokens.css`, so a new build shows up without editing them.
|
|
123
|
+
It opens on <http://localhost:6007>; the Theme menu in the toolbar switches Dark and Light. The pages read the DTCG files in `tokens/` and are styled with `tokens.css`, so a new build shows up without editing them.
|
|
124
|
+
|
|
125
|
+
## 🛠️ Scripts
|
|
126
|
+
|
|
127
|
+
| Script | What it does |
|
|
128
|
+
| --- | --- |
|
|
129
|
+
| `npm run build` | Figma export → DTCG → `tokens.css`, `text-styles.css` and the `DESIGN.md` reference. `npm install` and `npm publish` run it too. |
|
|
130
|
+
| `npm run storybook` | The Rove Tokens Storybook on port 6007 |
|
|
131
|
+
| `npm run build:storybook` | A static copy of it in `storybook-static/` |
|
|
132
|
+
| `npm run present` | Builds, then exports the Figma file's pages to the slideshow in `presentation/`. Needs `FIGMA_TOKEN` in `.env.local`. |
|
|
133
|
+
| `npm run present:publish` | Pushes that slideshow to GitHub Pages |
|
|
81
134
|
|
|
82
135
|
## 🔄 Update the tokens
|
|
83
136
|
|
|
84
137
|
1. Change the variables or text styles in Figma.
|
|
85
138
|
2. Export them to `src/figma/variables.json` and `src/figma/text-styles.json`, either with the plugin in `figma-plugin/` (Figma desktop: Plugins → Development → Import plugin from manifest; then **Export**) or by asking Claude to export them through the Figma connection.
|
|
86
|
-
3. Run `npm run build` (Node 22) and check `tokens.css`.
|
|
139
|
+
3. Run `npm run build` (Node 22) and check `tokens.css`. The build stops if a variable's code syntax doesn't match its name, or a DTCG reference doesn't resolve.
|
|
87
140
|
4. Commit the change.
|
|
88
141
|
|
|
89
142
|
## 🚀 Release
|
|
@@ -105,24 +158,42 @@ It opens on <http://localhost:6007>; the Theme menu in the toolbar switches Dark
|
|
|
105
158
|
|
|
106
159
|
## 🗂️ What's where
|
|
107
160
|
|
|
161
|
+
**From Figma**
|
|
162
|
+
|
|
108
163
|
| Path | What |
|
|
109
164
|
| --- | --- |
|
|
110
165
|
| `src/figma/variables.json` | Raw Figma export. Every variable with a Web code syntax becomes that CSS variable. |
|
|
111
166
|
| `src/figma/text-styles.json` | Raw export of the local text styles: font, size, weight, line height, letter spacing, text case (when set) and the variables bound to them. Each style becomes a `--type-*` group. |
|
|
112
|
-
| `figma-plugin/` |
|
|
167
|
+
| `figma-plugin/` | Rove Tokens Export, the Figma plugin that writes the two exports: every local variable by collection and mode, aliases kept, in the variables panel's order, and every local text style with the variables bound to it. It previews both files, then downloads them; it has no network access. |
|
|
113
168
|
| `src/code-tokens.json` | What Figma variables can't hold: font stacks for the font-family variables, shadows, easing curves and the CSS expressions built on variables (`--focus-outline`). `{figma/name}` pulls a Figma value in per theme. |
|
|
114
|
-
|
|
169
|
+
|
|
170
|
+
**Build**
|
|
171
|
+
|
|
172
|
+
| Path | What |
|
|
173
|
+
| --- | --- |
|
|
115
174
|
| `scripts/tokens/build.mjs` | `npm run build`: runs the steps below and writes `tokens.css` and `text-styles.css` at the package root, where the import paths point. |
|
|
116
|
-
| `scripts/tokens/dtcg.mjs` | Figma export → the DTCG files in `tokens/`, checking that every reference resolves in both themes. |
|
|
117
|
-
| `scripts/tokens/css.mjs` | DTCG files → `tokens.css`, with Style Dictionary and a `rove/css` format: Dark on `:root`, what differs in Light on `:root.theme-light`, each text style as four `--type-*` variables (letter spacing included). |
|
|
118
|
-
| `scripts/tokens/text-styles.mjs` | DTCG text styles → `text-styles.css`: a `.type-<style>` class per style that reads its `--type-*` variables. |
|
|
119
|
-
| `scripts/tokens/
|
|
120
|
-
| `
|
|
121
|
-
|
|
122
|
-
|
|
175
|
+
| `scripts/tokens/figma-to-dtcg.mjs` | Figma export → the DTCG files in `tokens/`, checking that every reference resolves in both themes. |
|
|
176
|
+
| `scripts/tokens/dtcg-to-css.mjs` | DTCG files → `tokens.css`, with Style Dictionary and a `rove/css` format: Dark on `:root`, what differs in Light on `:root.theme-light`, each text style as four `--type-*` variables (letter spacing included). |
|
|
177
|
+
| `scripts/tokens/dtcg-to-text-styles.mjs` | DTCG text styles → `text-styles.css`: a `.type-<style>` class per style that reads its `--type-*` variables. |
|
|
178
|
+
| `scripts/tokens/token-reference.mjs` | Figma export and `tokens.css` → the token reference in `DESIGN.md`: every token by name and Figma description, with values for the scales (spacing, radius, type, opacity) but not the colours, so nobody copies a hex. |
|
|
179
|
+
| `DESIGN.md` | How to build Rove UI with the tokens. The rules at the top are written by hand; the token reference below the marker line is generated by the build. |
|
|
180
|
+
|
|
181
|
+
**Storybook and slideshow**
|
|
182
|
+
|
|
183
|
+
| Path | What |
|
|
184
|
+
| --- | --- |
|
|
185
|
+
| `.storybook/` | The Rove Tokens Storybook's config, and the Inter, Questrial and Geist Mono files it bundles. |
|
|
123
186
|
| `stories/` | Its pages, one file per sidebar group. `tokens.js` reads the DTCG files. |
|
|
187
|
+
| `scripts/presentation/export.mjs` | `npm run present`: exports the Figma file's pages to `presentation/index.html`, a slideshow styled with the tokens. Needs `FIGMA_TOKEN` (a Figma personal access token, `file_content:read`) in `.env.local`. |
|
|
124
188
|
| `scripts/presentation/publish.mjs` | `npm run present:publish`: pushes the exported presentation to the `gh-pages` branch, which GitHub Pages serves at <https://swiftsolve.github.io/rove-tokens/>. Each publish replaces the last. |
|
|
125
|
-
| `.github/workflows/presentation.yml` | Runs the export and publish on every `v*` tag, or by hand. Needs the `FIGMA_TOKEN` repository secret. |
|
|
126
|
-
| `docs/rationale.md` | Why the values are what they are (contrast targets, theme choices). |
|
|
127
189
|
|
|
128
|
-
|
|
190
|
+
**Workflows and docs**
|
|
191
|
+
|
|
192
|
+
A release tag is the `v1.2.0`-style git tag that `npm version` creates and `git push --follow-tags` pushes (see [Release](#-release)).
|
|
193
|
+
|
|
194
|
+
| Path | What |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `.github/workflows/build.yml` | On each release tag, builds the tokens and checks `DESIGN.md` was rebuilt and committed. Run it by hand from Actions to check `main`. |
|
|
197
|
+
| `.github/workflows/publish.yml` | On each release tag, publishes that version to npm with trusted publishing, so the repo holds no npm token. |
|
|
198
|
+
| `.github/workflows/presentation.yml` | On each release tag, or by hand from Actions, exports the slideshow from Figma and publishes it. Needs the `FIGMA_TOKEN` repository secret. |
|
|
199
|
+
| `docs/rationale.md` | Why the values are what they are (contrast targets, theme choices). |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swiftsolve/rove-tokens",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Rove's design tokens, exported from the Rove Design System in Figma, as CSS and DTCG.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "node scripts/tokens/build.mjs",
|
|
26
26
|
"present": "npm run build && node scripts/presentation/export.mjs",
|
|
27
|
-
"present:open": "node scripts/presentation/open.mjs",
|
|
28
27
|
"present:publish": "node scripts/presentation/publish.mjs",
|
|
29
28
|
"prepare": "npm run build",
|
|
30
29
|
"storybook": "storybook dev -p 6007",
|
package/src/code-tokens.json
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
"--ease-out": "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
16
16
|
"--ease-in-out": "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
17
|
-
"--ease-pulse": "cubic-bezier(0.42, 0, 0.58, 1)"
|
|
17
|
+
"--ease-pulse": "cubic-bezier(0.42, 0, 0.58, 1)",
|
|
18
|
+
"--ease-spring": "linear(0, 0.1896, 0.4943, 0.7351, 0.8834, 0.9602, 0.9936, 1.0046, 1.0062, 1.0047, 1.0028, 1.0014, 1.0006, 1, 1)"
|
|
18
19
|
}
|
|
19
20
|
}
|
package/src/figma/variables.json
CHANGED
|
@@ -2072,6 +2072,16 @@
|
|
|
2072
2072
|
"values": {
|
|
2073
2073
|
"Value": 220
|
|
2074
2074
|
}
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
"name": "duration/spring",
|
|
2078
|
+
"collection": "Motion",
|
|
2079
|
+
"type": "FLOAT",
|
|
2080
|
+
"code": "var(--duration-spring)",
|
|
2081
|
+
"description": "A spring’s full run",
|
|
2082
|
+
"values": {
|
|
2083
|
+
"Value": 450
|
|
2084
|
+
}
|
|
2075
2085
|
}
|
|
2076
2086
|
]
|
|
2077
2087
|
}
|
package/text-styles.css
CHANGED
package/tokens.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* @swiftsolve/rove-tokens 1.
|
|
1
|
+
/* @swiftsolve/rove-tokens 1.2.0. Generated from Figma by scripts/tokens/build.mjs; do not edit. */
|
|
2
2
|
:root {
|
|
3
3
|
/* Color */
|
|
4
4
|
--bg-base: #0b0b0c; /* Backdrop */
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
/* Motion */
|
|
99
99
|
--duration-fast: 140ms; /* Hovers, small changes */
|
|
100
100
|
--duration-normal: 220ms; /* Panels, page changes */
|
|
101
|
+
--duration-spring: 450ms; /* A spring’s full run */
|
|
101
102
|
|
|
102
103
|
/* Code-only */
|
|
103
104
|
--shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.22), 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
109
110
|
--ease-pulse: cubic-bezier(0.42, 0, 0.58, 1);
|
|
110
111
|
--focus-inset: calc(-1 * var(--focus-ring-width));
|
|
112
|
+
--ease-spring: linear(0, 0.1896, 0.4943, 0.7351, 0.8834, 0.9602, 0.9936, 1.0046, 1.0062, 1.0047, 1.0028, 1.0014, 1.0006, 1, 1);
|
|
111
113
|
|
|
112
114
|
/* Type styles */
|
|
113
115
|
--type-heading-large-size: var(--font-size-2xl);
|