design-tokens / community-group

This is the official DTCG repository for the design tokens specification.
https://tr.designtokens.org
Other
1.56k stars 63 forks source link

Can alias tokens reference tokens in another file? #166

Open TravisSpomer opened 2 years ago

TravisSpomer commented 2 years ago

Theming (#2) is definitely still a big unresolved issue, but let's say for now you have three token files all in this format: global.json, light.json, and dark.json.

global.json

{ "black": { "$type": "color", "$value": "#000000" },
  "white": { "$type": "color", "$value": "#ffffff" } }

light.json

{ "foreground": { "$type": "color", "$value": "{black}" } }

dark.json

{ "foreground": { "$type": "color", "$value": "{white}" } }

You combine them with something like this:

theoretical-token-tool --in global.json --in light.json --out light.css
theoretical-token-tool --in global.json --in dark.json --out dark.css

On their own, light.json and dark.json are useless; they require global.json to make sense. My open-ended question is: are light.json and dark.json invalid DTCG-format token files that should not be accepted by any tool because their references can't be resolved on their own? Or are they still valid, but just can't be used without global.json?

I've been assuming all this time that all three files are valid, but I didn't see anything in the spec that says either way.

I'm not sure if we have to solve theming for v1 of this spec, but it seems like we do at least have to define this. All of those options have downsides, and if the spec doesn't specify the behavior, I think we'll get several downsides all at once as each tool interprets things a little differently.

c1rrus commented 2 years ago

Thanks for raising this. I completely agree that this is something the spec needs to be more explicit about.

I think this relates closely to the discussion in #123 - i.e. should the spec be explicit about how multiple token files are processed and their contents are merged. For example, what happens if global.json and dark.json both contain a token or group with the same name? Is that an error or does one override the other and, if so, which one "wins"?

As I proposed there, I wonder whether we ought to also think about some kind of include or import mechanism. While we'd still need to figure out exactly how those included files are processed and merged, it could provide a more convenient experience for end users.

Specifying muliple files in a specific order for a CLI like your theoretical-token-tool example is OK. But might be more cumbersome in a GUI. Imagine being in a UI design tool that had the ability to import a tokens file. Presumably you'd get a file picker dialog to choose the file to import. Maybe that lets you pick multiple files, but if the order is important, then you might need some additional UI to then set the order in which they are applied. Doable, but probably more clunky than just picking a single file.

In both cases, the people would also need to understand which files to pick and in which order. However, if they could just pick a single file, which then imports whatever other files it needs in the correct order, they could be blissfully unaware.

drwpow commented 8 months ago

However, if they could just pick a single file, which then imports whatever other files it needs in the correct order, they could be blissfully unaware.

Couldn’t agree more. I’m strongly in favor of the “entry file” approach where a single file contains all information needed about all the tokens. This is a pattern mirrored by JSONSchema/OpenAPI, and even JS modules themselves.

As you (and others) pointed out, requiring multiple files with no information on how they relate requires some higher-level metadata that I don’t think is necessary (i.e. it becomes “the entry file” in another sense, which could just be tokens.json to begin with).

Remote aliases

I’m sure this has been mentioned in some other thread already, but I’d love to be able to reference both local and remote files, because I think hosting tokens from a server/API will be very common. It could be done similarly to JSONSchema’s $ref property, where the # is a character delimiting the URL from the key:

{
  "inline": {
    "$type": "color",
    "$value": "#0033ff"
  },
  "local": {
    "$type": "color",
    "$value": "{file://./colors.json#color.red}"
  },
  "remote":{
    "$type": "color",
    "$value": "{https://myapi.com/v1/tokens#color.green}"
  }
}

I’m not too attached to the file:// protocol or anything; was just proposing some universal reserved prefix that designates the alias is remote. We could even revisit the alias syntax too, I suppose, but I’m not trying to open a can of worms; just advocate for remote file aliasing and that’s all.