Created
April 1, 2021 18:14
-
-
Save bherbst/1b8c9a66953f25044631db68dd773429 to your computer and use it in GitHub Desktop.
Style Dictionary - Compose Dark Mode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.tokens | |
import androidx.compose.ui.graphics.Color | |
class Colors( | |
val textPrimary: Color, | |
val textSecondary: Color, | |
val textInverse: Color, | |
val textSecondaryInverse: Color, | |
) | |
fun lightColors( | |
textPrimary: Color = Palette.grayDarkest, | |
textSecondary: Color = Palette.grayDark, | |
textInverse: Color = Palette.paletteWhite, | |
textSecondaryInverse: Color = Palette.grayLightest, | |
): Colors = Colors( | |
textPrimary, | |
textSecondary, | |
textInverse, | |
textSecondaryInverse, | |
) | |
fun darkColors( | |
textPrimary: Color = Palette.grayLightest, | |
textSecondary: Color = Palette.grayDark, | |
textInverse: Color = Palette.paletteWhite, | |
textSecondaryInverse: Color = Palette.grayLightest, | |
): Colors = Colors( | |
textPrimary, | |
textSecondary, | |
textInverse, | |
textSecondaryInverse, | |
) | |
object Palette { | |
val paletteWhite: Color = Color(0xffffffff) | |
val paletteGray20: Color = Color(0x333333ff) | |
val paletteGray40: Color = Color(0x666666ff) | |
val paletteGray84: Color = Color(0xd6d6d6ff) | |
val paletteGray91: Color = Color(0xe8e8e8ff) | |
val paletteGray97: Color = Color(0xf7f7f7ff) | |
val grayLightest: Color = paletteGray97 | |
val grayDark: Color = paletteGray40 | |
val grayDarkest: Color = paletteGray20 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = { | |
source: ["tokens/*.json"], | |
transform: { | |
'color/ComposeColor': require('./transformers/composeColor') | |
}, | |
format: { | |
androidComposeColors: require('./formats/compose') | |
}, | |
platforms: { | |
androidCompose: { | |
transforms: [ | |
'attribute/cti', | |
'name/ti/camel', | |
'color/ComposeColor' | |
], | |
buildPath: "build/android-compose/", | |
files: [{ | |
destination: "Colors.kt", | |
format: `androidComposeColors`, | |
packageName: "com.example.tokens", | |
options: { | |
outputReferences: true | |
}, | |
filter: (token) => token.attributes.category === `color` | |
}] | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = function({ dictionary, options, file }) { | |
const themeableTokens = dictionary.allProperties.filter(token => { return token.themeable === true || token.darkValue }); | |
return `package ` + file.packageName + ` | |
import androidx.compose.ui.graphics.Color | |
class Colors(\n` + | |
themeableTokens.map(token => { | |
return ` val ${token.name}: Color,` | |
}).join(`\n`) + | |
`\n)\n\n` + | |
// Light mode colors | |
`fun lightColors(\n` + | |
themeableTokens.map(token => { | |
var value = tokenToThemedValue(dictionary, options, themeableTokens, token); | |
return ` ${token.name}: Color = ${value},` | |
}).join(`\n`) + | |
`\n): Colors = Colors(\n` + | |
themeableTokens.map(token => { return ` ${token.name},` }).join(`\n`) + | |
`\n)\n\n` + | |
// Dark mode colors - any color without a defined darkValue property will fall back to the light value | |
`fun darkColors(\n` + | |
themeableTokens | |
.map(token => { | |
var value = tokenToThemedDarkValue(dictionary, options, themeableTokens, token); | |
return ` ${token.name}: Color = ${value},` | |
}).join(`\n`) + | |
`\n): Colors = Colors(\n` + | |
themeableTokens.map(token => { return ` ${token.name},` }).join(`\n`) + | |
`\n)\n\n` + | |
// This is the color palette that we build our light and dark themes on | |
`object Palette {\n` + | |
dictionary.allProperties | |
// We need to sort based on how deep the reference trail is, because a value needs to be | |
// defined before we reference it in Kotlin | |
.sort( (token1, token2) => { return sortByReferenceDepth(dictionary, token1, token2) }) | |
.filter( token => { return !token.themeable && !token.darkValue } ) | |
.map(token => { | |
var value = tokenToValue(dictionary, options, token); | |
return ` val ${token.name}: Color = ${value}` | |
}).join(`\n`) + | |
`\n}` | |
} | |
function tokenToValue(dictionary, options, token) { | |
if (options.outputReferences && dictionary.usesReference(token.original.value)) { | |
var reference = dictionary.getReference(token.original.value) | |
return reference.name; | |
} else { | |
return token.value; | |
} | |
} | |
function tokenToThemedValue(dictionary, options, themeableTokens, token) { | |
if (options.outputReferences && dictionary.usesReference(token.original.value)) { | |
var reference = dictionary.getReference(token.original.value) | |
if (themeableTokens.includes(reference)) { | |
return reference.name; | |
} else { | |
return `Palette.${reference.name}` | |
} | |
} else { | |
return token.value; | |
} | |
} | |
function tokenToThemedDarkValue(dictionary, options, themeableTokens, token) { | |
if (!token.darkValue) { | |
return tokenToThemedValue(dictionary, options, themeableTokens, token) | |
} | |
if (options.outputReferences && dictionary.usesReference(token.original.darkValue)) { | |
var reference = dictionary.getReference(token.original.darkValue) | |
if (themeableTokens.includes(reference)) { | |
return reference.name; | |
} else { | |
return `Palette.${reference.name}` | |
} | |
} else { | |
return token.darkValue; | |
} | |
} | |
function sortByReferenceDepth(dictionary, token1, token2) { | |
return tokenDepth(dictionary, token1) - tokenDepth(dictionary, token2) | |
} | |
function tokenDepth(dictionary, token) { | |
if (dictionary.usesReference(token.original.value)) { | |
var reference = dictionary.getReference(token.original.value) | |
return tokenDepth(dictionary, reference) + 1 | |
} else { | |
return 0 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"color": { | |
"palette": { | |
"white": {"value":"#ffffff"}, | |
"gray": { | |
"97": { "value": "#f7f7f7" }, | |
"91" : { "value": "#e8e8e8" }, | |
"84" : { "value": "#d6d6d6" }, | |
"40" : { "value": "#666" }, | |
"20" : { "value": "#333" } | |
} | |
}, | |
"gray": { | |
"lightest": {"value":"{color.palette.gray.97.value}"}, | |
"dark": {"value":"{color.palette.gray.40.value}"}, | |
"darkest": {"value":"{color.palette.gray.20.value}"} | |
}, | |
"text": { | |
"primary": { | |
"themeable": true, | |
"value": "{color.gray.darkest.value}", | |
"darkValue": "{color.gray.lightest.value}", | |
"comment": "Primary textual content" | |
}, | |
"secondary": { | |
"themeable": true, | |
"value": "{color.gray.dark.value}", | |
"comment": "Secondary content" | |
}, | |
"inverse": { | |
"themeable": true, | |
"value": "{color.palette.white.value}", | |
"comment": "Text that must contrast negatively against a background. (e.g. white on red)" | |
}, | |
"secondaryInverse": { | |
"themeable": true, | |
"value": "{color.gray.lightest.value}", | |
"comment": "Secondary text that must contrast negatively against a background." | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const StyleDictionary = require('style-dictionary'); | |
var Color = require('tinycolor2') | |
module.exports = { | |
type: `value`, | |
matcher: (token) => token.attributes.category === `color`, | |
transformer: (prop) => { | |
const hex8 = Color(prop.value).toHex8(); | |
return `Color(0x${hex8})`; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment