@swiftsolve/rove-tokens 1.0.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
 
@@ -74,7 +74,7 @@ Disabled controls use `--opacity-disabled`.
74
74
 
75
75
  ## Changing the design
76
76
 
77
- Figma is the source of truth. Change a token in the Rove Design System Figma file, export it with the plugin in `figma-plugin/` into `src/figma/`, then run `npm run build` (see the [README](README.md#update-the-tokens)). Don't edit `tokens.css`, `tokens/` or the values in `src/figma/` by hand. What Figma can't hold (shadows, layout, motion) lives in `src/code-tokens.json`.
77
+ Figma is the source of truth. Change a token in the Rove Design System Figma file, export it with the plugin in `figma-plugin/` into `src/figma/`, then run `npm run build` (see the [README](README.md#update-the-tokens)). Don't edit `tokens.css`, `tokens/` or the values in `src/figma/` by hand. What Figma can't hold (shadows, easing curves, the focus outline) lives in `src/code-tokens.json`.
78
78
 
79
79
  Everything below the next line is rewritten by `npm run build`; edit only above it.
80
80
 
@@ -101,8 +101,12 @@ Names and uses, from Figma. The values are in `tokens.css`; Dark and Light diffe
101
101
  - **Radius:** `--radius-xs` 5px, `--radius-sm` 8px, `--radius-md` 10px, `--radius-lg` 13px, `--radius-full` 999px
102
102
  - **Font sizes:** `--font-size-2xs` 10px, `--font-size-xs` 11px, `--font-size-sm` 12px, `--font-size-md` 13px, `--font-size-lg` 14px, `--font-size-xl` 15px (dialog titles), `--font-size-2xl` 17px, `--font-size-3xl` 28px
103
103
  - **Font families:** `--font-family-sans` Inter, `--font-family-numeric` Questrial
104
- - **Focus:** `--focus-offset` 2px (focus ring offset)
104
+ - **Focus:** `--focus-ring-width` 1px (focus ring stroke), `--focus-offset` 2px (focus ring offset)
105
105
  - **Opacity:** `--opacity-tint-xs` 8% (faintest tint), `--opacity-tint-sm` 10% (light tint), `--opacity-tint-md` 14% (tint), `--opacity-tint-lg` 22% (strong tint), `--opacity-tint-xl` 28% (strongest tint), `--opacity-high` 80% (nearly opaque), `--opacity-disabled` 40% (disabled controls)
106
+ - **Layout:** `--rail-item-size` 38px (rail items), `--titlebar-height` 56px (title bar)
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
+ - **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), `--duration-spring` 450ms (a spring’s full run)
106
110
 
107
111
  ### Text styles
108
112
 
@@ -130,8 +134,5 @@ Apply a style with its class from `text-styles.css`. Each class reads four varia
130
134
  What Figma variables can't hold, from `src/code-tokens.json`.
131
135
 
132
136
  - **Shadows:** `--shadow-panel`, `--shadow-raised`, `--shadow-popover`
133
- - **Focus:** `--focus-ring-width` 1px, `--focus-outline`, `--focus-inset`
134
- - **Layout:** `--titlebar-height` 56px, `--rail-item-size` 38px
135
- - **Cards:** `--card-padding` `var(--spacing-14)`, `--card-header-padding-y` `var(--card-padding)`, `--card-header-padding-x` `var(--card-padding)`, `--card-header-min-height` 42px, `--card-header-height` 44px, `--card-body-padding` `var(--card-padding)`, `--row-padding-y` 8px
136
- - **Motion:** `--ease-out`, `--ease-in-out`, `--ease-pulse`, `--duration-fast` 140ms, `--duration-normal` 220ms
137
- - **Font weights:** `--weight-regular` 400, `--weight-medium` 500, `--weight-semibold` 600
137
+ - **Focus:** `--focus-outline`, `--focus-inset`
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.
@@ -59,9 +97,9 @@ Each Figma text style becomes four tokens: `--type-<style>-size`, `-weight`, `-l
59
97
  | --- | --- |
60
98
  | `palette.tokens.json` | Every colour, once |
61
99
  | `color.dark.tokens.json`, `color.light.tokens.json` | The Color tokens in each theme, pointing at the palette (`{neutral.850}`) |
62
- | `spacing.tokens.json`, `typography.tokens.json`, `opacity.tokens.json` | The other Figma collections |
100
+ | `spacing.tokens.json`, `typography.tokens.json`, `opacity.tokens.json`, `layout.tokens.json`, `motion.tokens.json` | The other Figma collections |
63
101
  | `text-styles.tokens.json` | Each text style as a `typography` token |
64
- | `code.tokens.json` | The code-only tokens (shadows, motion, layout) |
102
+ | `code.tokens.json` | The code-only tokens (shadows, easing curves, the focus outline) |
65
103
 
66
104
  A theme is every file plus one of the two color files. Paths follow the Figma names (`bg/base` is `bg.base`). Tokens that other tokens point at but that aren't CSS variables (the palette, the shadow colours) are marked `"$extensions": { "net.swiftsolve.rove-tokens": { "css": false } }`. CSS-only expressions (`--focus-inset`, a `calc()`) aren't in them.
67
105
 
@@ -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. |
113
- | `src/code-tokens.json` | What Figma variables can't hold: font stacks for the font-family variables, shadows, layout constants, motion. `{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. |
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. |
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. |
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.0.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",
@@ -9,29 +9,12 @@
9
9
  "--shadow-raised": "0 12px 32px {shadow-color/raised}",
10
10
  "--shadow-popover": "0 2px 6px {shadow-color/popover-1}, 0 6px 16px {shadow-color/popover-2}",
11
11
 
12
- "--focus-ring-width": "1px",
13
12
  "--focus-outline": "var(--focus-ring-width) solid var(--focus-ring)",
14
13
  "--focus-inset": "calc(-1 * var(--focus-ring-width))",
15
14
 
16
- "--titlebar-height": "56px",
17
- "--rail-item-size": "38px",
18
-
19
- "--card-padding": "var(--spacing-14)",
20
- "--card-header-padding-y": "var(--card-padding)",
21
- "--card-header-padding-x": "var(--card-padding)",
22
- "--card-header-min-height": "42px",
23
- "--card-header-height": "44px",
24
- "--card-body-padding": "var(--card-padding)",
25
- "--row-padding-y": "8px",
26
-
27
15
  "--ease-out": "cubic-bezier(0.16, 1, 0.3, 1)",
28
16
  "--ease-in-out": "cubic-bezier(0.4, 0, 0.2, 1)",
29
17
  "--ease-pulse": "cubic-bezier(0.42, 0, 0.58, 1)",
30
- "--duration-fast": "140ms",
31
- "--duration-normal": "220ms",
32
-
33
- "--weight-regular": "400",
34
- "--weight-medium": "500",
35
- "--weight-semibold": "600"
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)"
36
19
  }
37
20
  }
@@ -56,6 +56,18 @@
56
56
  "modes": [
57
57
  "Value"
58
58
  ]
59
+ },
60
+ {
61
+ "name": "Layout",
62
+ "modes": [
63
+ "Value"
64
+ ]
65
+ },
66
+ {
67
+ "name": "Motion",
68
+ "modes": [
69
+ "Value"
70
+ ]
59
71
  }
