-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tokens): add tooling for EDS theming
[sc-225326]: - handle initializing token override file from base - handle configuration for local paths to use - handle comparison to base in package for checksum - handle updates to themes when base has changed
- Loading branch information
1 parent
1e1a03f
commit 772c0a2
Showing
9 changed files
with
3,438 additions
and
64 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module.exports = { | ||
/** | ||
* Fetch the EDS config from the project using the lilconfig hierarchy. | ||
* This can be from package.json, or from various separate non-YAML files. | ||
* | ||
* @see https://github.com/antonk52/lilconfig#usage | ||
* @returns nullable config object returned from lilconfig | ||
*/ | ||
getConfig: async function () { | ||
const { lilconfig } = require('lilconfig'); | ||
|
||
// read in the config from config file, package json "eds", etc. | ||
const { config } = await lilconfig('eds').search(); | ||
|
||
// If no config exists, exit. | ||
if (!config) { | ||
// TODO: point to documentation (linked either to the repo or confluence) | ||
console.error('Please add EDS config to your project before continuing.'); | ||
} | ||
|
||
return config; | ||
}, | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
#!/usr/bin/env node | ||
(async function () { | ||
/** | ||
* Documentation: | ||
* - Token change log published when EDS changed, and errors link to changelog | ||
* | ||
* Possible Usages: | ||
* - Checks for reference to the token to link to change log entry(ies) | ||
* - Integrate with husky so that PRs always include updated theme values (pre-push) | ||
* | ||
* TODO: | ||
* - remove the config, and generated files from this PR before merging | ||
* - update the local app-theme.json with any new values from the base theme | ||
* | ||
* Questions: | ||
* - should this preserve the tier 1 tokens used by tier 2 and 3 files? | ||
* - (in wireframe kit, the only updates happen to colors/fonts) | ||
* - (in along, colors/fonts/border-* & drop shadows need overriding) | ||
* - should we use token references in the output instead of the hex codes? | ||
* - should we remove the listing of the tier-1 values in the theme base file? | ||
* - should we use the wireframe theme as the values used in the theme base? | ||
* - should all the grade-based tokens be filtered out (they might not apply to point solutions)? | ||
*/ | ||
const StyleDictionary = require('style-dictionary'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const { getConfig } = require('./_util'); | ||
|
||
// Compare local to base theme file for differences. flag and quit when theme has | ||
// undefined tokens being overridden | ||
let packageRootPath; | ||
try { | ||
packageRootPath = | ||
path.dirname(require.resolve('@chanzuckerberg/eds')) + '/tokens/'; | ||
} catch (e) { | ||
console.error('EDS package not installed. Using local path...'); | ||
packageRootPath = | ||
path.dirname(require.main.path) + '/src/tokens-dist/json/'; | ||
} | ||
|
||
const config = await getConfig(); | ||
|
||
// read and parse JSON files on disk | ||
const localTheme = JSON.parse( | ||
fs.readFileSync(`${config.json}app-theme.json`, 'utf8'), | ||
); | ||
const baseTheme = JSON.parse( | ||
fs.readFileSync(`${packageRootPath}theme-base.json`, 'utf8'), | ||
); | ||
|
||
// Keys in theme must be a strict subset of those in base | ||
try { | ||
isStrictSubset(baseTheme, localTheme); | ||
} catch (error) { | ||
// TODO: if theme has things not in base, error showing where the conflict | ||
console.error('Theme error:', error.message); | ||
return; | ||
} | ||
|
||
StyleDictionary.registerFileHeader({ | ||
name: 'cssOverrideHeader', | ||
fileHeader: (defaultMessage) => [ | ||
...defaultMessage, | ||
'To update, edit app-theme.json, then run `npx eds-update-theme`', | ||
], | ||
}); | ||
|
||
const EDSStyleDictionary = StyleDictionary.extend({ | ||
source: [config.json + 'app-theme.json'], | ||
platforms: { | ||
css: { | ||
transforms: [...StyleDictionary.transformGroup.css, 'name/cti/kebab'], | ||
buildPath: config.css, | ||
files: [ | ||
{ | ||
format: 'css/variables', | ||
destination: 'app-theme.css', | ||
options: { | ||
fileHeader: 'cssOverrideHeader', | ||
}, | ||
filter: function (token) { | ||
// don't allow theming on legacy tokens | ||
return token.attributes.category !== 'legacy'; | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}); | ||
EDSStyleDictionary.buildAllPlatforms(); | ||
|
||
function isStrictSubset(base, theme, path = []) { | ||
for (const name in theme) { | ||
if (typeof theme[name] === 'object') { | ||
if (base[name] === undefined) { | ||
throw new Error( | ||
`Local themeable value does not exist in base theme: ${path.join( | ||
'.', | ||
)}.${name}"`, | ||
); | ||
} | ||
isStrictSubset(base[name], theme[name], path.concat(name)); | ||
} | ||
} | ||
} | ||
})(); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#!/usr/bin/env node | ||
(async function () { | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { getConfig } = require('./_util'); | ||
|
||
let packageRootPath; | ||
try { | ||
packageRootPath = | ||
path.dirname(require.resolve('@chanzuckerberg/eds')) + '/tokens/'; | ||
} catch (e) { | ||
console.error('EDS package not installed. Using local path...'); | ||
packageRootPath = path.dirname(require.main.path) + '/src/tokens-dist/'; | ||
} | ||
|
||
// read in the config from config file, package json "eds", etc. | ||
const config = await getConfig(); | ||
|
||
// take the packaged var file and place a copy in the project's 'json' directory | ||
if (config) { | ||
try { | ||
fs.copyFileSync( | ||
packageRootPath + 'json/theme-base.json', | ||
`${config.json}app-theme.json`, | ||
fs.constants.COPYFILE_EXCL, | ||
); | ||
} catch (error) { | ||
console.error('The local theme file already exists. Exiting.'); | ||
return; | ||
} | ||
|
||
console.log( | ||
'File copy completed! Please use `npx eds-update-theme` to generate theme override CSS.', | ||
); | ||
} | ||
})(); |
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
Oops, something went wrong.