amzn / style-dictionary

A build system for creating cross-platform styles.
https://styledictionary.com
Apache License 2.0
3.88k stars 543 forks source link

RFC: What would you like to see in Style Dictionary 4.0?👩🏽‍💻💡 #643

Closed chazzmoney closed 3 months ago

chazzmoney commented 3 years ago

Hey SD community... we need your help!

We would really love to hear what YOU would like to see in SD 4.0. Answers to this might include answers to these questions:

We would love to hear all your thoughts - we might* even send you some SD swag***...

bherbst commented 3 years ago

I'd love to see a few things to better support strongly typed languages such as Kotlin/Java:

lewishealey commented 3 years ago

I'd love to be able to create different formats and transforms based off different sources (if we can't do already)

dbanksdesign commented 3 years ago

@lewishealey could you elaborate a bit on this?

chazzmoney commented 3 years ago

@didoo @nhoizey @EvanLovely @kharrop @Tenga @jbarreiros @tonyjwalt @7studio @lukasoppermann

Would love your thoughts!

lukasoppermann commented 3 years ago

I am not sure how easy it is now, but splitting output by theme would be interesting.

E.g. you have dark / colors / background and light / colors / background and want to get two css files or better be able to define if two files or maybe one file but nested within two parents: body {...} and body.dark-mode { ... }

Still very rough, but this is something we work on currently. (Not just for the web of course)

didoo commented 3 years ago

Some initial thoughts.

I think a possible focus could be on making SD do things better, not necessarily do more. For example, I think one inevitable thing (and I am not saying it lightly, I understand the complexity of it) would be to convert the entire codebase to TypeScript. I know it's a huge, massive work. But this would make the refactoring of code (for its evolution) so much better! For those who have to touch the codebase, the knowledge that there is something in place that allows code refactoring without worrying that you forgot to change one prop or variable name somewhere in a file, is a game changer. This will not impact the final user, I know, but I think is a very important "safety feature" to add to the project.

Another thing I was thinking was the website and the documentation: I know also this one is huge and requires a massive effort, but I think is long past overdue :) (I suspect there is also a GH issue, somewhere, where this discussion already happened). There are so many things we could do in this area, and so many good websites of open-source projects where we could get inspiration from (in terms of exposing to the users the documentation/information in a smart way)

One last thing, possibly controversial: what if instead of "adding something" we "remove something"? The risk I see for many open-source projects is feature bloat, and I would be extremely sad to see this happen to SD. Quoting Antoine de Saint-Exupery “Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away” 😀

jacoblapworth commented 3 years ago

Support for naming structures with nested/default values.

Given end result token names of: $color-white $color-white-alpha

It's not currently possible to achieve this with a token structure like:

  color: {
    white: {
      value: '#fff',
      alpha: {
        value: 'rgba(1,1,1,0.8)',
      },
    },
  }

The alpha token is treated as an attribute of the white token.

We're currently solving this with a default value, which is then renamed in the formatter to remove the suffix. Not an ideal solution as we should only be mutating tokens during the transform step.

  color: {
    white: {
      default: {
        value: "#fff",
      },
      alpha: {
        value: 'rgba(1,1,1,0.8)',
      },
    },
  }

Possible solutions

isaachorton commented 3 years ago

I would like the ability to create multi-file formats. For instance, being able to generate an iOS Asset Catalog containing named colors (*.colorset)

Asset Catalog Ref

nhoizey commented 3 years ago

Hi, there are multiple things I would like to have in SD, which are already listed in the issues.

I agree with what @jacoblapworth asks for, and it is already in #366.

For Sass modules with @use, I would like to have a simple way to generate simple Sass files with automatic addition of @use directives where required, depending on references: #618

As Design Tokens are often part of a Design System, I would like to have a simple way to document tokens. I'm currently struggling with Storybook to do that, as I showed in #477 and https://github.com/storybookjs/storybook/issues/7671#issuecomment-797064663 . Maybe there could be a Storybook plugin as part of the SD project. Maybe for other Design System / documentation tools too.

I would also like to be able to "treat file path as prefix for property path", as asked in #104

bhdicaire commented 3 years ago

I would appreciate the ability to transform design tokens into color palettes usable by designers such as .ase, .clr and .sketchpallete.

You can refer to to the following project to estimate the required effort:

There is also mac centric projects (e.g., objective-c and swift):

uptonking commented 3 years ago