60
72
  ],
61
73
  "variables": [
@@ -1902,6 +1914,174 @@
1902
1914
  "alias": "neutral/850-a2"
1903
1915
  }
1904
1916
  }
1917
+ },
1918
+ {
1919
+ "name": "titlebar/height",
1920
+ "collection": "Layout",
1921
+ "type": "FLOAT",
1922
+ "code": "var(--titlebar-height)",
1923
+ "description": "Title bar",
1924
+ "values": {
1925
+ "Value": 56
1926
+ }
1927
+ },
1928
+ {
1929
+ "name": "rail/item-size",
1930
+ "collection": "Layout",
1931
+ "type": "FLOAT",
1932
+ "code": "var(--rail-item-size)",
1933
+ "description": "Rail items",
1934
+ "values": {
1935
+ "Value": 38
1936
+ }
1937
+ },
1938
+ {
1939
+ "name": "card/padding",
1940
+ "collection": "Layout",
1941
+ "type": "FLOAT",
1942
+ "code": "var(--card-padding)",
1943
+ "description": "Card inset",
1944
+ "values": {
1945
+ "Value": {
1946
+ "alias": "spacing/14"
1947
+ }
1948
+ }
1949
+ },
1950
+ {
1951
+ "name": "card/header-padding-y",
1952
+ "collection": "Layout",
1953
+ "type": "FLOAT",
1954
+ "code": "var(--card-header-padding-y)",
1955
+ "description": "",
1956
+ "values": {
1957
+ "Value": {
1958
+ "alias": "card/padding"
1959
+ }
1960
+ }
1961
+ },
1962
+ {
1963
+ "name": "card/header-padding-x",
1964
+ "collection": "Layout",
1965
+ "type": "FLOAT",
1966
+ "code": "var(--card-header-padding-x)",
1967
+ "description": "",
1968
+ "values": {
1969
+ "Value": {
1970
+ "alias": "card/padding"
1971
+ }
1972
+ }
1973
+ },
1974
+ {
1975
+ "name": "card/header-min-height",
1976
+ "collection": "Layout",
1977
+ "type": "FLOAT",
1978
+ "code": "var(--card-header-min-height)",
1979
+ "description": "Compact card header",
1980
+ "values": {
1981
+ "Value": 42
1982
+ }
1983
+ },
1984
+ {
1985
+ "name": "card/header-height",
1986
+ "collection": "Layout",
1987
+ "type": "FLOAT",
1988
+ "code": "var(--card-header-height)",
1989
+ "description": "Card header",
1990
+ "values": {
1991
+ "Value": 44
1992
+ }
1993
+ },
1994
+ {
1995
+ "name": "card/body-padding",
1996
+ "collection": "Layout",
1997
+ "type": "FLOAT",
1998
+ "code": "var(--card-body-padding)",
1999
+ "description": "",
2000
+ "values": {
2001
+ "Value": {
2002
+ "alias": "card/padding"
2003
+ }
2004
+ }
2005
+ },
2006
+ {
2007
+ "name": "row/padding-y",
2008
+ "collection": "Layout",
2009
+ "type": "FLOAT",
2010
+ "code": "var(--row-padding-y)",
2011
+ "description": "Data row, above and below",
2012
+ "values": {
2013
+ "Value": 8
2014
+ }
2015
+ },
2016
+ {
2017
+ "name": "focus/ring-width",
2018
+ "collection": "Spacing",
2019
+ "type": "FLOAT",
2020
+ "code": "var(--focus-ring-width)",
2021
+ "description": "Focus ring stroke",
2022
+ "values": {
2023
+ "Value": 1
2024
+ }
2025
+ },
2026
+ {
2027
+ "name": "weight/regular",
2028
+ "collection": "Typography",
2029
+ "type": "FLOAT",
2030
+ "code": "var(--weight-regular)",
2031
+ "description": "",
2032
+ "values": {
2033
+ "Value": 400
2034
+ }
2035
+ },
2036
+ {
2037
+ "name": "weight/medium",
2038
+ "collection": "Typography",
2039
+ "type": "FLOAT",
2040
+ "code": "var(--weight-medium)",
2041
+ "description": "",
2042
+ "values": {
2043
+ "Value": 500
2044
+ }
2045
+ },
2046
+ {
2047
+ "name": "weight/semibold",
2048
+ "collection": "Typography",
2049
+ "type": "FLOAT",
2050
+ "code": "var(--weight-semibold)",
2051
+ "description": "",
2052
+ "values": {
2053
+ "Value": 600
2054
+ }
2055
+ },
2056
+ {
2057
+ "name": "duration/fast",
2058
+ "collection": "Motion",
2059
+ "type": "FLOAT",
2060
+ "code": "var(--duration-fast)",
2061
+ "description": "Hovers, small changes",
2062
+ "values": {
2063
+ "Value": 140
2064
+ }
2065
+ },
2066
+ {
2067
+ "name": "duration/normal",
2068
+ "collection": "Motion",
2069
+ "type": "FLOAT",
2070
+ "code": "var(--duration-normal)",
2071
+ "description": "Panels, page changes",
2072
+ "values": {
2073
+ "Value": 220
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
+ }
1905
2085
  }
