@labmgm/tokens
v0.1.0
Published
Design tokens for the MGM Laboratory Design System — primitive, semantic, and themed values for every product surface (web, iOS, Android, React Native, Flutter, Figma).
Maintainers
Readme
@labmgm/tokens
The design-token foundation of the MGM Laboratory Design System — primitive, semantic, and themed values for every product surface across web, iOS, Android, React Native, Flutter, and Figma.
Built from the brand spec at
mgm-laboratory-design-system.md. Light and dark themes, retuned for WCAG 2.2 AA. Every consumer format is regenerated deterministically from one source.
Install
pnpm add @labmgm/tokens
# or
npm install @labmgm/tokensUse
Tailwind preset (Next.js, Vite, anything)
// tailwind.config.ts
import type { Config } from "tailwindcss";
import preset from "@labmgm/tokens/tailwind";
export default {
presets: [preset],
content: ["./src/**/*.{ts,tsx,html}"],
} satisfies Config;/* app/globals.css */
@import "@labmgm/tokens/css/light";
@import "@labmgm/tokens/css/dark" (prefers-color-scheme: dark);
/* Or, for explicit theming, ship both unconditionally:
@import "@labmgm/tokens/css/light";
@import "@labmgm/tokens/css/dark";
…and toggle with <html data-theme="dark"> */After that, every class in brand spec §12.2 just works:
<button className="bg-brand-blue text-bg rounded-md px-5 h-10 text-body-sm font-medium">
Get started
</button>CSS variables (any framework)
<link rel="stylesheet" href="@labmgm/tokens/css" />
<!-- shared primitives -->
<link rel="stylesheet" href="@labmgm/tokens/css/light" />
<!-- :root -->
<link rel="stylesheet" href="@labmgm/tokens/css/dark" />
<!-- [data-theme=dark]-->.cta {
background: var(--brand-blue);
color: var(--bg);
border-radius: var(--radius);
padding-block: var(--spacing-3);
}TypeScript / JavaScript
import { tokens } from "@labmgm/tokens";
console.log(tokens.color.brand.blue); // → "#3a6dc5" (light)
console.log(tokens.spacing[4]); // → "16px"iOS Swift
import SwiftUI
import LabMgmTokens // from dist/ios/Tokens+Light.swift
Text("Get started")
.foregroundColor(LightTokens.Colors.brandBlue)
.padding(LightTokens.Dimensions.spacing4)Or use the asset catalog (dist/ios/Colors.xcassets/) and switch automatically:
Color("brand-blue") // resolves to light or dark per system appearanceAndroid (Compose + XML)
// dist/android/compose/TokensLight.kt
import org.labmgm.tokens.LightTokens
Surface(color = LightTokens.brandBlue) {
Text("Get started", color = LightTokens.bg)
}<!-- dist/android/values/colors.xml + values-night/colors.xml -->
<TextView android:textColor="@color/brand-blue" />React Native
import { resolveColors } from "@labmgm/tokens/react-native";
import { useColorScheme, View } from "react-native";
const colors = resolveColors(useColorScheme() ?? "light");
<View style={{ backgroundColor: colors["brand-blue"] }} />;Flutter
import 'package:labmgm_tokens/tokens.dart';
Container(
color: LightTokens.brandBlue,
child: Text('Get started', style: TextStyle(color: LightTokens.bg)),
);Figma (Tokens Studio)
Import dist/tokens-studio/tokens.json into the Tokens Studio plugin. Theme sets Light and Dark are preconfigured.
What's inside
tokens/ # W3C DTCG source of truth
├── primitives/ # raw values, no semantics
│ ├── color.json # neutrals, brand, dark variants
│ ├── typography.json # families, sizes, weights, lh, tracking
│ ├── spacing.json # 4-px scale + containers
│ ├── radius.json # 8 / 12 / 20 / 28 / pill
│ ├── shadow.json # 3-step elevation, light + dark
│ ├── motion.json # 5 durations × 3 easings
│ ├── breakpoint.json # mobile-first responsive
│ └── zIndex.json # 13-step stack
├── semantic/ # references to primitives
│ ├── color.json # bg, surface, ink-1..4, line, brand
│ ├── action.json # button & link states
│ ├── feedback.json # info, success, warning, danger
│ ├── focus.json # visible focus ring
│ └── elevation.json # named shadow steps
└── themes/ # theme-specific bindings
├── light.json
└── dark.json
dist/ # generated outputs
├── css/ # tokens.css + theme-{light,dark}.css
├── scss/tokens.scss
├── js/index.{js,cjs,d.ts} # typed nested object
├── js/tailwind.preset.{js,cjs,d.ts}
├── json/ # tokens.json (flat) + tokens.dtcg.json + tokens.nested.json
├── ios/ # Tokens+Light.swift, Tokens+Dark.swift, Colors.xcassets/
├── android/ # values/{colors,dimens,type}.xml + values-night/colors.xml + compose/
├── react-native/tokens.{js,d.ts}
├── flutter/tokens.dart
└── tokens-studio/tokens.jsonArchitecture
Three layers, walked top-down:
- Primitives — raw, named, never themed.
color.brand.blue.500 = "#3a6dc5". - Semantic — references to primitives, addressed by intent:
color.bg,action.primary.bg. Theme-agnostic. - Themes — light and dark, each binds the semantic layer to a specific primitive value.
Components only ever consume semantic tokens. Primitives can rename without breaking the API; themes can change values without breaking the API; only semantic names are stable.
Dark mode
Brand colors are retuned, not just darkened. The brand spec values pass AA on white; dark-mode equivalents are recomputed to pass AA on #0b0d10:
| Token | Light | Dark | AA on bg |
| -------------- | --------- | --------- | -------- |
| brand-blue | #3a6dc5 | #8db4f2 | 9.2 : 1 |
| brand-yellow | #f7bf33 | #ffd255 | 13.6 : 1 |
| brand-red | #f94141 | #ff7676 | 7.6 : 1 |
| brand-green | #0f8657 | #46d595 | 10.5 : 1 |
The -50 tints become brand-tinted near-blacks (#131b2a, #1f1a0d, #1f1010, #0d1f17) so chips and inline accents read against the dark page.
Contracts the build enforces
pnpm verifyfails if any text/background pair in either theme falls below WCAG 2.2 AA.pnpm verifyfails if any DTCG reference doesn't resolve, or any leaf is missing$value/$type.- Vitest covers: every semantic alias resolves to a primitive; both themes expose the same key set; tinted chip pairs pass AA-Large; the Tailwind preset surfaces every brand color and type-scale slug from brand spec §12.2.
- Output is deterministic and idempotent — the same input always produces byte-identical output.
Scripts
pnpm build # regenerate dist/ for both themes
pnpm verify # contrast + DTCG schema
pnpm test # vitest
pnpm typecheck # tsc --noEmit
pnpm lint
pnpm changeset # add a changeset for your PRVersioning
Changesets, independent versioning. See CHANGELOG.md.
- Patch — bug fixes, contrast tweaks within the scale, doc edits.
- Minor — new tokens, new semantic aliases, new platform outputs.
- Major — renaming or removing tokens; changing the resolved value of a semantic alias; changing output file shape.
Contributing
See CONTRIBUTING.md.
License
MIT © MGM Laboratory. See LICENSE.