I want more built-in support for integrations/plugins/extensions to popular design tools like figma, sketch, framer-motion...

nhoizey commented 3 years ago

Now that there is an official glossary published by the Design Tokens W3C Community Group: https://www.designtokens.org/glossary/

Just as "properties" were renamed to "tokens" for v3, v4 could see "category" (in CTI) renamed to "type", but then "type" would have to be renamed to something else… maybe "property"? 😅

We would move from CTI to TPI…

andre-brdoch commented 3 years ago

I would love to see the possibility to derive different tokens from the same source! For example color-red would lead to color-red (hex) and color-red-rgb (rgb). color-red-rgb can then be referenced by other tokens, like any other token can.

Right now we have to use formats, which makes referencing the derived rgb-tokens difficult. To us, the rgb-tokens are first-level tokens. We simply dont want to specify them additionally to the hex-tokens, since that is redundant.

lukasoppermann commented 3 years ago

While I have different use cases, I also would love something like @andre-brdoch see: #695

JackHowa commented 3 years ago

feature request possibly:

https://amzn.github.io/style-dictionary/#/formats?id=scssmap-deep

before:

/**
 * Do not edit directly
 * Generated on Tue, 05 Oct 2021 21:06:03 GMT
 */

$list-components-date-font-weight: 900 !default;
$links-bar-font-size: 14px !default;

$blocks: (
  'list': (
    'components': (
      'date': (
        'font-weight': $list-components-date-font-weight
      )
    )
  ),
  'links-bar': (
    'font-size': $links-bar-font-size
  )
);

ideally after:

/**
 * Do not edit directly
 * Generated on Tue, 05 Oct 2021 21:06:03 GMT
 */

$blocks: (
  'list': (
    'components': (
      'date': (
        'font-weight': 900 
      )
    )
  ),
  'links-bar': (
    'font-size': 14px
  )
);
JackHowa commented 2 years ago

Dynamic outputs would be awesome as well https://github.com/amzn/style-dictionary/issues/667#issue-941786692

this library is still in development, right? @chazzmoney

dbanksdesign commented 2 years ago

This is still in development, we are working a bit more slowly recently because other priorities and personal things. And we are still looking to build a plan for a 4.0 release in the future.

MelSumner commented 2 years ago

I might already be able to do this, but I'm new to using style-dictionary; I haven't seen it in the docs though.

It would be cool if I could do something like this:

"size": {
     "base": { "value": 4 },
      "half": { "value": "{size.base.value}", "divide": 2 },
      "2": { "value": "{size.base.value}", "multiply": 2},
      "3": { "value": "{size.base.value}", "multiply": 3},
 }

Or perhaps accepting the MathJSON formatting: "half": { "value": ["Divide", "{size.base.value}", 2] }.

This way, if a designer changed their minds about what the base was, I could change a single value and then let math do the rest. (also if there is already a way to do this please let me know).

Thanks for considering!

alehar9320 commented 2 years ago

There might already be a clever way to achieve a nicely formatted design token changelog, or be out of scope for a CLI tool, but I'd love it if StyleDictionary could help provide an output of what tokens changed - from one generation to another (one version to another).

To give an example, StyleDictionary could accept two separate properties folders as input. Could be one version of properties folder from master branch, and another from current topic branch. The output would be a nicely formatted list of which tokens were added, removed and changed.

Simply thinking out loud 👨‍💻

jorgecasar commented 2 years ago

Define files programatically

I would like to be able to generate files based on current dictionary. When you have a dynamic number of components or you have more than 100 components tokenized it's hard to maintain the list of files.

Export all components variables into a single file is not efficient when you can include in your app only a sub set of all available components.

I would like to have something like this:

files: [{
  destination: `components/*.css`,
  format: 'css/component',
  filter: token => token.path[0] === 'component',
  split: dictionary => {
    const uniqueItems = [...new Set(
      dictionary.allTokens
      .filter(token => token.attributes?.item)
      .map(token => token.attributes.item)
    )]
    return uniqueItems.map(item => ({
      destination: `${component}.css`,
      filter: token => token.item === item,
    }));
  }
}]

Then easily you can get 1 file per item or any other split you would like to do attending to the token properties.

jorgecasar commented 2 years ago

Migrate to ESM

Deprecate CommonJS in in favor of ESM.

irwinsol commented 2 years ago

Support for naming structures with nested/default values.