1906
2086
  ]
1907
2087
  }
package/text-styles.css CHANGED
@@ -1,4 +1,4 @@
1
- /* @swiftsolve/rove-tokens 1.0.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. */
@@ -107,68 +107,14 @@
107
107
  }
108
108
  ]
109
109
  },
110
- "focus-ring-width": {
111
- "$type": "dimension",
112
- "$value": {
113
- "value": 1,
114
- "unit": "px"
115
- }
116
- },
117
110
  "focus-outline": {
118
111
  "$type": "border",
119
112
  "$value": {
120
- "width": "{focus-ring-width}",
113
+ "width": "{focus.ring-width}",
121
114
  "style": "solid",
122
115
  "color": "{focus.ring}"
123
116
  }
124
117
  },
125
- "titlebar-height": {
126
- "$type": "dimension",
127
- "$value": {
128
- "value": 56,
129
- "unit": "px"
130
- }
131
- },
132
- "rail-item-size": {
133
- "$type": "dimension",
134
- "$value": {
135
- "value": 38,
136
- "unit": "px"
137
- }
138
- },
139
- "card-padding": {
140
- "$value": "{spacing.14}"
141
- },
142
- "card-header-padding-y": {
143
- "$value": "{card-padding}"
144
- },
145
- "card-header-padding-x": {
146
- "$value": "{card-padding}"
147
- },
148
- "card-header-min-height": {
149
- "$type": "dimension",
150
- "$value": {
151
- "value": 42,
152
- "unit": "px"
153
- }
154
- },
155
- "card-header-height": {
156
- "$type": "dimension",
157
- "$value": {
158
- "value": 44,
159
- "unit": "px"
160
- }
161
- },
162
- "card-body-padding": {
163
- "$value": "{card-padding}"
164
- },
165
- "row-padding-y": {
166
- "$type": "dimension",
167
- "$value": {
168
- "value": 8,
169
- "unit": "px"
170
- }
171
- },
172
118
  "ease-out": {
173
119
  "$type": "cubicBezier",
174
120
  "$value": [
@@ -195,31 +141,5 @@
195
141
  0.58,
196
142
  1
197
143
  ]
198
- },
199
- "duration-fast": {
200
- "$type": "duration",
201
- "$value": {
202
- "value": 140,
203
- "unit": "ms"
204
- }
205
- },
206
- "duration-normal": {
207
- "$type": "duration",
208
- "$value": {
209
- "value": 220,
210
- "unit": "ms"
211
- }
212
- },
213
- "weight-regular": {
214
- "$type": "fontWeight",
215
- "$value": 400
216
- },
217
- "weight-medium": {
218
- "$type": "fontWeight",
219
- "$value": 500
220
- },
221
- "weight-semibold": {
222
- "$type": "fontWeight",
223
- "$value": 600
224
144
  }
