amzn / style-dictionary

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

Pull `$extensions` from closest ancestor #1376

Open gavinbaradic opened 2 weeks ago

gavinbaradic commented 2 weeks ago

I see the $type property is applied from the closest ancestor in my design tokens file. Is there a way to do this for other properties? Specifically looking at using it for $extensions.

I'm just getting into the DTCG format and this seems like it would be a really useful feature to keep token files clean. If not supported out of the box, it'd be nice to show the best approach for how to achieve something like this.

Any advice would be greatly appreciated!

{
  color: {
    light: {
      $type: 'color',

      content: {
        $extensions: {
          'org.figma': {
            scopes: ['TEXT_FILL'],
          },
        },

        default: {
          $value: '{base.color.neutral.black}',
          $description: 'Default color for text and icons.',
        },
        muted: { $value: '{base.color.neutral.600}' },
        // ...
      }
    }
  }
}
jorenbroekema commented 2 weeks ago

Yeah you could look at this utility https://github.com/amzn/style-dictionary/blob/main/lib/utils/typeDtcgDelegate.js which is responsible for delegating the group level $type to the token level. I could have probably done a better job at commenting what that recursive code is doing but essentially it recurses breadth-first and:

Hope that makes sense 😅 and you can now copy + adjust it for $extensions. Then, you will have to register a preprocessor that uses your adapted $extensions delegate function:

StyleDictionary.registerPreprocessor({
  name: '$extensions-delegate',
  preprocessor: (dictionary) => extensionsDelegate(dictionary)
});

and use it by name in your config "preprocessors" prop, more info here


If the spec starts allowing more $props to be group-level dedupable just like $type, then I'm open to add these to Style Dictionary but until that's standardized / defined in the DTCG format, I think it's better if this is something users do themselves.

That said, if there's a lot of use cases where putting other properties on the group level and delegating them to the token level is useful, we might want to publish a utility that makes it easy for users to use this e.g. the public API would look something like:

import StyleDictionary from 'style-dictionary';
import { delegateGroupPropertiesFactory } from 'style-dictionary/utils';

StyleDictionary.registerPreprocessor({
  name: 'delegate-group-props',
  preprocessor: (dictionary) => delegateGroupPropertiesFactory(['$extensions', '$description'])(dictionary)
});
gavinbaradic commented 2 weeks ago

This worked perfectly, thank you! I was looking around the codebase for the utility that handled $type and just couldn't find it.

Appreciate the help! I could definitely see value in adding this to the docs even with the DTCG format not being finalized... Being able to apply properties to all children tokens is a super useful feature.