carpenter_mordant 0.2.0 copy "carpenter_mordant: ^0.2.0" to clipboard
carpenter_mordant: ^0.2.0 copied to clipboard

Typed design tokens and YAML code generation for Flutter.

Carpenter Mordant #

Typed design tokens and YAML code generation for Flutter.

Mordant turns declarative token files into strongly typed Dart APIs.

Installation #

Add Mordant:

dependencies:
  carpenter_mordant: ^0.1.0

dev_dependencies:
  build_runner: any

Basic usage #

Create a Mordant file under lib:

# lib/tokens/tokens.mordant.yaml

palette:
  brand:
    500: "#987654"
    600: "#825E4A"

space:
  sm: 0.5rem
  md: 1rem

button:
  primary:
    background: "${palette.brand[500]}"
    padding: "${space.md}"

Generate Dart code:

dart run build_runner build --delete-conflicting-outputs

Mordant generates:

lib/tokens/tokens.mordant.g.dart

The generated API can be used directly:

palette.brand[500
]
palette.brand[600
]

space.md

button.primary.background
button.primary.padding

Unit tokens integrate with carpenter_units and resolve through an explicit runtime context:


final padding = button.primary.padding.resolve(
  const LengthUnitContext(rootFontSize: 16),
);

Includes #

Large token sets can be split across multiple files.

lib/tokens/
├── tokens.mordant.yaml
├── palette.mordant.part.yaml
├── space.mordant.part.yaml
└── button.mordant.part.yaml

Root file:

$include:
  - palette.mordant.part.yaml
  - space.mordant.part.yaml
  - button.mordant.part.yaml

Includes are resolved relative to the file containing $include.

They may also be nested:

$include:
  - components/button.mordant.part.yaml

Included files use the .mordant.part.yaml suffix so they do not generate standalone Dart files.

Duplicate token definitions are rejected.

Circular includes are rejected.

Generated palettes #

Mordant can generate a color scale from a seed:

palette:
  brand:
    $generate: palette
    seed: "#987654"
    start: 500

This produces:

palette.brand[50
]
palette.brand[100
]
palette.brand[200
]
palette.brand[300
]
palette.brand[400
]
palette.brand[500
]
palette.brand[600
]
palette.brand[700
]
palette.brand[800
]
palette.brand[900
]
palette.brand[950
]

The seed is preserved exactly at the configured start step.

Custom steps are supported:

palette:
  brand:
    $generate: palette
    seed: "#987654"
    start: 400

    steps:
      - 50
      - 100
      - 200
      - 300
      - 400
      - 500
      - 600
      - 700
      - 800
      - 900
      - 950

Palette tone endpoints can also be configured:

palette:
  brand:
    $generate: palette
    seed: "#987654"
    start: 500
    light-tone: 98
    dark-tone: 5

Palette generation uses HCT color space.

Token values #

Mordant currently recognizes:

color: "#987654"

px: 12px
em: 1.25em
rem: 1rem
duration: 200ms

number: 42
decimal: 1.25

enabled: true

label: Hello

reference: "${space.md}"

Hex colors must be quoted because an unquoted # starts a YAML comment.

References #

References use ${...} syntax:

space:
  md: 1rem

button:
  padding: "${space.md}"

Indexed groups may be referenced with bracket syntax:

palette:
  brand:
    500: "#987654"

button:
  background: "${palette.brand[500]}"

References are validated during generation.

Missing and circular references cause the build to fail.

Generated code #

Generated files are automatically formatted.

Mordant generates typed Dart structures instead of runtime string lookups.

For example:

button:
  primary:
    filled:
      background: "${palette.brand[500]}"

becomes an API shaped like:

button.primary.filled.background

No runtime token-path parsing is involved.

License #

Apache License 2.0.