resolveExports function

void resolveExports(
  1. SceneNode node,
  2. Map<String, Object?> exports
)

Puts the app's own values on the properties of node bound to them.

An EXPORT — Token<Color>('brand', AppColors.brand) in the group's declaration — reaches the editor as a name; the editor never holds the value and sends the binding as it is. This end holds the object, so a fill bound to brand takes the app's colour here, a double a number, a String text. A TextStyle in the style slot is laid UNDER the text's own values: every property the app's style sets and the text left at its default takes the style's — the resolution the compiled TextNode(…, style: tokens.title) does with fontSize ?? style?. fontSize ?? 16, so the two planes agree.

Implementation

void resolveExports(SceneNode node, Map<String, Object?> exports) {
  for (var e in node.bindings.entries) {
    var prop = e.key;
    switch (e.value) {
      case TokenRef(:var name) when sceneArgName(prop) == null:
        if (!exports.containsKey(name)) continue;
        var value = switch (exports[name]) {
          Color c => c.scene,
          SceneColor c => c,
          num n => n.toDouble(),
          String s => s,
          bool b => b,
          _ => null,
        };
        if (value != null) setSceneProperty(node, prop, value);
      case StyleRef(:var name) when node is TextNode:
        var style = switch (exports[name]) {
          TextStyle s => sceneTextStyleOf(s),
          SceneTextStyle s => s,
          _ => null,
        };
        if (style == null) continue;
        var props = {for (var p in scenePropsOf(node)) p.name: p};
        for (var f in style.values.entries) {
          var prop = props[f.key];
          if (prop == null) continue;
          if (isSceneDefault(prop, prop.read(node))) {
            setSceneProperty(node, f.key, f.value);
          }
        }
      default:
        break;
    }
  }
}