225
145
  }
@@ -0,0 +1,67 @@
1
+ {
2
+ "titlebar": {
3
+ "height": {
4
+ "$type": "dimension",
5
+ "$value": {
6
+ "value": 56,
7
+ "unit": "px"
8
+ },
9
+ "$description": "Title bar"
10
+ }
11
+ },
12
+ "rail": {
13
+ "item-size": {
14
+ "$type": "dimension",
15
+ "$value": {
16
+ "value": 38,
17
+ "unit": "px"
18
+ },
19
+ "$description": "Rail items"
20
+ }
21
+ },
22
+ "card": {
23
+ "padding": {
24
+ "$type": "dimension",
25
+ "$value": "{spacing.14}",
26
+ "$description": "Card inset"
27
+ },
28
+ "header-padding-y": {
29
+ "$type": "dimension",
30
+ "$value": "{card.padding}"
31
+ },
32
+ "header-padding-x": {
33
+ "$type": "dimension",
34
+ "$value": "{card.padding}"
35
+ },
36
+ "header-min-height": {
37
+ "$type": "dimension",
38
+ "$value": {
39
+ "value": 42,
40
+ "unit": "px"
41
+ },
42
+ "$description": "Compact card header"
43
+ },
44
+ "header-height": {
45
+ "$type": "dimension",
46
+ "$value": {
47
+ "value": 44,
48
+ "unit": "px"
49
+ },
50
+ "$description": "Card header"
51
+ },
52
+ "body-padding": {
53
+ "$type": "dimension",
54
+ "$value": "{card.padding}"
55
+ }
56
+ },
57
+ "row": {
58
+ "padding-y": {
59
+ "$type": "dimension",
60
+ "$value": {
61
+ "value": 8,
62
+ "unit": "px"
63
+ },
64
+ "$description": "Data row, above and below"
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "duration": {
3
+ "fast": {
4
+ "$type": "duration",
5
+ "$value": {
6
+ "value": 140,
7
+ "unit": "ms"
8
+ },
9
+ "$description": "Hovers, small changes"
10
+ },
11
+ "normal": {
12
+ "$type": "duration",
13
+ "$value": {
14
+ "value": 220,
15
+ "unit": "ms"
16
+ },
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"
26
+ }
27
+ }
28
+ }
@@ -109,6 +109,14 @@
109
109
  "unit": "px"
110
110
  },
111
111
  "$description": "Focus ring offset"
112
+ },
113
+ "ring-width": {
114
+ "$type": "dimension",
115
+ "$value": {
116
+ "value": 1,
117
+ "unit": "px"
118
+ },
119
+ "$description": "Focus ring stroke"
112
120
  }
