Codexportfolio intelligence

@philiprehberger/dart-design-tokens

Token-based design system with themes, JSON import/export, and validation. Zero dependencies. Pure Dart.

Dartpub.dev

Capabilities

README

philiprehberger_design_tokens

Tests pub package Last updated

Token-based design system with themes, JSON import/export, and validation. Zero dependencies. Pure Dart.

Requirements

  • Dart >= 3.6

Installation

Add to your pubspec.yaml:

dependencies:
  philiprehberger_design_tokens: ^0.4.0

Then run:

dart pub get

Usage

import 'package:philiprehberger_design_tokens/design_tokens.dart';

final theme = Theme(
  name: 'light',
  colors: {
    'primary': ColorToken.fromHex('#3366FF'),
    'background': ColorToken.fromHex('#FFFFFF'),
  },
  spacings: {
    'sm': SpacingToken(value: 8.0),
    'md': SpacingToken(value: 16.0),
  },
  typographies: {
    'body': TypographyToken(fontSize: 16.0, fontWeight: FontWeight.regular),
  },
);

final color = theme.color('primary');
print(color!.toHex()); // #3366ff

Theme Switching

final manager = ThemeManager();
manager.register(lightTheme);
manager.register(darkTheme);

manager.onChange((theme) => print('Now using: ${theme.name}'));
manager.switchTo('dark');

Token Types

// Colors with hex parsing
final color = ColorToken.fromHex('#FF6633');
final rgba = ColorToken(red: 1.0, green: 0.4, blue: 0.2);

// Spacing
const spacing = SpacingToken(value: 16.0);

// Typography with font weight enum
const heading = TypographyToken(
  fontSize: 32.0,
  fontWeight: FontWeight.bold,
  lineHeight: 1.2,
  letterSpacing: -0.5,
);

// Shadows
final shadow = ShadowToken(
  color: ColorToken.fromHex('#000000'),
  radius: 8.0,
  xOffset: 0.0,
  yOffset: 4.0,
  opacity: 0.15,
);

// Borders
final border = BorderToken(
  width: 1.0,
  color: ColorToken.fromHex('#E0E0E0'),
  style: BorderStyle.dashed,
);

Theme Merging and Extending

// Merge: other theme's tokens override matching keys
final merged = baseTheme.merging(overrideTheme);

// Extend: add tokens while keeping the original name
final extended = baseTheme.extending(
  colors: {'accent': ColorToken.fromHex('#FF6633')},
);

Token Aliases

// Register semantic aliases for existing token keys
final themed = theme.withAliases({
  'brand': 'primary',
  'small': 'sm',
  'paragraph': 'body',
});

// Resolve by alias or direct name
final color = themed.resolveColor('brand');    // same as theme.color('primary')
final spacing = themed.resolveSpacing('small'); // same as theme.spacing('sm')
final typo = themed.resolveTypography('paragraph');

Responsive Tokens

// Define breakpoint-dependent values
final spacing = ResponsiveToken<double>({
  'mobile': 8.0,
  'tablet': 16.0,
  'desktop': 24.0,
});

print(spacing.resolve('tablet'));          // 16.0
print(spacing.containsBreakpoint('mobile')); // true
print(spacing.breakpointNames);            // [mobile, tablet, desktop]

// JSON round-trip
final json = spacing.toJson((v) => v);
final restored = ResponsiveToken.fromJson<double>(json, (v) => (v as num).toDouble());

JSON Export and Import

final exporter = TokenExporter();

// Export to JSON map
final json = exporter.exportJson(theme);

// Import from JSON map
final restored = exporter.importJson(json);

// Serialize to bytes
final bytes = exporter.serialize(theme);
final fromBytes = exporter.deserialize(bytes);

Input Validation

All token constructors validate their inputs at construction time:

  • ColorToken -- RGBA channels must be between 0.0 and 1.0
  • SpacingToken -- value must be non-negative
  • TypographyToken -- fontSize must be positive, lineHeight (if set) must be positive
  • BorderToken -- width must be non-negative
  • ShadowToken -- radius must be non-negative, opacity must be between 0.0 and 1.0

Invalid values throw RangeError.

Accessibility Validation

ColorToken includes WCAG 2.1 contrast helpers for verifying color pairs:

final foreground = ColorToken.fromHex('#000000');
final background = ColorToken.fromHex('#FFFFFF');

// Relative luminance per WCAG 2.1
print(foreground.relativeLuminance); // 0.0
print(background.relativeLuminance); // 1.0

// Contrast ratio (1.0 .. 21.0)
print(foreground.contrastRatio(background)); // ~21.0

// AA: 4.5:1 normal text, 3:1 large text
foreground.meetsWcagAA(background);                   // true
foreground.meetsWcagAA(background, largeText: true);  // true

// AAA: 7:1 normal text, 4.5:1 large text
foreground.meetsWcagAAA(background);                  // true
foreground.meetsWcagAAA(background, largeText: true); // true

Validation

final validator = TokenValidator();
final issues = validator.validate(
  theme,
  requiredColors: ['primary', 'background', 'error'],
  requiredSpacing: ['sm', 'md', 'lg'],
  requiredTypography: ['body', 'heading'],
  requiredShadows: ['card'],
  requiredBorders: ['default'],
);

for (final issue in issues) {
  print('${issue.severity.name}: ${issue.message}');
}

API

Token Types

ClassDescription
ColorTokenRGBA color with hex parsing (fromHex, toHex)
SpacingTokenNumeric spacing value
TypographyTokenFont size, weight, line height, letter spacing
ShadowTokenShadow with color, radius, offsets, opacity
BorderTokenBorder with width, color, and style
TokenAliasMaps an alias name to an existing token key
ResponsiveToken<T>Breakpoint-dependent token values

ColorToken

MemberDescription
relativeLuminanceWCAG 2.1 relative luminance in [0.0, 1.0]
contrastRatio(other)WCAG 2.1 contrast ratio against another color (1.0..21.0)
meetsWcagAA(other, {largeText})true if contrast meets WCAG AA (4.5 normal, 3.0 large)
meetsWcagAAA(other, {largeText})true if contrast meets WCAG AAA (7.0 normal, 4.5 large)

Theme

MethodDescription
color(key)Look up a color token
spacing(key)Look up a spacing token
typography(key)Look up a typography token
shadow(key)Look up a shadow token
border(key)Look up a border token
merging(other)Merge another theme (other overrides)
extending(...)Extend with additional tokens
withAliases(aliases)Return new theme with semantic aliases
resolveColor(nameOrAlias)Look up color by name or alias
resolveSpacing(nameOrAlias)Look up spacing by name or alias
resolveTypography(nameOrAlias)Look up typography by name or alias
aliasesRegistered aliases (unmodifiable map)

ResponsiveToken

MethodDescription
resolve(breakpoint)Get value for a breakpoint
breakpointNamesList of all breakpoint keys
containsBreakpoint(breakpoint)Check if breakpoint exists
toJson(serializer)Serialize to JSON map
fromJson(json, deserializer)Deserialize from JSON map

ThemeManager

MethodDescription
register(theme)Register a theme
switchTo(name)Switch active theme
activeThemeCurrent active theme
availableThemesList of registered theme names
onChange(callback)Listen for theme changes

TokenExporter

MethodDescription
exportJson(theme)Export theme to JSON map
importJson(json)Import theme from JSON map
serialize(theme)Export to UTF-8 bytes
deserialize(bytes)Import from UTF-8 bytes

TokenValidator

MethodDescription
validate(theme, ...)Validate against required token names (colors, spacing, typography, shadows, borders)

Development

dart pub get
dart analyze --fatal-infos
dart test

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT