Painting Typography

The typography resolver reads a text role or utility class as a TypeSpec: font, size, weight, paint, and optional stroke. Apply it to custom text, or convert it for Highcharts labels.

#

Typography

Every resolver takes an optional { el }: the id or element whose nearest .screen ancestor supplies the paint. The probe technique is documented on Paint API .

  • type(classOrRole, { el, stroke }): the resolved typography of a role or class as a TypeSpec. The role 'chart-label' maps to text--small; 'value', 'label', 'title' and 'description' map to their own classes; any other string passes through as a literal class list (e.g. 'value value--xxlarge'). Font family, size, weight and line-height follow the active font bundle and density, so they are always probed, never read from vars. Pass stroke (a size token, or true for the base ring) to also resolve a text-stroke onto the spec.
  • strokeSpec(sizeToken, { el }): the resolved text-stroke ring as { color, width, radius }. The sizeToken is 'small' / 'medium' / 'large' / 'xlarge', or null for the base text-stroke.
TypeSpec = {
  fontFamily:      string | null,  // resolved family for the active bundle x density
  fontSize:        string | null,  // e.g. "38px" for .value
  fontWeight:      string | null,
  fontStyle:       string | null,
  fontVariantNumeric: string | null,
  fontVariationSettings: string | null,
  webkitFontSmoothing: string | null,
  letterSpacing:   string | null,
  lineHeight:      string | null,
  color:           string | null,  // exact computed color; transparent in clipped-tile modes
  backgroundColor: string | null,  // the text tile under-field
  backgroundImage: string | null,  // exact computed image; dither ink rides here
  backgroundSize:  string | null,
  backgroundPosition: string | null,
  backgroundRepeat:string | null,
  clip:            string | null,  // computed background-clip
  textShadow:      string | null,  // exact 16-ring program when stroke was requested
  filter:          string | null,
  overflow:        string | null,
  stroke:          null | { color, width, radius },  // present only when stroke was requested
}
// The .value role, size/family/weight resolved for the active bundle + density.
var big = TRMNLPaint.type("value", { el: "my-chart" });       // -> TypeSpec
var axis = TRMNLPaint.type("chart-label", { el: "my-chart" });
#

Painting type

A resolved spec is written back complete, so dither ink and stroke rings survive instead of collapsing to a solid color. Wrap paints in watch() so type re-resolves when the bundle, density or theme changes; see Paint API .

  • applyType(node, typeSpec): writes a TypeSpec's exact computed font, text paint, clipping and optional stroke longhands onto a node. Dither ink, its under-field and the full 16-ring text-shadow round-trip instead of being reduced to a solid color.
#

Highcharts labels

The text adapter copies a resolved spec into Highcharts' label options; the fill adapter and the adapter ground rules live on Painting Charts .

  • toHighchartsText(typeSpec): turns a TypeSpec into { color, textOutline, fontFamily?, fontSize?, ... }. Font keys appear only when resolved, and textOutline is 'none' unless a real opaque stroke was requested, which kills Highcharts' default white halo on data labels.
// Typography into Highcharts label options.
var label = TRMNLPaint.toHighchartsText(
  TRMNLPaint.type("chart-label", { el: "my-chart" }));
// => { color, textOutline: "none", fontFamily, fontSize, fontWeight }
#

Live example

The two stat tiles below are built from plain spans that carry no framework classes. TRMNLPaint.type() resolves the value role (the big-number face used by stat tiles) and the chart-label role (mapped to text--small), and TRMNLPaint.applyType() writes the resolved font and text-paint longhands onto them. Toggle the font bundle or density in the picker and the tiles follow, because family and size are probed from the live cascade rather than hardcoded.

TRMNL Logo Paint API TRMNLPaint.applyType
<div id="type-specimen" class="grid grid--cols-2 w--full"></div>

<script type="text/javascript">
  function whenReady(cb) {
    if (window.TRMNLPaint) return cb();
    window.addEventListener("load", function () {
      if (window.TRMNLPaint) cb();
    }, { once: true });
  }

  whenReady(function () {
    var el = "type-specimen";
    var TILES = [
      { value: "4,283", caption: "Reams Sold" },
      { value: "12", caption: "Dundie Awards" }
    ];
    // watch() re-resolves the typography whenever bundle/density/theme changes.
    TRMNLPaint.watch(el, function () {
      var grid = document.getElementById(el);
      if (!grid) return;
      grid.innerHTML = "";
      var big = TRMNLPaint.type("value", { el: el });
      var small = TRMNLPaint.type("chart-label", { el: el });
      TILES.forEach(function (t) {
        var cell = document.createElement("div");
        cell.className = "flex flex--col flex--center-x";
        var v = document.createElement("span");
        v.textContent = t.value;
        // applyType writes the complete TypeSpec; the spans themselves carry
        // no framework class.
        TRMNLPaint.applyType(v, big);
        var c = document.createElement("span");
        c.textContent = t.caption;
        TRMNLPaint.applyType(c, small);
        cell.appendChild(v);
        cell.appendChild(c);
        grid.appendChild(cell);
      });
    });
  });
</script>