@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 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
  [![Slideshow](https://img.shields.io/github/actions/workflow/status/swiftsolve/rove-tokens/presentation.yml?label=slideshow&labelColor=17181b)](https://github.com/swiftsolve/rove-tokens/actions/workflows/presentation.yml)
13
13
  [![Version](https://img.shields.io/github/package-json/v/swiftsolve/rove-tokens?label=version&labelColor=17181b&color=5b8cff)](https://github.com/swiftsolve/rove-tokens/tags)
14
14
  [![Figma](https://img.shields.io/badge/Figma-source_of_truth-5b8cff?logo=figma&logoColor=white&labelColor=17181b)](https://www.figma.com/design/NoICIoyhWNOya9tOnNfEhH/Rove-Design-System)
15
+
15
16
  [![DTCG](https://img.shields.io/badge/DTCG-2025.10-5b8cff?labelColor=17181b)](https://www.designtokens.org/tr/2025.10/format/)
16
17
  [![Style Dictionary](https://img.shields.io/badge/Style_Dictionary-5-5b8cff?labelColor=17181b)](https://styledictionary.com/)
17
18
  [![WCAG](https://img.shields.io/badge/WCAG_2.2-AA-5b8cff?labelColor=17181b)](#-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; this package turns its variables and text styles into DTCG token files, and those into CSS with [Style Dictionary](https://styledictionary.com/).
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.0.0`); then npm builds them on install, which needs Node 22 (see `.nvmrc`).
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
- **Rove Tokens** is a Storybook of every token in both themes: colour, palette, type, spacing, radius, effects, motion and layout.
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. `npm run build:storybook` writes a static copy to `storybook-static/`.
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`. It writes the DTCG files, then generates `tokens.css` from them with Style Dictionary and `text-styles.css` from the text styles, then rewrites the token reference at the end of `DESIGN.md`. The build stops if a variable's code syntax doesn't match its name, or a DTCG reference doesn't resolve.
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/` | The Figma plugin that writes the two exports. |
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
- | `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. |
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/design.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. |
120
- | `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`. |
121
- | `scripts/presentation/open.mjs` | `npm run present:open`: opens the exported presentation in your browser. |
122
- | `.storybook/` | The Rove Tokens Storybook's config, and the Inter and Questrial files it serves. |
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
- 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.
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.1.0",
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",
@@ -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
  }
@@ -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
@@ -1,4 +1,4 @@
1
- /* @swiftsolve/rove-tokens 1.1.0. Generated from Figma by scripts/tokens/build.mjs; do not edit. */
1
+ /* @swiftsolve/rove-tokens 1.2.0. Generated from Figma by scripts/tokens/build.mjs; do not edit. */
2
2
 
3
3
  @layer components {
4
4
  /* Page titles, the wordmark. */
@@ -15,6 +15,14 @@
15
15
  "unit": "ms"
16
16
  },
17
17
  "$description": "Panels, page changes"
18
+ },
19
+ "spring": {
20
+ "$type": "duration",
21
+ "$value": {
22
+ "value": 450,
23
+ "unit": "ms"
24
+ },
25
+ "$description": "A spring’s full run"
18
26
  }
19
27
  }
20
28
  }
package/tokens.css CHANGED
@@ -1,4 +1,4 @@
1
- /* @swiftsolve/rove-tokens 1.1.0. Generated from Figma by scripts/tokens/build.mjs; do not edit. */
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);