Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Themeable in formats #474

Open
dbanksdesign opened this issue Oct 8, 2020 · 10 comments
Open

Themeable in formats #474

dbanksdesign opened this issue Oct 8, 2020 · 10 comments
Labels

Comments

@dbanksdesign
Copy link
Member

We recently merged in #359 that adds a themeable flag on tokens that will have the !default flag in SCSS. We want to make this broadly applicable to other built-in formats for other platforms. If you have any ideas/thoughts please post them here.

@nhoizey
Copy link
Contributor

nhoizey commented May 7, 2021

Do we have to set the themeable flag on each property, or is there a way to set this for all properties at once, in the configuration of a target platform of the build?

@dbanksdesign
Copy link
Member Author

Right now it is each property. Although it wouldn't be too much work to be able to set it per file or per platform, we would just need to update the formats that support it.

Another option that would work right now would be to use a custom parser o.0

module.exports = {
  parsers: [{
    pattern: /\.json$/,
    parse: ({ contents, filePath }) => {
      const tokens = JSON.parse(contents);
      traverseObj(tokens, (obj) => {
        // add themeable to all tokens
        if (obj.hasOwnProperty('value')) {
          obj.themeable = true;
        }
      });
      return tokens;
    }
  }],
  //...
}

@nhoizey
Copy link
Contributor

nhoizey commented May 7, 2021

I could indeed use a custom parser, thanks for providing the code! 👍

Obviously, like anyone else I guess, I try to keep my code as small and "default" as possible, so if it becomes a default option, it would be awesome. 😃

@dbanksdesign
Copy link
Member Author

I think adding a themable option to the formats that support it sounds like pretty good idea. It would be a pretty minor change. @chazzmoney thoughts?

@jacoblapworth
Copy link
Contributor

jacoblapworth commented May 12, 2021

I created a small transform to add a attribute to the platforms I needed.

import { Named, AttributeTransform } from 'style-dictionary'

export const themeable: Named<AttributeTransform> = {
  name: 'attribute/themeable',
  type: 'attribute',
  matcher: () => true,
  transformer: () => {
    return { themeable: true }
  },
}

@dbanksdesign
Copy link
Member Author

dbanksdesign commented May 12, 2021

Oh that is a good idea @jacoblapworth! One potential improvement, you can leave off the matcher function, if there is no matcher function on a transform then it will match all tokens.

@lennartbuit
Copy link

@jacoblapworth for me that didn't quite work. I think the attribute transform adds themeable to token.attibutes.themeable, whereas the formatting function for sass variables looks for token.themeable.

Am I missing something here?

@jacoblapworth
Copy link
Contributor

It looks like you're right @lennartbuit

if (format == 'sass' && prop.themeable === true) {

I ended up writing a custom format using string literals:

import StyleDictionary, { Format } from 'style-dictionary';
import { Formatter } from 'style-dictionary/types/Format';
import { Named } from 'style-dictionary/types/_helpers';

const { fileHeader } = StyleDictionary.formatHelpers;

const template: Formatter = ({ dictionary, file }) => {
  const tokens = dictionary.allTokens
    .map(token => {
      const name = token.name;
      const comment = token.comment ? `// ${token.comment}\n` : '';
      return `${comment}$${name}: ${token.value} !default;`;
    })
    .join('\n');

  return `${fileHeader({ file, commentStyle: 'long' })}
${tokens}
`;
};

@lennartbuit
Copy link

Yeah I ended with a similar workaround, I did add themeable: true to the attributes, and wrangled the tokens prior to calling formattedVariables:

const template = ({ dictionary, options, file }) => {
  const { outputReferences } = options;
    
  // Little cheat  
  const dictionaryWithGlobalThemeableKeys = {
    ...dictionary,
    allTokens: dictionary.allTokens.map(token => ({
      ...token,
      themeable: !!token.attributes.themeable,
    })),
  };
  
    return `
${fileHeader({ file, commentStyle: 'short' })}

${formattedVariables({ format: 'sass', dictionary: dictionaryWithGlobalThemeableKeys, outputReferences })}
  `.trim();
}

notlee added a commit to notlee/style-dictionary that referenced this issue Oct 19, 2021
Use the `formattedVariables` within the `scss/map-deep` formatter
to add support for the `outputReferences` option.
Closes: amzn#712

A side effect of this change is that `scss/map-deep` also
supports the `themeable` token property. For backward compatibility
changes have been made so tokens default to being themeable
with `scss/map-deep`, unlike for `scss/variables` where tokens
are not themeable by default. See amzn#474
@notlee
Copy link
Contributor

notlee commented Oct 19, 2021

I think adding a themable option to the formats that support it sounds like pretty good idea. It would be a pretty minor change. @chazzmoney thoughts?

Plus one 👍 I'd find a themeable formatter option useful to avoid scss/map-deep outputting themeable variables by default, which is its current behaviour.

Aside: this PR adds support for the themeable flag on tokens to scss/map-deep, it uses a formatter level argument to keep the default themeable behaviour ofscss/map-deep but could use a public themeable options instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants