These repository contains the Atom Learning Design System tokens, like colours, sizes, spaces, font families and so on.
If you need to add tokens that are not part of the theme specification, follow the instruction below. You can also have a look at this PR where we did it for aspect ratios.
In
system-ui-theme.js, inschemaadd a new field as an empty object, likeratios: {}Also in
system-ui-theme.js, inmatchSchema, add a new field named[category].[type], which value references the field you added toschemain the previous step. For example if the category is ratios, and the type is ratio, it would look like'ratios.ratio': 'ratiosDepending on what you are adding you might have to add it to an existing .json file or create a new one. In our example, we created a new one
src/properties/ratios.json, and added all our tokens there. The json structure is as follow- first level: the
categorymentioned in the step above - second level: the
typementioned in the step above - third level: the token name, as you would use it with
$, e.g.:$16-9 - fourth level:
$value, the value the token will be replaced by (token sources use the DTCG format; groups may also declare a$type).
e.g.:
{ "ratios": { "ratio": { "16-9": { "$value": "16/9" }, "3-2": { "$value": "3/2" }, "4-3": { "$value": "4/3" }, "1-1": { "$value": "1/1" }, "3-4": { "$value": "3/4" } } } }In
style.config.jsadd your new category (if you added a new category) to the filter of the formatter'custom/format/scss-map-flat'. So it's treated the same way than'size'and'effects'In
theme-map.jsadd the (css property -> category) relation tothemeMap, in this example, we addedaspectRatio: 'ratios'. ThisthemeMapconfig is exported and used by projects using ourthemerepo. It's used bycreateStitches()from@stitches/reactso that we don't have to reference thetype, so we can call the token like'$16-9'instead of'$ratios$16-9'
- first level: the
For example, in components repo we use it like this:
...
import { createStitches, defaultThemeMap } from '@stitches/react'
import { themeMap } from '@atom-learning/theme/theme-map'
...
const stitchesConfig = createStitches({
theme: atomTheme as Theme,
themeMap: {
...defaultThemeMap,
...themeMap
},
utils,
media
})
Some CSS properties are not included in the defaultThemeMap. If they are missing (e.g.: aspectRatio) you need to add them to our custom themeMap which we pass to stitches themeMap config
Alongside the web outputs, the build emits the tokens in native-consumable form for the iOS and Android apps:
lib/theme-*.swift— aThemeTokensenum of SwiftUIColor(red:green:blue:opacity:)andCGFloatconstants (style-dictionary'sios-swift/enum.swiftformat)lib/theme-*.kt— the equivalent ComposeColor(0xAARRGGBB),.sp/.dpconstants inpackage uk.co.atomlearning.theme(style-dictionary'scompose/objectformat)
Values are converted at build time by style-dictionary's built-in transforms (color/ColorSwiftUI, color/composeColor, size/swift/remToCGFloat, size/compose/remToSp, size/compose/remToDp), driven by the $type declared on each token group: colours from hsl()/hex to sRGB components, size.font/size.radii/size.space from rem to pt (× 16). size.leading has no transform on purpose — the multipliers pass through unitless. Constant names come from the custom name/native/camel transform in src/native.ts: flat camelCase from the token path (color.blue.800 → blue800, size.font.sm → fontSm) — renames are breaking for the native apps.
Deliberately excluded: font.families.* (web font stacks — the apps bundle their own fonts), size.breakpoint.* (windowed-web concern) and effects.* (CSS box-shadow strings don't translate to native shadow parameters).
The files ship inside the npm tarball; the native repos vendor the file for a pinned version (e.g. fetched from unpkg in their build). There is no Swift Package or Maven artifact.
yarn test (watch) and yarn test:run (single run) both build first via a pretest hook, so the suite never asserts against stale lib/ output. CI runs the same suite on every PR (.github/workflows/ci.yml), plus yarn validate:types.
The suite is output-focused — it builds the package and inspects the real artifacts in lib/:
test/theme.test.ts— JS / CSS /.d.ts/ media query structure and formattingtest/completeness.test.ts— reconciles the token sources against every output, so a filter or naming regression that silently drops tokens fails the buildtest/values.test.ts— exact values for shadows, breakpoints and font stacks, and cross-output consistency (Swift colours are re-derived from the source hsl and checked against the JS theme and the Kotlin output)test/native.test.ts— Swift/Kotlin structure, conversions and per-theme filteringtest/native-compile.test.ts— compiles the generated files withswiftcandkotlinc. These tests skip when the toolchain is absent, so a local run without Xcode or Kotlin still passes. Both CI runners have them (GitHub's Ubuntu image ships Swift and Kotlin; the macOS job additionally validates against the real Xcode toolchain), so they always execute in CI. Invoking a real compiler far exceeds vitest's default 5s timeout, hence the explicitCOMPILE_TIMEOUTtest/assets.test.ts— everypackage.jsonexport target,typesVersionspath and copied asset exists and is non-empty
One known failure is encoded as an expected failure (it.fails) in test/completeness.test.ts: the CSS formatters emit --color-coolGrey-100 while the JS/.d.tsproperties map declares --color-cool-grey-100, so var(--color-cool-grey-100) resolves to nothing. This predates the native outputs work; remove the .fails marker when the naming is reconciled.