113
121
  }
114
122
  }
@@ -78,5 +78,19 @@
78
78
  "sans-serif"
79
79
  ]
80
80
  }
81
+ },
82
+ "weight": {
83
+ "regular": {
84
+ "$type": "fontWeight",
85
+ "$value": 400
86
+ },
87
+ "medium": {
88
+ "$type": "fontWeight",
89
+ "$value": 500
90
+ },
91
+ "semibold": {
92
+ "$type": "fontWeight",
93
+ "$value": 600
94
+ }
81
95
  }
82
96
  }
package/tokens.css CHANGED
@@ -1,4 +1,4 @@
1
- /* @swiftsolve/rove-tokens 1.0.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 */
@@ -44,6 +44,7 @@
44
44
 
45
45
  /* Spacing */
46
46
  --focus-offset: 2px; /* Focus ring offset */
47
+ --focus-ring-width: 1px; /* Focus ring stroke */
47
48
  --spacing-2: 2px;
48
49
  --spacing-4: 4px;
49
50
  --spacing-6: 6px;
@@ -70,6 +71,9 @@
70
71
  --font-size-3xl: 28px;
71
72
  --font-family-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
72
73
  --font-family-numeric: 'Questrial', ui-sans-serif, system-ui, sans-serif;
74
+ --weight-regular: 400;
75
+ --weight-medium: 500;
76
+ --weight-semibold: 600;
73
77
 
74
78
  /* Opacity */
75
79
  --opacity-tint-xs: 8%; /* Faintest tint */
@@ -80,30 +84,32 @@
80
84
  --opacity-high: 80%; /* Nearly opaque */
81
85
  --opacity-disabled: 40%; /* Disabled controls */
82
86
 
87
+ /* Layout */
88
+ --titlebar-height: 56px; /* Title bar */
89
+ --rail-item-size: 38px; /* Rail items */
90
+ --card-padding: var(--spacing-14); /* Card inset */
91
+ --card-header-padding-y: var(--card-padding);
92
+ --card-header-padding-x: var(--card-padding);
93
+ --card-header-min-height: 42px; /* Compact card header */
94
+ --card-header-height: 44px; /* Card header */
95
+ --card-body-padding: var(--card-padding);
96
+ --row-padding-y: 8px; /* Data row, above and below */
97
+
98
+ /* Motion */
99
+ --duration-fast: 140ms; /* Hovers, small changes */
100
+ --duration-normal: 220ms; /* Panels, page changes */
101
+ --duration-spring: 450ms; /* A spring’s full run */
102
+
83
103
  /* Code-only */
84
104
  --shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.22), 0 4px 12px rgba(0, 0, 0, 0.1);
85
105
  --shadow-raised: 0 12px 32px rgba(0, 0, 0, 0.22);
86
106
  --shadow-popover: 0 2px 6px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(0, 0, 0, 0.22);
87
- --focus-ring-width: 1px;
88
107
  --focus-outline: var(--focus-ring-width) solid var(--focus-ring);
89
- --titlebar-height: 56px;
90
- --rail-item-size: 38px;
91
- --card-padding: var(--spacing-14);
92
- --card-header-padding-y: var(--card-padding);
93
- --card-header-padding-x: var(--card-padding);
94
- --card-header-min-height: 42px;
95
- --card-header-height: 44px;
96
- --card-body-padding: var(--card-padding);
97
- --row-padding-y: 8px;
98
108
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
99
109
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
100
110
  --ease-pulse: cubic-bezier(0.42, 0, 0.58, 1);
101
- --duration-fast: 140ms;
102
- --duration-normal: 220ms;
103
- --weight-regular: 400;
104
- --weight-medium: 500;
105
- --weight-semibold: 600;
106
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);
107
113
 
108
114
  /* Type styles */
109
115
  --type-heading-large-size: var(--font-size-2xl);