Given end result token names of: $color-white $color-white-alpha

It's not currently possible to achieve this with a token structure like:

  color: {
    white: {
      value: '#fff',
      alpha: {
        value: 'rgba(1,1,1,0.8)',
      },
    },
  }

The alpha token is treated as an attribute of the white token.

We're currently solving this with a default value, which is then renamed in the formatter to remove the suffix. Not an ideal solution as we should only be mutating tokens during the transform step.

  color: {
    white: {
      default: {
        value: "#fff",
      },
      alpha: {
        value: 'rgba(1,1,1,0.8)',
      },
    },
  }

Possible solutions

* A new type of transformer for modifying paths. This could allow us to rearrange the structure dependent on platform/token matcher.

* Provide a configuration to limit the keys of attributes, in order for the parser to understand when to continue traversing the object for values.

  * this could also be achieved by enabling users to provide a custom traverser

I had this same issue, and followed @MrDevinB's suggestion of using a special character like "@": https://github.com/amzn/style-dictionary/issues/119#issuecomment-580472661

gearsandcode commented 2 years ago

I'd love to see things restructured into external files / folders and I second @didoo 's Typescript sentiments.

jholt1 commented 2 years ago

Ability to have transforms that allow one-to-many tokens.

This would be useful for something like color steps in a palette to be dynamically generated.

An idea for it

"neutral": {
  "light": {
    "value": "{ color.lightest.value }",
    "steps": {
      "type": "darken",
      "amount": {
        "50": 0.5,
        "100": 1,
        "150": 1.5,
        "200": 2,
        "250": 2.5,
        "300": 3,
        "350": 3.5,
        "400": 4,
        "450": 4.5,
        "500": 5
      }
    }
  }
}

For an output of tokens:

neutral.light.50.value
neutral.light.100.value
neutral.light.150.value
neutral.light.200.value
neutral.light.250.value
neutral.light.300.value
neutral.light.350.value
neutral.light.400.value
neutral.light.450.value
neutral.light.500.value
aitorllj93 commented 2 years ago

HTML formatter to visualize the tokens in a website

aitorllj93 commented 2 years ago

Web application to modify/export style dictionaries

andre-brdoch commented 2 years ago

Web application to modify/export style dictionaries

Making it easy for non-developers to do edits would be a really big one. Right now the technical threshold can make design tokens feel alien to designers, while they are probably equally (if not more) relevant to design.

chazzmoney commented 2 years ago

Current priorities appear to include:

  1. Typed tokens (this should help with context and formats)
  2. Token Browser / Editor (something to view, modify tokens - and maybe document output too?)
  3. Mono-repo w/ maintained library of formats (and encouraging the community to build more)
  4. Support for ESM import/export - and maybe rewriting everything into typescript
  5. Custom output file organization, including support for proper import handling of outputReferences
  6. Better logging, warning, and error control
ghost commented 2 years ago

Build-in solutions & documentation for Dark mode, High-contrast mode

djmtype commented 2 years ago

For CSS, it would be nice to automatically split up HSL values as well into separate custom properties. For JS, this seems possible using attribute/color.

Also follow the W3C spec while doing it.
https://design-tokens.github.io/community-group/format/#design-token-properties

{
  "color": {
    "white": {
      "value": "#ffffff"
    }
  }
}
:root {
--color-white: hsl(0 0% 100%);
--color-white-h: 0;
--color-white-s: 0%;
--color-white-l: 100%;
}
nareshbhatia commented 2 years ago

It would be nice to add support for composable tokens (unless I have missed it). This will allow us to generate CSS classes vs. only CSS Variable.

Example

I have a token like this one:

{
  "h1": {
    "value": {
      "fontFamily": "Inter",
      "fontWeight": 400,
      "lineHeight": 1.2,
      "fontSize": "1rem",
    },
    "type": "typography"
  }
}

After conversion it should look like this:

.h1 {
  font-family: Inter;
  font-weight: 400;
  line-height: 1.2;
  font-size: 1rem;
}

P.S. Related issue: https://github.com/amzn/style-dictionary/issues/798

otaviomad commented 2 years ago

type generics for transforms/parsers would be nice. as of now, the value in design tokens is always set as any so we have to type it with "as" inside the function. with generics, we could define the expected type of the token for better intellisense

gearsandcode commented 2 years ago

