Skip to content

Commit

Permalink
Merge pull request #1834 from chanzuckerberg/release-v13.9.0
Browse files Browse the repository at this point in the history
## [13.9.0](v13.8.1...v13.9.0) (2024-01-19)

[Storybook](https://61313967cde49b003ae2a860-utfzotmwuw.chromatic.com/)

### Features

* **Avatar:** adjust typography usages and sizing for icons ([#1830](#1830)) ([7da31e6](7da31e6))
* **InlineNotification:** remove deprecated variants ([#1833](#1833)) ([cfcf1fa](cfcf1fa))
* **Label:** mark optional as deprecated ([#1832](#1832)) ([8067082](8067082))
* **tokens:** output token literal values in a new tailwind config file ([#1828](#1828)) ([08fa1c4](08fa1c4))


### Bug Fixes

* **InputField:** mark unused prop as deprecated ([#1831](#1831)) ([622abfb](622abfb))
* **Select:** update incorrect documentation ([#1825](#1825)) ([94aace5](94aace5))
  • Loading branch information
booc0mtaco authored Jan 19, 2024
2 parents 7ae38fe + dc5db0a commit 607a995
Show file tree
Hide file tree
Showing 27 changed files with 1,253 additions and 1,085 deletions.
28 changes: 19 additions & 9 deletions .storybook/components/Docs/Guidelines/Theming.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ Below are instructions on how to use the tooling and tokens to define custom the
EDS comes with some tooling to allow easy transfer of theme data from Figma (or some style-dictionary compatible format) into code.

* `eds-init-theme` - This command sets up the initial file(s) for theming your application
* `eds-apply-theme` - This command parses the style dictionary files to generate the tokens (CSS Variables) used by EDS
* `eds-apply-theme` - This command parses the style dictionary files to generate the tokens used by EDS (and tailwind, or other tools)

Each of these tools reads config to figure out where to read/write files. This can be defined in several ways, e.g., a top-level file `.edsrc.json`, or as a key-value set in package.json. Example:

`package.json`

```json
"eds": {
"json": "src/components/",
"css": "src/components/"
"src": "src/components/",
"dest": "src/components/"
},
```

`.edsrc.json`

```json
{
"json": "src/components/",
"css": "src/components/"
"src": "src/components/",
"dest": "src/components/"
}
```

`json` determines where the core theme file will be copied to OR read from, and `css` determines where the resulting css token file will be stored.
`src` determines where the core theme file will be copied to (upon init) OR read from (upon apply), and `dest` determines where the processed files will be written to.

### eds-init-theme

Expand Down Expand Up @@ -79,9 +79,9 @@ EDS comes pre-packaged with many tokens that define the base style and character

### eds-apply-theme

After making changes to the `app-theme.json` to reflect what has been defined by design, update the CSS token file by running `npx eds-apply-theme`.
After making changes to the `app-theme.json` to reflect what has been defined by design, update the project's theme files by running `npx eds-apply-theme`.

Once run, you will have a CSS file `app-theme.css` that includes a set of token values that can be used in the app as appropriate.
Once run, you will have a CSS file `app-theme.css` that includes a set of token values as CSS variables, which can be used in the app as appropriate.

```css
/**
Expand All @@ -101,7 +101,17 @@ Once run, you will have a CSS file `app-theme.css` that includes a set of token
}
```

Add this file to your core app root file. That's it! Now, the theme will be applied to the tokens used by EDS components. To make other changes, edit `app-theme.json`, then re-run `npx eds-apply-theme`.
Add this file to your core app root file.

This also generates an additional file `app-tailwind-theme.config.json` which contains [useful tailwind configuration](https://github.com/chanzuckerberg/edu-design-system?tab=readme-ov-file#tailwind-setup) for EDS-specific utility classes
This will also show a preview of the tokens in your IDE of choice. To use this config, replace the import from the package with a link to this files location:

```diff
-const edsConfig = require('@chanzuckerberg/eds/tailwind.config');
+const edsConfig = require('./src/components/app-tailwind-theme.config');
```

That's it! Now, the theme will be applied to the tokens used by EDS components. To make other changes, edit `app-theme.json`, then re-run `npx eds-apply-theme`.

**NOTE**: do not edit this file directly. Instead, follow the instructions at the top of the file!

Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [13.9.0](https://github.com/chanzuckerberg/edu-design-system/compare/v13.8.1...v13.9.0) (2024-01-19)


### Features

* **Avatar:** adjust typography usages and sizing for icons ([#1830](https://github.com/chanzuckerberg/edu-design-system/issues/1830)) ([7da31e6](https://github.com/chanzuckerberg/edu-design-system/commit/7da31e6d8f9dc973ae03b9337c33bbe00bf7a666))
* **InlineNotification:** remove deprecated variants ([#1833](https://github.com/chanzuckerberg/edu-design-system/issues/1833)) ([cfcf1fa](https://github.com/chanzuckerberg/edu-design-system/commit/cfcf1fae674215cac8fb3ca2101ef77758ecb3c8))
* **Label:** mark optional as deprecated ([#1832](https://github.com/chanzuckerberg/edu-design-system/issues/1832)) ([8067082](https://github.com/chanzuckerberg/edu-design-system/commit/806708291d9dc8733eee3b782c29cb1409f1cb95))
* **tokens:** output token literal values in a new tailwind config file ([#1828](https://github.com/chanzuckerberg/edu-design-system/issues/1828)) ([08fa1c4](https://github.com/chanzuckerberg/edu-design-system/commit/08fa1c4783651d815939f735d4ed55d360b473aa))


### Bug Fixes

* **InputField:** mark unused prop as deprecated ([#1831](https://github.com/chanzuckerberg/edu-design-system/issues/1831)) ([622abfb](https://github.com/chanzuckerberg/edu-design-system/commit/622abfb0e5a29ab5aaf38a8f9ea08c1bf76308b1))
* **Select:** update incorrect documentation ([#1825](https://github.com/chanzuckerberg/edu-design-system/issues/1825)) ([94aace5](https://github.com/chanzuckerberg/edu-design-system/commit/94aace5ecda613600de23566c85304bb415b3765))

### [13.8.1](https://github.com/chanzuckerberg/edu-design-system/compare/v13.8.0...v13.8.1) (2024-01-04)

## [13.8.0](https://github.com/chanzuckerberg/edu-design-system/compare/v13.7.1...v13.8.0) (2023-12-06)
Expand Down
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module.exports = {
};
```

This will replace the default color tokens that come [with Tailwind](https://tailwindcss.com/docs/customizing-colors) with those defined by EDS. **NOTE**: this might cause regressions in your project, if you have been using the default colors from tailwind.
This will replace the default color tokens that come [with Tailwind](https://tailwindcss.com/docs/customizing-colors) with those defined by EDS. **NOTE**: this might cause regressions in your project, if you have been using the default colors provided by tailwind.

#### Applying the EDS tailwind extensions piecemeal

Expand All @@ -63,7 +63,7 @@ If you want a gentler transition to using EDS tailwind config, you can instead i
const edsConfig = require('@chanzuckerberg/eds/tailwind.config');

module.exports = {
content: ['./app/**/*.{ts,tsx,jsx,js}'],
// ...
theme: {
extend: {
...edsConfig.theme.extend
Expand All @@ -74,9 +74,7 @@ module.exports = {

This will add in the utility classes for properties like background color `bg-*`, border `border-*`, and text color `text-*`. These match the styles and variables defined in Figma designs.

You can spread each of the sub-objects in `theme` as desired, e.g., `fontSize`, `fontWeight`, etc.

Refer to the [tokens tailwind section][tokens] for usage guidelines.
Refer to the [tokens tailwind section][tokens] for usage guidelines if your project uses the theming tooling.

[tokens]: https://chanzuckerberg.github.io/edu-design-system/?path=/docs/documentation-guidelines-tokens--docs

Expand All @@ -102,7 +100,6 @@ EDS also provides the tokens used in the internal styles, to use in any custom c

Refer to the "EDS Token and Theme Tools" in [the tokens documentation](https://chanzuckerberg.github.io/edu-design-system/?path=/docs/documentation-theming--docs) to learn about the optional tooling setup.


## Usage

Import any of the components from the top-level package:
Expand Down
121 changes: 120 additions & 1 deletion bin/_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,129 @@ module.exports = {
// If no config exists, fail
if (!settings) {
throw new Error(
'Please add EDS config to your project before continuing (specify "json" and "css" target paths)',
'Please add EDS config to your project before continuing (specify "src" and "dest" target paths)',
);
}

/**
* TODO: Remove the old names for the input/output keys in the config at a future major version
* json => src
* css => dest
*/
if (settings.config.json) {
settings.config.src = settings.config.json;
console.warn(
'WARNING: You are using "json" in your config. Please replace with "src".',
);
}

if (settings.config.css) {
settings.config.dest = settings.config.css;
console.warn(
'WARNING: You are using "css" in your config. Please replace with "dest".',
);
}

return settings.config;
},
/**
* Utilities for handling generation of tokens in various formats.
*
* These will be used when preparing files upon publish, and are used with tooling provided by EDS to
* consumers.
*/
/**
* Function to handle various minimizing tasks on style-dictionary rows, where a value to transform exists
*
* @param {StyleObject} obj Metadata object produced from style-dictionary
* @param {Function} formatFunc function containing all the metadata for a given token
* @returns object representing the full transformed token object
*/
minifyDictionaryUsingFormat: function (obj, formatFunc) {
if (typeof obj !== 'object' || Array.isArray(obj)) {
return obj;
}

const toRet = {};

if (obj.hasOwnProperty('value')) {
return formatFunc(obj);
} else {
for (const name in obj) {
toRet[name] = module.exports.minifyDictionaryUsingFormat(
obj[name],
formatFunc,
);
}
}
return toRet;
},
/**
* Determine if the given theme file is a subset of what's in the base theme file.
* If it isnt, throw an error:
* - If keys are in base that are missing in the theme file, that's OK (no need to override everything)
* - If keys are in theme that aren't in base, throw (you can't theme tokens that don't exist in EDS)
* @param {object} base The tokens theme file stored in the EDS project
* @param {object} theme The project theme file stored in the app code (same format as bas)
* @param {Array} path The base path, stored as an array of object key names (default [])
* @throws Error when there are tokens in theme that aren't in base
*/
isStrictSubset: function (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}"`,
);
}
module.exports.isStrictSubset(
base[name],
theme[name],
path.concat(name),
);
}
}
},
/**
* Flatten token names such that any "root-tokens" do not include `@` in the resulting token name.
*
* Example:
* "neutral": {
* "default": {
* "@": "var(--eds-theme-color-border-neutral-default)",
* "hover": "var(--eds-theme-color-border-neutral-default-hover)"
* },
* },
*
* will be changed to
*
* "neutral": {
* "default": {
* "hover": "var(--eds-theme-color-border-neutral-default-hover)"
* },
* },
* "neutral-default": "var(--eds-theme-color-border-neutral-default)",
*/
formatEdsTokens: function (obj) {
for (const name in obj) {
if (typeof obj[name] === 'object') {
for (const nestedName in obj[name]) {
if (obj[name][nestedName]['@']) {
obj[name + '-' + nestedName] = obj[name][nestedName]['@'];
delete obj[name][nestedName]['@'];
if (Object.keys(obj[name][nestedName]).length === 0) {
delete obj[name][nestedName];
}
if (Object.keys(obj[name]).length === 0) {
delete obj[name];
}
} else if (typeof obj[name][nestedName] === 'object') {
module.exports.formatEdsTokens(obj[name]);
}
}
}
}
},
};
62 changes: 31 additions & 31 deletions bin/eds-apply-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@
const StyleDictionary = require('style-dictionary');
const path = require('path');
const fs = require('fs');
const { getConfig } = require('./_util');
const {
formatEdsTokens,
getConfig,
isStrictSubset,
minifyDictionaryUsingFormat,
} = require('./_util');

let packageRootPath;
try {
packageRootPath =
path.dirname(require.resolve('@chanzuckerberg/eds')) + '/tokens/json/';
} catch (e) {
// used for working on theming within EDS
console.error('EDS package not installed. Using local path...');
packageRootPath =
path.dirname(require.main.path) + '/src/tokens-dist/json/';
packageRootPath = path.dirname(require.main.path) + '/lib/tokens/json/';
}

// Read the config to sort out where to read JSON from and where to write the CSS file
const config = await getConfig();

// read and parse JSON files on disk
const localTheme = JSON.parse(
fs.readFileSync(`${config.json}app-theme.json`, 'utf8'),
fs.readFileSync(`${config.src}app-theme.json`, 'utf8'),
);
const baseTheme = JSON.parse(
fs.readFileSync(`${packageRootPath}theme-base.json`, 'utf8'),
Expand All @@ -35,12 +40,24 @@
],
});

StyleDictionary.registerFormat({
name: 'json/tailwind-utility-config',
formatter: function (dictionary) {
const minifiedCssDictionary = minifyDictionaryUsingFormat(
dictionary.properties,
(obj) => `${obj.value}`,
);
formatEdsTokens(minifiedCssDictionary);
return JSON.stringify(minifiedCssDictionary, null, 2);
},
});

const EDSStyleDictionary = StyleDictionary.extend({
source: [config.json + 'app-theme.json'],
source: [config.src + 'app-theme.json'],
platforms: {
css: {
transforms: [...StyleDictionary.transformGroup.css, 'name/cti/kebab'],
buildPath: config.css,
buildPath: config.dest,
files: [
{
format: 'css/variables',
Expand All @@ -54,36 +71,19 @@
return token.attributes.category !== 'legacy';
},
},
{
format: 'json/tailwind-utility-config',
destination: 'app-tailwind-theme.config.json',
options: {
outputReferences: true,
fileHeader: 'cssOverrideHeader',
},
},
],
},
},
});

/**
* Determine if the given theme file is a subset of what's in the base theme file.
* If it isnt, throw an error:
* - If keys are in base that are missing in the theme file, that's OK (no need to override everything)
* - If keys are in theme that aren't in base, throw (you can't theme tokens that don't exist in EDS)
* @param {object} base The tokens theme file stored in the EDS project
* @param {object} theme The project theme file stored in the app code (same format as bas)
* @param {Array} path The base path, stored as an array of object key names (default [])
* @throws Error when there are tokens in theme that aren't in base
*/
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));
}
}
}

try {
// Keys in the theme file must be a strict subset of those in the base file
isStrictSubset(baseTheme, localTheme);
Expand Down
13 changes: 8 additions & 5 deletions bin/eds-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
packageRootPath =
path.dirname(require.resolve('@chanzuckerberg/eds')) + '/tokens/json/';
} catch (e) {
// used for working on theming within EDS
console.error('EDS package not installed. Using local path...');
packageRootPath =
path.dirname(require.main.path) + '/src/tokens-dist/json/';
packageRootPath = path.dirname(require.main.path) + '/lib/tokens/json/';
}

// read in the config from config file, package json "eds", etc.
Expand All @@ -22,16 +22,19 @@
try {
fs.copyFileSync(
packageRootPath + 'theme-base.json',
`${config.json}app-theme.json`,
`${config.src}app-theme.json`,
fs.constants.COPYFILE_EXCL,
);
} catch (error) {
console.error('The local theme file already exists. Exiting.');
console.error(
'The local theme file already exists. Exiting. Details: \n',
error,
);
return 1;
}

console.log(
'File copy completed! Please use `npx eds-apply-theme` to generate theme tokens (CSS Variables).',
'File copy completed! Please use `npx eds-apply-theme` to generate theme token file(s).',
);
}
})();
Loading

0 comments on commit 607a995

Please sign in to comment.