I want more built-in support for integrations/plugins/extensions to popular design tools like figma, sketch, framer-motion...

I’d love to see a pre-defined format for the Figma Tokens plugin.

jbltx commented 2 years ago

The ability to register a custom property reference resolver. So we won't get any thrown exception when reference resolution logic is different from SD's default one (transitive value transformers are still limited and doesn't prevent exceptions).

hbmuller commented 2 years ago

Group level attributes, as defined in the tokens format draft.

Same as mentioned here in #757

Edit: there's an open discussion related to generic attributes on group level

aitorllj93 commented 2 years ago

Implement kdrag0n's material you transform

ShaneHudson commented 2 years ago

For me, interoperability is the main thing. It has diverged a little from the current Design Tokens schema from the Community Group... close synchronicity there is important.

The workflow I'm aiming for is design tokens shared between Figma and Storybook with no manual steps when tokens change. It's close, but not quite there yet.

jam-awake commented 2 years ago

I'd like to be able to add ad-hoc custom transforms without needing to register them:

// config
{
  source,
  platforms: {
    css: {
      buildPath,
      transforms: [
        "attribute/cti",
        { matcher: (token) => token.isSource,
        , transitive: false,
        , transform: (token) => ...,
        },
      ],
      files,
    },
  },
};

Put differently, I'm not sure whether this can't be done today because of a design constraint or because it just hasn't been supported yet.

bennypowers commented 2 years ago
"type": "module"
Screen Shot 2022-05-29 at 12 46 11
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/config.js from /Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/style-dictionary/lib/extend.js not supported.
Instead change the require of config.js in /Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/style-dictionary/lib/extend.js to a dynamic import() which is available in all CommonJS modules.
    at Object.extend (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/style-dictionary/lib/extend.js:95:15)
    at Command.styleDictionaryBuild (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/style-dictionary/bin/style-dictionary:84:41)
    at Command.listener [as _actionHandler] (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:488:17)
    at /Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:1227:65
    at Command._chainOrCall (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:1144:12)
    at Command._parseCommand (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:1227:27)
    at Command._dispatchSubcommand (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:1050:25)
    at Command._parseCommand (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:1193:19)
    at Command.parse (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/commander/lib/command.js:897:10)
    at Object.<anonymous> (/Users/bennyp/Developer/redhat-ux/red-hat-design-tokens/node_modules/style-dictionary/bin/style-dictionary:111:9) {
  code: 'ERR_REQUIRE_ESM'
}

Support for module type package.json projects.

bennypowers commented 2 years ago

Expanding on https://github.com/amzn/style-dictionary/issues/643#issuecomment-1105109719, I'd like the input format to conform to the Design Tokens Format Module from the community group report.

# 3.0
color:
  type: color
  comment: Design system color values
  blue:
    100:
      value: '#e7f1fa'
# 4.0
color:
  $type: color
  $description: Design system color values
  blue:
    100:
      $value: '#e7f1fa'
aitorllj93 commented 2 years ago

Expanding on #643 (comment), I'd like the input format to conform to the Design Tokens Format Module from the community group report.

# 3.0
color:
  type: color
  comment: Design system color values
  blue:
    100:
      value: '#e7f1fa'
# 4.0
color:
  $type: color
  $description: Design system color values
  blue:
    100:
      $value: '#e7f1fa'

not really a fan of the $ syntax but any kind of improvement over the standard sounds great to me

aitorllj93 commented 2 years ago

Expanding on #643 (comment), I'd like the input format to conform to the Design Tokens Format Module from the community group report.

# 3.0
color:
  type: color
  comment: Design system color values
  blue:
    100:
      value: '#e7f1fa'
# 4.0
color:
  $type: color
  $description: Design system color values
  blue:
    100:
      $value: '#e7f1fa'

also, related to this need of "extra properties for the tokens" have any of you tried using the system for domain/business or any other kind of context modeling instead of just for design? I see potential on the templating system

bennypowers commented 2 years ago

not really a fan of the $ syntax but any kind of improvement over the standard sounds great to me

That'd be something to bring up in the design-tokens w3c community group

bennypowers commented 2 years ago

Per the Design Tokens Format Module from the community group report, $type (currently type) on parent objects should act as a default for its childrens' values, and not get output as the type on that parent:

color:
  $type: color
  red:
    $value: '#f00'
  green:
    $value: '#0f0'
  blue:
    $value: '#00f'

Actual:

{
  "color": {
    "$type": "color",
    "red": {
      "$value": "#f00"
    },
    "green": {
      "$value": "#0f0"
    },
    "blue": {
      "$value": "#00f"
    }
  }
}

Expected:

{
  "color": {
    "red": {
      "$type": "color",
      "$value": "#f00"
    },
    "green": {
      "$type": "color",
      "$value": "#0f0"
    },
    "blue": {
      "$type": "color",
      "$value": "#00f"
    }
  }
}
ShaneHudson commented 2 years ago

Maybe what we need is a simple way to do custom schemas for the JSON we use? Then any time the spec updates or alternatives are around, we can use the relevant ones. On 2 Jun 2022, 7:47 AM +0100, Benny Powers @.***>, wrote:

Per the Design Tokens Format Module from the community group report, $type (currently type) on parent objects should act as a default for its childrens' values, and not get output as the type on that parent: color: $type: color red: $value: '#f00' green: $value: '#0f0' blue: $value: '#00f' Actual: { "color": { "$type": "color", "red": { "$value": "#f00" }, "green": { "$value": "#0f0" }, "blue": { "$value": "#00f" } } } Expected: { "color": { "red": { "$type": "color", "$value": "#f00" }, "green": { "$type": "color", "$value": "#0f0" }, "blue": { "$type": "color", "$value": "#00f" } } } — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

aitorllj93 commented 2 years ago

Maybe what we need is a simple way to do custom schemas for the JSON we use? Then any time the spec updates or alternatives are around, we can use the relevant ones. On 2 Jun 2022, 7:47 AM +0100, Benny Powers @.>, wrote: Per the Design Tokens Format Module from the community group report, $type (currently type) on parent objects should act as a default for its childrens' values, and not get output as the type on that parent: color: $type: color red: $value: '#f00' green: $value: '#0f0' blue: $value: '#00f' Actual: { "color": { "$type": "color", "red": { "$value": "#f00" }, "green": { "$value": "#0f0" }, "blue": { "$value": "#00f" } } } Expected: { "color": { "red": { "$type": "color", "$value": "#f00" }, "green": { "$type": "color", "$value": "#0f0" }, "blue": { "$type": "color", "$value": "#00f" } } } — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.>

that's the reason why although I dislike the $ format I think is a good approach, we can start implementing custom schemas after we have a way to symbolize those custom properties (in this case, description, type, but could be more) after that, you just need a transform.

Other approaches I can think about (adding a meta/$/_ single prop, or wrapping all the properties as JSONSchema does) look ugly to me.

About the specific key, prefixing it with _ instead of $ (idk why in this case the markdown breaks if I don't wrap it lol) seems too strict for projects with "private" or context based naming conventions. I think $ is good because it works fine in most common file formats (json, yml and js/ts)

One thing I dislike about the current format (maybe I'm doing something wrong) is that in most of the cases you only need the value prop, and you need to add an extra line for each token just to include it as "value: myToken". That's too verbose IMO but not sure if that's something possible to change with the current implementation. I'm actually thinking about creating a parser just to add that to every end key on my tokens

aitorllj93 commented 2 years ago

Also, I think it would be nice to be able to reference remote values (ie HTTP protocol) or definitions from the JSON themselves (or at least some "preloaded" values)

stevenpetryk commented 2 years ago

It would be great if it were possible to change values at runtime/make Style Dictionary runnable in the browser context. Would enable live theme changes.

leifniem commented 2 years ago

I think a great addition would be to have the option of files being a function with the dictionary object available to it.

That way there would be an option to dynamically generate output files based on all available keys, which would make modular outputs a lot easier to handle and diff.

I came to that idea because i currently need to make two different token sets available as a single package, but not being able to split them into named exports based on their category or type without importing all JSON files and recursively iterating all of them.

julrich commented 2 years ago

Late to the party, but haven't seen this mentioned: It would be super nice if one would be able to run Style Dictionary in the browser, too. That would enable building things like wizard, configuration interfaces, etc, featuring client-side live reload / preview of the changed token set.

I know Backlight was (somewhat) successful in carving out a working part of the code base to achieve this for: https://www.style-dictionary-play.dev/

If this is possible (e.g. by only conditionally requiring fs dependencies), without crippling features already established, that would be super nice!

For some more background info about what is currently problematic when trying this: https://backlight.dev/blog/nodejs-in-browser