forked from mirrors/gecko-dev
Bug 1850611 - Create a JSON file source of truth for our design tokens. r=reusable-components-reviewers,desktop-theme-reviewers,hjones,dao
* Add light-dark transformer for generating web CSS * Use value object in design-tokens.json * Add HCM media queries to built CSS * Add MPL license and how to edit file header * Strip '-default' from token names and values * Refactor generated media query placement within file. * generate multiple CSS files from a single JSON file. * add the :host(.anonymous-content-host) selector to the built CSS * Output tokens in pre-defined order * Generate CSS layer declarations and relevant selectors * Sort tokens by t-shirt size and state semantically not alphabetically * Add remaining tokens to design-tokens.json * Add design tokens JSON docs --------- Co-authored-by: Jules Simplicio <jsimplicio@mozilla.com> Co-authored-by: Hanna Jones <hjones@mozilla.com> Co-authored-by: Mark Striemer <mstriemer@mozilla.com> Co-authored-by: Tim Giles <tgiles@mozilla.com> Differential Revision: https://phabricator.services.mozilla.com/D204108
This commit is contained in:
parent
99ff3ccc0d
commit
68b2a33f07
11 changed files with 2875 additions and 16 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -341,6 +341,9 @@ browser/components/storybook/storybook-static/
|
||||||
browser/components/storybook/.storybook/chrome-map.js
|
browser/components/storybook/.storybook/chrome-map.js
|
||||||
browser/components/storybook/custom-elements.json
|
browser/components/storybook/custom-elements.json
|
||||||
|
|
||||||
|
# Ignore design-system node_modules
|
||||||
|
toolkit/themes/shared/design-system/node_modules/
|
||||||
|
|
||||||
# Ignore jscodeshift installed by mach esmify on windows
|
# Ignore jscodeshift installed by mach esmify on windows
|
||||||
tools/esmify/jscodeshift
|
tools/esmify/jscodeshift
|
||||||
tools/esmify/jscodeshift.cmd
|
tools/esmify/jscodeshift.cmd
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,9 @@ tps_result\.json$
|
||||||
^browser/components/storybook/\.storybook/chrome-map\.js
|
^browser/components/storybook/\.storybook/chrome-map\.js
|
||||||
^browser/components/storybook/custom-elements\.json
|
^browser/components/storybook/custom-elements\.json
|
||||||
|
|
||||||
|
# Ignore design-system node_modules
|
||||||
|
toolkit/themes/shared/design-system/node_modules/
|
||||||
|
|
||||||
# Ignore jscodeshift installed by mach esmify on windows
|
# Ignore jscodeshift installed by mach esmify on windows
|
||||||
^tools/esmify/jscodeshift
|
^tools/esmify/jscodeshift
|
||||||
^tools/esmify/jscodeshift\.cmd
|
^tools/esmify/jscodeshift\.cmd
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
# JSON design tokens
|
||||||
|
## Background
|
||||||
|
The benefit of storing design tokens with a platform-agnostic format such as JSON is that it can be converted or translated into other languages or tools (e.g CSS, Swift, Kotlin, Figma).
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
`design-tokens.json` holds our source of truth for design tokens in `mozilla-central` under the [design-system](https://searchfox.org/mozilla-central/source/toolkit/themes/shared/design-system) folder in `toolkit/themes/shared`. The CSS design token files in that folder come from the JSON file. If you need to modify a design token file, you should be editing the JSON.
|
||||||
|
|
||||||
|
In order for us to be able to define design tokens in one place (the JSON file) and allow all platforms to consume design tokens in their specific format, we use a build system called [Style Dictionary](https://amzn.github.io/style-dictionary/#/).
|
||||||
|
|
||||||
|
Here's how to build design tokens for desktop:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./mach npm run build --prefix=toolkit/themes/shared/design-system
|
||||||
|
```
|
||||||
|
|
||||||
|
If successful, you should see Style Dictionary building all of our tokens files within the `design-system` folder. Otherwise, Style Dictionary can also generate helpful errors to help you debug.
|
||||||
|
|
||||||
|
At the end, we're capable of transforming JSON notation into CSS:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"color": {
|
||||||
|
"blue": {
|
||||||
|
"05": {
|
||||||
|
"value": "#deeafc"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#73a7f3"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#0060df"
|
||||||
|
},
|
||||||
|
"60": {
|
||||||
|
"value": "#0250bb"
|
||||||
|
},
|
||||||
|
"70": {
|
||||||
|
"value": "#054096"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#003070"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
--color-blue-05: #deeafc;
|
||||||
|
--color-blue-30: #73a7f3;
|
||||||
|
--color-blue-50: #0060df;
|
||||||
|
--color-blue-60: #0250bb;
|
||||||
|
--color-blue-70: #054096;
|
||||||
|
--color-blue-80: #003070;
|
||||||
|
```
|
||||||
|
|
||||||
|
Neat!
|
||||||
944
toolkit/themes/shared/design-system/design-tokens.json
Normal file
944
toolkit/themes/shared/design-system/design-tokens.json
Normal file
|
|
@ -0,0 +1,944 @@
|
||||||
|
{
|
||||||
|
"attention": {
|
||||||
|
"dot": {
|
||||||
|
"color": {
|
||||||
|
"value": {
|
||||||
|
"platform": {
|
||||||
|
"default": "AccentColor"
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"light": "#2ac3a2",
|
||||||
|
"dark": "#54ffbd"
|
||||||
|
},
|
||||||
|
"prefersContrast": "AccentColor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"color": {
|
||||||
|
"box": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.white}",
|
||||||
|
"dark": "{color.gray.80}",
|
||||||
|
"prefersContrast": "{background.color.canvas}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"canvas": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "Canvas",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.white}",
|
||||||
|
"dark": "{color.gray.90}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "Canvas"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"critical": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.05}",
|
||||||
|
"dark": "{color.red.80}",
|
||||||
|
"prefersContrast": "{background.color.canvas}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"information": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.blue.05}",
|
||||||
|
"dark": "{color.blue.80}",
|
||||||
|
"prefersContrast": "{background.color.canvas}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.green.05}",
|
||||||
|
"dark": "{color.green.80}",
|
||||||
|
"prefersContrast": "{background.color.canvas}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.yellow.05}",
|
||||||
|
"dark": "{color.yellow.80}",
|
||||||
|
"prefersContrast": "{background.color.canvas}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"border": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "{text.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"interactive": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "{text.color.@base}",
|
||||||
|
"forcedColors": "ButtonText",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.gray.60}",
|
||||||
|
"dark": "{color.gray.50}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "color-mix(in srgb, currentColor 15%, {color.gray.60})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{border.color.interactive.@base}",
|
||||||
|
"forcedColors": "SelectedItem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{border.color.interactive.@base}",
|
||||||
|
"forcedColors": "ButtonText"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{border.color.interactive.@base}",
|
||||||
|
"forcedColors": "GrayText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"radius": {
|
||||||
|
"circle": {
|
||||||
|
"value": "9999px"
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": "4px"
|
||||||
|
},
|
||||||
|
"medium": {
|
||||||
|
"value": "8px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"value": "1px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"box": {
|
||||||
|
"shadow": {
|
||||||
|
"10": {
|
||||||
|
"value": "0 1px 4px {color.black.a10}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"background": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"comment": "TODO Bug 1821203 - Gray use needs to be consolidated",
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "ButtonFace",
|
||||||
|
"brand": {
|
||||||
|
"default": "color-mix(in srgb, currentColor 7%, transparent)"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-bgcolor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "SelectedItemText",
|
||||||
|
"brand": {
|
||||||
|
"default": "color-mix(in srgb, currentColor 14%, transparent)"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-hover-bgcolor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "SelectedItemText",
|
||||||
|
"brand": {
|
||||||
|
"default": "color-mix(in srgb, currentColor 21%, transparent)"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-active-bgcolor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.background.color.@base}",
|
||||||
|
"forcedColors": "ButtonFace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"primary": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{color.accent.primary.@base}"
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": "{color.accent.primary.hover}"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "{color.accent.primary.active}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.background.color.primary.@base}",
|
||||||
|
"forcedColors": "{button.text.color.disabled}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"destructive": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.50}",
|
||||||
|
"dark": "{color.red.30}",
|
||||||
|
"forcedColors": "{button.background.color.primary.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.70}",
|
||||||
|
"dark": "{color.red.05}",
|
||||||
|
"forcedColors": "{button.background.color.primary.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.background.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.background.color.primary.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.60}",
|
||||||
|
"dark": "{color.red.10}",
|
||||||
|
"forcedColors": "{button.background.color.primary.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ghost": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "transparent",
|
||||||
|
"prefersContrast": "{button.background.color.@base}",
|
||||||
|
"forcedColors": "{button.background.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "{button.background.color.active}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.background.color.ghost.@base}",
|
||||||
|
"forcedColors": "{button.background.color.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": "{button.background.color.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"border": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{border.width} solid {button.border.color.@base}"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "transparent",
|
||||||
|
"prefersContrast": "{button.text.color.@base}",
|
||||||
|
"forcedColors": "{border.color.interactive.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.@base}",
|
||||||
|
"forcedColors": "{border.color.interactive.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"destructive": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "transparent",
|
||||||
|
"forcedColors": "{button.border.color.primary.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.border.color.primary.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.border.color.primary.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.border.color.primary.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.@base}",
|
||||||
|
"forcedColors": "{border.color.interactive.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ghost": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.@base}",
|
||||||
|
"forcedColors": "{border.color.interactive.hover}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"primary": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "transparent",
|
||||||
|
"forcedColors": "ButtonFace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.primary.@base}",
|
||||||
|
"forcedColors": "ButtonText"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": "{button.border.color.primary.@base}"
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.border.color.primary.@base}",
|
||||||
|
"forcedColors": "SelectedItemText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"radius": {
|
||||||
|
"value": "{border.radius.small}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"font": {
|
||||||
|
"size": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{font.size.root}"
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": "{font.size.small}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"weight": {
|
||||||
|
"value": "{font.weight.bold}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"min": {
|
||||||
|
"height": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{size.item.large}"
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": "{size.item.medium}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"opacity": {
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": 0.5,
|
||||||
|
"forcedColors": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"padding": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{space.xsmall} {space.large}"
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"value": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"icon": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{button.min.height.@base}"
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": "{button.min.height.small}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "ButtonText",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.gray.100}",
|
||||||
|
"dark": "{color.gray.05}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-color)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.@base}",
|
||||||
|
"forcedColors": "SelectedItem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"destructive": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.gray.05}",
|
||||||
|
"dark": "{color.gray.100}",
|
||||||
|
"forcedColors": "{button.text.color.primary.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.text.color.primary.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.text.color.primary.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.destructive.@base}",
|
||||||
|
"forcedColors": "{button.text.color.primary.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.@base}",
|
||||||
|
"forcedColors": "GrayText"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ghost": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.active}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.disabled}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.hover}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.@base}",
|
||||||
|
"forcedColors": "SelectedItem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"primary": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "ButtonFace",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.gray.05}",
|
||||||
|
"dark": "{color.gray.100}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-primary-color)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "{button.text.color.primary.hover}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"value": "{button.text.color.primary.@base}"
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"default": "{button.text.color.primary.@base}",
|
||||||
|
"forcedColors": "SelectedItemText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"checkbox": {
|
||||||
|
"margin": {
|
||||||
|
"inline": {
|
||||||
|
"value": "{space.small}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"comment": "TODO Bug 1876537: Make this em-based, probably?",
|
||||||
|
"value": "{size.item.small}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"black": {
|
||||||
|
"a10": {
|
||||||
|
"value": "rgba(0, 0, 0, 0.1)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blue": {
|
||||||
|
"05": {
|
||||||
|
"value": "#deeafc"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#73a7f3"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#0060df"
|
||||||
|
},
|
||||||
|
"60": {
|
||||||
|
"value": "#0250bb"
|
||||||
|
},
|
||||||
|
"70": {
|
||||||
|
"value": "#054096"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#003070"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cyan": {
|
||||||
|
"20": {
|
||||||
|
"value": "#aaf2ff"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#80ebff"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#00ddff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gray": {
|
||||||
|
"05": {
|
||||||
|
"value": "#fbfbfe"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#bfbfc9"
|
||||||
|
},
|
||||||
|
"60": {
|
||||||
|
"value": "#8f8f9d"
|
||||||
|
},
|
||||||
|
"70": {
|
||||||
|
"value": "#5b5b66"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#23222b"
|
||||||
|
},
|
||||||
|
"90": {
|
||||||
|
"value": "#1c1b22"
|
||||||
|
},
|
||||||
|
"100": {
|
||||||
|
"value": "#15141a"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"green": {
|
||||||
|
"05": {
|
||||||
|
"value": "#d8eedc"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#4dbc87"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#017a40"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#004725"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"red": {
|
||||||
|
"05": {
|
||||||
|
"value": "#ffe8e8"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"value": "#ffbdc5"
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"value": "#ff9aa2"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#f37f98"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#d7264c"
|
||||||
|
},
|
||||||
|
"60": {
|
||||||
|
"value": "#ac1e3d"
|
||||||
|
},
|
||||||
|
"70": {
|
||||||
|
"value": "#8a1831"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#690f22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yellow": {
|
||||||
|
"05": {
|
||||||
|
"value": "#ffebcd"
|
||||||
|
},
|
||||||
|
"30": {
|
||||||
|
"value": "#e49c49"
|
||||||
|
},
|
||||||
|
"50": {
|
||||||
|
"value": "#cd411e"
|
||||||
|
},
|
||||||
|
"80": {
|
||||||
|
"value": "#5a3100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"white": {
|
||||||
|
"value": "#ffffff"
|
||||||
|
},
|
||||||
|
"accent": {
|
||||||
|
"primary": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "ButtonText",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.blue.50}",
|
||||||
|
"dark": "{color.cyan.50}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-primary-bgcolor, AccentColor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "SelectedItem",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.blue.60}",
|
||||||
|
"dark": "{color.cyan.30}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-primary-hover-bgcolor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"forcedColors": "{color.accent.primary.hover}",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.blue.70}",
|
||||||
|
"dark": "{color.cyan.20}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "var(--button-primary-active-bgcolor)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"focus": {
|
||||||
|
"outline": {
|
||||||
|
"@base": {
|
||||||
|
"value": "{focus.outline.width} solid {focus.outline.color}"
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"value": "{color.accent.primary.@base}"
|
||||||
|
},
|
||||||
|
"inset": {
|
||||||
|
"value": "calc(-1 * {focus.outline.width})"
|
||||||
|
},
|
||||||
|
"offset": {
|
||||||
|
"value": "2px"
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"value": "2px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"font": {
|
||||||
|
"size": {
|
||||||
|
"root": {
|
||||||
|
"value": {
|
||||||
|
"brand": {
|
||||||
|
"default": "15px"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": {
|
||||||
|
"brand": {
|
||||||
|
"default": "0.867rem"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"large": {
|
||||||
|
"value": {
|
||||||
|
"brand": {
|
||||||
|
"default": "1.133rem"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xlarge": {
|
||||||
|
"value": {
|
||||||
|
"brand": {
|
||||||
|
"default": "1.467rem"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xxlarge": {
|
||||||
|
"value": {
|
||||||
|
"brand": {
|
||||||
|
"default": "1.6rem"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"weight": {
|
||||||
|
"@base": {
|
||||||
|
"value": "normal"
|
||||||
|
},
|
||||||
|
"bold": {
|
||||||
|
"value": 600
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.gray.70}",
|
||||||
|
"dark": "{color.gray.05}",
|
||||||
|
"prefersContrast": "{text.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"information": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.blue.50}",
|
||||||
|
"dark": "{color.blue.30}",
|
||||||
|
"prefersContrast": "{icon.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.green.50}",
|
||||||
|
"dark": "{color.green.30}",
|
||||||
|
"prefersContrast": "{icon.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.yellow.50}",
|
||||||
|
"dark": "{color.yellow.30}",
|
||||||
|
"prefersContrast": "{icon.color.@base}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"critical": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.50}",
|
||||||
|
"dark": "{color.red.30}",
|
||||||
|
"prefersContrast": "{icon.color.@base}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"default": {
|
||||||
|
"value": "{size.item.small}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"text": {
|
||||||
|
"min": {
|
||||||
|
"height": {
|
||||||
|
"value": "{button.min.height.@base}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "LinkText",
|
||||||
|
"brand": {
|
||||||
|
"default": "{color.accent.primary.@base}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "LinkText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "LinkText",
|
||||||
|
"brand": {
|
||||||
|
"default": "{color.accent.primary.hover}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "LinkText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "ActiveText",
|
||||||
|
"brand": {
|
||||||
|
"default": "{color.accent.primary.active}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "ActiveText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"visited": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "{link.color.@base}",
|
||||||
|
"brand": {
|
||||||
|
"default": "{link.color.@base}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "{link.color.@base}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"focus": {
|
||||||
|
"outline": {
|
||||||
|
"offset": {
|
||||||
|
"comment": "Not using --force-outline-offset for links because that's intended for\nelements with a background, and we only want a slight offset here while\nnot overlapping adjacent text",
|
||||||
|
"value": "1px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outline": {
|
||||||
|
"color": {
|
||||||
|
"error": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.50}",
|
||||||
|
"dark": "{color.red.20}",
|
||||||
|
"prefersContrast": "{border.color.@base}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"item": {
|
||||||
|
"small": {
|
||||||
|
"value": "16px"
|
||||||
|
},
|
||||||
|
"medium": {
|
||||||
|
"value": "28px"
|
||||||
|
},
|
||||||
|
"large": {
|
||||||
|
"value": "32px"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"space": {
|
||||||
|
"xxsmall": {
|
||||||
|
"value": "calc(0.5 * {space.xsmall})"
|
||||||
|
},
|
||||||
|
"xsmall": {
|
||||||
|
"value": "0.267rem"
|
||||||
|
},
|
||||||
|
"small": {
|
||||||
|
"value": "calc(2 * {space.xsmall})"
|
||||||
|
},
|
||||||
|
"medium": {
|
||||||
|
"value": "calc(3 * {space.xsmall})"
|
||||||
|
},
|
||||||
|
"large": {
|
||||||
|
"value": "calc(4 * {space.xsmall})"
|
||||||
|
},
|
||||||
|
"xlarge": {
|
||||||
|
"value": "calc(6 * {space.xsmall})"
|
||||||
|
},
|
||||||
|
"xxlarge": {
|
||||||
|
"value": "calc(8 * {space.xsmall})"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"color": {
|
||||||
|
"@base": {
|
||||||
|
"value": {
|
||||||
|
"prefersContrast": "CanvasText",
|
||||||
|
"brand": {
|
||||||
|
"light": "{color.gray.100}",
|
||||||
|
"dark": "{color.gray.05}"
|
||||||
|
},
|
||||||
|
"platform": {
|
||||||
|
"default": "currentColor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deemphasized": {
|
||||||
|
"value": {
|
||||||
|
"default": "color-mix(in srgb, currentColor 69%, transparent)",
|
||||||
|
"prefersContrast": "inherit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": {
|
||||||
|
"light": "{color.red.50}",
|
||||||
|
"dark": "{color.red.20}",
|
||||||
|
"prefersContrast": "inherit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1405
toolkit/themes/shared/design-system/package-lock.json
generated
Normal file
1405
toolkit/themes/shared/design-system/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
12
toolkit/themes/shared/design-system/package.json
Normal file
12
toolkit/themes/shared/design-system/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "design-system",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Package file for node modules used to create our CSS tokens from a JSON source of truth.",
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"scripts": {
|
||||||
|
"build": "(npm ls || npm ci) && style-dictionary build --config ./tokens-config.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"style-dictionary": "^3.9.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* DO NOT EDIT this file directly, instead modify design-tokens.json
|
||||||
|
* and run `npm run build` to see your changes. */
|
||||||
|
|
||||||
@import url("chrome://global/skin/design-system/tokens-shared.css");
|
@import url("chrome://global/skin/design-system/tokens-shared.css");
|
||||||
|
|
||||||
@layer tokens-foundation {
|
@layer tokens-foundation {
|
||||||
|
|
@ -17,8 +20,7 @@
|
||||||
--border-color-interactive: light-dark(var(--color-gray-60), var(--color-gray-50));
|
--border-color-interactive: light-dark(var(--color-gray-60), var(--color-gray-50));
|
||||||
|
|
||||||
/** Button **/
|
/** Button **/
|
||||||
/* TODO Bug 1821203 - Gray use needs to be consolidated */
|
--button-background-color: color-mix(in srgb, currentColor 7%, transparent); /* TODO Bug 1821203 - Gray use needs to be consolidated */
|
||||||
--button-background-color: color-mix(in srgb, currentColor 7%, transparent);
|
|
||||||
--button-background-color-hover: color-mix(in srgb, currentColor 14%, transparent);
|
--button-background-color-hover: color-mix(in srgb, currentColor 14%, transparent);
|
||||||
--button-background-color-active: color-mix(in srgb, currentColor 21%, transparent);
|
--button-background-color-active: color-mix(in srgb, currentColor 21%, transparent);
|
||||||
--button-text-color: light-dark(var(--color-gray-100), var(--color-gray-05));
|
--button-text-color: light-dark(var(--color-gray-100), var(--color-gray-05));
|
||||||
|
|
@ -30,11 +32,11 @@
|
||||||
--color-accent-primary-active: light-dark(var(--color-blue-70), var(--color-cyan-20));
|
--color-accent-primary-active: light-dark(var(--color-blue-70), var(--color-cyan-20));
|
||||||
|
|
||||||
/** Font Size **/
|
/** Font Size **/
|
||||||
--font-size-root: 15px; /* Set at the `:root`. Do not use */
|
--font-size-root: 15px;
|
||||||
--font-size-small: 0.867rem; /* 13px */
|
--font-size-small: 0.867rem;
|
||||||
--font-size-large: 1.133rem; /* 17px */
|
--font-size-large: 1.133rem;
|
||||||
--font-size-xlarge: 1.467rem; /* 22px */
|
--font-size-xlarge: 1.467rem;
|
||||||
--font-size-xxlarge: 1.6rem; /* 24px */
|
--font-size-xxlarge: 1.6rem;
|
||||||
|
|
||||||
/** Link **/
|
/** Link **/
|
||||||
--link-color: var(--color-accent-primary);
|
--link-color: var(--color-accent-primary);
|
||||||
|
|
|
||||||
428
toolkit/themes/shared/design-system/tokens-config.js
Normal file
428
toolkit/themes/shared/design-system/tokens-config.js
Normal file
|
|
@ -0,0 +1,428 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* eslint-env node */
|
||||||
|
|
||||||
|
const StyleDictionary = require("style-dictionary");
|
||||||
|
const { createPropertyFormatter } = StyleDictionary.formatHelpers;
|
||||||
|
const TOKEN_SECTIONS = {
|
||||||
|
"Attention Dot": "attention-dot",
|
||||||
|
"Background Color": "background-color",
|
||||||
|
Border: "border",
|
||||||
|
"Box Shadow": "box-shadow",
|
||||||
|
Button: "button",
|
||||||
|
Checkbox: "checkbox",
|
||||||
|
Color: ["brand-color", "color", "platform-color"],
|
||||||
|
"Focus Outline": "focus-outline",
|
||||||
|
"Font Size": "font-size",
|
||||||
|
"Font Weight": "font-weight",
|
||||||
|
Icon: "icon",
|
||||||
|
"Input - Text": "input-text",
|
||||||
|
Link: "link",
|
||||||
|
"Outline Color": "outline-color",
|
||||||
|
Size: "size",
|
||||||
|
Space: "space",
|
||||||
|
Text: "text",
|
||||||
|
Unspecified: "",
|
||||||
|
};
|
||||||
|
const TSHIRT_ORDER = [
|
||||||
|
"circle",
|
||||||
|
"xxxsmall",
|
||||||
|
"xxsmall",
|
||||||
|
"xsmall",
|
||||||
|
"small",
|
||||||
|
"medium",
|
||||||
|
"large",
|
||||||
|
"xlarge",
|
||||||
|
"xxlarge",
|
||||||
|
"xxxlarge",
|
||||||
|
];
|
||||||
|
const STATE_ORDER = [
|
||||||
|
"base",
|
||||||
|
"default",
|
||||||
|
"root",
|
||||||
|
"hover",
|
||||||
|
"active",
|
||||||
|
"focus",
|
||||||
|
"disabled",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the Mozilla Public License header in one comment and
|
||||||
|
* how to make changes in the generated output files via the
|
||||||
|
* design-tokens.json file in another comment. Also imports
|
||||||
|
* tokens-shared.css when applicable.
|
||||||
|
*
|
||||||
|
* @param {string} surface
|
||||||
|
* Desktop surface, either "brand" or "platform". Determines
|
||||||
|
* whether or not we need to import tokens-shared.css.
|
||||||
|
* @returns {string} Formatted comment header string
|
||||||
|
*/
|
||||||
|
let customFileHeader = surface => {
|
||||||
|
let licenseString = [
|
||||||
|
"/* This Source Code Form is subject to the terms of the Mozilla Public",
|
||||||
|
" * License, v. 2.0. If a copy of the MPL was not distributed with this",
|
||||||
|
" * file, You can obtain one at http://mozilla.org/MPL/2.0/. */",
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
let commentString = [
|
||||||
|
"/* DO NOT EDIT this file directly, instead modify design-tokens.json",
|
||||||
|
" * and run `npm run build` to see your changes. */",
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
let cssImport = surface
|
||||||
|
? `@import url("chrome://global/skin/design-system/tokens-shared.css");\n\n`
|
||||||
|
: "";
|
||||||
|
let layerString = !surface
|
||||||
|
? `@layer tokens-foundation, tokens-prefers-contrast, tokens-forced-colors;\n\n`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return [
|
||||||
|
licenseString + "\n\n" + commentString + "\n\n" + cssImport + layerString,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const NEST_MEDIA_QUERIES_COMMENT = `/* Bug 1879900: Can't nest media queries inside of :host, :root selector
|
||||||
|
until Bug 1879349 lands */`;
|
||||||
|
|
||||||
|
const MEDIA_QUERY_PROPERTY_MAP = {
|
||||||
|
"forced-colors": "forcedColors",
|
||||||
|
"prefers-contrast": "prefersContrast",
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatBaseTokenNames(str) {
|
||||||
|
return str.replaceAll(/(?<tokenName>\w+)-base(?=\b)/g, "$<tokenName>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a surface-specific formatter. The formatter is used to build
|
||||||
|
* our different CSS files, including "prefers-contrast" and "forced-colors"
|
||||||
|
* media queries. See more at
|
||||||
|
* https://amzn.github.io/style-dictionary/#/formats?id=formatter
|
||||||
|
*
|
||||||
|
* @param {string} surface
|
||||||
|
* Which desktop area we are generating CSS for.
|
||||||
|
* Either "brand" (i.e. in-content) or "platform" (i.e. chrome).
|
||||||
|
* @returns {Function} - Formatter function that returns a CSS string.
|
||||||
|
*/
|
||||||
|
const createDesktopFormat = surface => args => {
|
||||||
|
return formatBaseTokenNames(
|
||||||
|
customFileHeader(surface) +
|
||||||
|
formatTokens({
|
||||||
|
surface,
|
||||||
|
args,
|
||||||
|
}) +
|
||||||
|
formatTokens({
|
||||||
|
mediaQuery: "prefers-contrast",
|
||||||
|
surface,
|
||||||
|
args,
|
||||||
|
}) +
|
||||||
|
formatTokens({
|
||||||
|
mediaQuery: "forced-colors",
|
||||||
|
surface,
|
||||||
|
args,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a subset of tokens into CSS. Wraps token CSS in a media query when
|
||||||
|
* applicable.
|
||||||
|
*
|
||||||
|
* @param {object} tokenArgs
|
||||||
|
* @param {string} [tokenArgs.mediaQuery]
|
||||||
|
* Media query formatted CSS should be wrapped in. This is used
|
||||||
|
* to determine what property we are parsing from the token values.
|
||||||
|
* @param {string} [tokenArgs.surface]
|
||||||
|
* Specifies a desktop surface, either "brand" or "platform".
|
||||||
|
* @param {object} tokenArgs.args
|
||||||
|
* Formatter arguments provided by style-dictionary. See more at
|
||||||
|
* https://amzn.github.io/style-dictionary/#/formats?id=formatter
|
||||||
|
* @returns {string} Tokens formatted into a CSS string.
|
||||||
|
*/
|
||||||
|
function formatTokens({ mediaQuery, surface, args }) {
|
||||||
|
let prop = MEDIA_QUERY_PROPERTY_MAP[mediaQuery] ?? "default";
|
||||||
|
let dictionary = Object.assign({}, args.dictionary);
|
||||||
|
let tokens = [];
|
||||||
|
|
||||||
|
dictionary.allTokens.forEach(token => {
|
||||||
|
let originalVal = getOriginalTokenValue(token, prop, surface);
|
||||||
|
if (originalVal != undefined) {
|
||||||
|
let formattedToken = transformTokenValue(token, originalVal, dictionary);
|
||||||
|
tokens.push(formattedToken);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tokens.length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary.allTokens = dictionary.allProperties = tokens;
|
||||||
|
|
||||||
|
let formattedVars = formatVariables({
|
||||||
|
format: "css",
|
||||||
|
dictionary,
|
||||||
|
outputReferences: args.options.outputReferences,
|
||||||
|
formatting: {
|
||||||
|
indentation: mediaQuery ? " " : " ",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let layer = `tokens-${mediaQuery ?? "foundation"}`;
|
||||||
|
// Weird spacing below is unfortunately necessary for formatting the built CSS.
|
||||||
|
if (mediaQuery) {
|
||||||
|
return `
|
||||||
|
${NEST_MEDIA_QUERIES_COMMENT}
|
||||||
|
@layer ${layer} {
|
||||||
|
@media (${mediaQuery}) {
|
||||||
|
:root,
|
||||||
|
:host(.anonymous-content-host) {
|
||||||
|
${formattedVars}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `@layer ${layer} {
|
||||||
|
:root,
|
||||||
|
:host(.anonymous-content-host) {
|
||||||
|
${formattedVars}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the original value of a token for a given media query and surface.
|
||||||
|
*
|
||||||
|
* @param {object} token - Token object parsed by style-dictionary.
|
||||||
|
* @param {string} prop - Name of the property we're querying for.
|
||||||
|
* @param {string} surface
|
||||||
|
* The desktop surface we're generating CSS for, either "brand" or "platform".
|
||||||
|
* @returns {string} The original token value based on our parameters.
|
||||||
|
*/
|
||||||
|
function getOriginalTokenValue(token, prop, surface) {
|
||||||
|
if (surface) {
|
||||||
|
return token.original.value[surface]?.[prop];
|
||||||
|
} else if (prop == "default" && typeof token.original.value != "object") {
|
||||||
|
return token.original.value;
|
||||||
|
}
|
||||||
|
return token.original.value?.[prop];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a token's value to the relevant original value after resolving
|
||||||
|
* variable references.
|
||||||
|
*
|
||||||
|
* @param {object} token - Token object parsed from JSON by style-dictionary.
|
||||||
|
* @param {string} originalVal
|
||||||
|
* Original value of the token for the combination of surface and media query.
|
||||||
|
* @param {object} dictionary
|
||||||
|
* Object of transformed tokens and helper fns provided by style-dictionary.
|
||||||
|
* @returns {object} Token object with an updated value.
|
||||||
|
*/
|
||||||
|
function transformTokenValue(token, originalVal, dictionary) {
|
||||||
|
let value = originalVal;
|
||||||
|
if (dictionary.usesReference(value)) {
|
||||||
|
dictionary.getReferences(value).forEach(ref => {
|
||||||
|
value = value.replace(`{${ref.path.join(".")}}`, `var(--${ref.name})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return { ...token, value };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a light-dark transform that works for a given surface. Registers
|
||||||
|
* the transform with style-dictionary and returns the transform's name.
|
||||||
|
*
|
||||||
|
* @param {string} surface
|
||||||
|
* The desktop surface we're generating CSS for, either "brand", "platform",
|
||||||
|
* or "shared".
|
||||||
|
* @returns {string} Name of the transform that was registered.
|
||||||
|
*/
|
||||||
|
const createLightDarkTransform = surface => {
|
||||||
|
let name = `lightDarkTransform/${surface}`;
|
||||||
|
|
||||||
|
// Matcher function for determining if a token's value needs to undergo
|
||||||
|
// a light-dark transform.
|
||||||
|
let matcher = token => {
|
||||||
|
if (surface != "shared") {
|
||||||
|
return (
|
||||||
|
token.original.value[surface]?.light &&
|
||||||
|
token.original.value[surface]?.dark
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return token.original.value.light && token.original.value.dark;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function that uses the token's original value to create a new "default"
|
||||||
|
// light-dark value and updates the original value object.
|
||||||
|
let transformer = token => {
|
||||||
|
if (surface != "shared") {
|
||||||
|
let lightDarkVal = `light-dark(${token.original.value[surface].light}, ${token.original.value[surface].dark})`;
|
||||||
|
token.original.value[surface].default = lightDarkVal;
|
||||||
|
return token.value;
|
||||||
|
}
|
||||||
|
let value = `light-dark(${token.original.value.light}, ${token.original.value.dark})`;
|
||||||
|
token.original.value.default = value;
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
StyleDictionary.registerTransform({
|
||||||
|
type: "value",
|
||||||
|
transitive: true,
|
||||||
|
name,
|
||||||
|
matcher,
|
||||||
|
transformer,
|
||||||
|
});
|
||||||
|
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the tokens dictionary to a string. This mostly defers to
|
||||||
|
* StyleDictionary.createPropertyFormatter but first it sorts the tokens based
|
||||||
|
* on the groupings in TOKEN_SECTIONS and adds comment headers to CSS output.
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
* Options for tokens to format.
|
||||||
|
* @param {string} options.format
|
||||||
|
* The format to output. Supported: "css"
|
||||||
|
* @param {object} options.dictionary
|
||||||
|
* The tokens dictionary.
|
||||||
|
* @param {string} options.outputReferences
|
||||||
|
* Whether to output variable references.
|
||||||
|
* @param {object} options.formatting
|
||||||
|
* The formatting settings to be passed to createPropertyFormatter.
|
||||||
|
* @returns {string} The formatted tokens.
|
||||||
|
*/
|
||||||
|
function formatVariables({ format, dictionary, outputReferences, formatting }) {
|
||||||
|
let lastSection = [];
|
||||||
|
let propertyFormatter = createPropertyFormatter({
|
||||||
|
outputReferences,
|
||||||
|
dictionary,
|
||||||
|
format,
|
||||||
|
formatting,
|
||||||
|
});
|
||||||
|
|
||||||
|
let outputParts = [];
|
||||||
|
let remainingTokens = [...dictionary.allTokens];
|
||||||
|
let isFirst = true;
|
||||||
|
|
||||||
|
function tokenParts(name) {
|
||||||
|
let lastDash = name.lastIndexOf("-");
|
||||||
|
let suffix = name.substring(lastDash + 1);
|
||||||
|
if (TSHIRT_ORDER.includes(suffix) || STATE_ORDER.includes(suffix)) {
|
||||||
|
return [name.substring(0, lastDash), suffix];
|
||||||
|
}
|
||||||
|
return [name, ""];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [label, selector] of Object.entries(TOKEN_SECTIONS)) {
|
||||||
|
let sectionMatchers = Array.isArray(selector) ? selector : [selector];
|
||||||
|
let sectionParts = [];
|
||||||
|
|
||||||
|
remainingTokens = remainingTokens.filter(token => {
|
||||||
|
if (
|
||||||
|
sectionMatchers.some(m =>
|
||||||
|
m.test ? m.test(token.name) : token.name.startsWith(m)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
sectionParts.push(token);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sectionParts.length) {
|
||||||
|
sectionParts.sort((a, b) => {
|
||||||
|
let aName = formatBaseTokenNames(a.name);
|
||||||
|
let bName = formatBaseTokenNames(b.name);
|
||||||
|
let [aToken, aSuffix] = tokenParts(aName);
|
||||||
|
let [bToken, bSuffix] = tokenParts(bName);
|
||||||
|
if (aSuffix || bSuffix) {
|
||||||
|
if (aToken == bToken) {
|
||||||
|
let aSize = TSHIRT_ORDER.indexOf(aSuffix);
|
||||||
|
let bSize = TSHIRT_ORDER.indexOf(bSuffix);
|
||||||
|
if (aSize != -1 && bSize != -1) {
|
||||||
|
return aSize - bSize;
|
||||||
|
}
|
||||||
|
let aState = STATE_ORDER.indexOf(aSuffix);
|
||||||
|
let bState = STATE_ORDER.indexOf(bSuffix);
|
||||||
|
if (aState != -1 && bState != -1) {
|
||||||
|
return aState - bState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aToken.localeCompare(bToken, undefined, { numeric: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
let headingParts = [];
|
||||||
|
if (!isFirst) {
|
||||||
|
headingParts.push("");
|
||||||
|
}
|
||||||
|
isFirst = false;
|
||||||
|
|
||||||
|
let sectionLevel = "**";
|
||||||
|
let labelParts = label.split("/");
|
||||||
|
for (let i = 0; i < labelParts.length; i++) {
|
||||||
|
if (labelParts[i] != lastSection[i]) {
|
||||||
|
headingParts.push(
|
||||||
|
`${formatting.indentation}/${sectionLevel} ${labelParts[i]} ${sectionLevel}/`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
sectionLevel += "*";
|
||||||
|
}
|
||||||
|
lastSection = labelParts;
|
||||||
|
|
||||||
|
outputParts = outputParts.concat(
|
||||||
|
headingParts.concat(sectionParts.map(propertyFormatter))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputParts.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
source: ["design-tokens.json"],
|
||||||
|
format: {
|
||||||
|
"css/variables/shared": createDesktopFormat(),
|
||||||
|
"css/variables/brand": createDesktopFormat("brand"),
|
||||||
|
"css/variables/platform": createDesktopFormat("platform"),
|
||||||
|
},
|
||||||
|
platforms: {
|
||||||
|
css: {
|
||||||
|
options: {
|
||||||
|
outputReferences: true,
|
||||||
|
showFileHeader: false,
|
||||||
|
},
|
||||||
|
transforms: [
|
||||||
|
...StyleDictionary.transformGroup.css,
|
||||||
|
...["shared", "platform", "brand"].map(createLightDarkTransform),
|
||||||
|
],
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
destination: "tokens-shared.css",
|
||||||
|
format: "css/variables/shared",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
destination: "tokens-brand.css",
|
||||||
|
format: "css/variables/brand",
|
||||||
|
filter: token =>
|
||||||
|
typeof token.original.value == "object" &&
|
||||||
|
token.original.value.brand,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
destination: "tokens-platform.css",
|
||||||
|
format: "css/variables/platform",
|
||||||
|
filter: token =>
|
||||||
|
typeof token.original.value == "object" &&
|
||||||
|
token.original.value.platform,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* DO NOT EDIT this file directly, instead modify design-tokens.json
|
||||||
|
* and run `npm run build` to see your changes. */
|
||||||
|
|
||||||
@import url("chrome://global/skin/design-system/tokens-shared.css");
|
@import url("chrome://global/skin/design-system/tokens-shared.css");
|
||||||
|
|
||||||
@layer tokens-foundation {
|
@layer tokens-foundation {
|
||||||
|
|
@ -17,7 +20,7 @@
|
||||||
--border-color-interactive: color-mix(in srgb, currentColor 15%, var(--color-gray-60));
|
--border-color-interactive: color-mix(in srgb, currentColor 15%, var(--color-gray-60));
|
||||||
|
|
||||||
/** Button **/
|
/** Button **/
|
||||||
--button-background-color: var(--button-bgcolor);
|
--button-background-color: var(--button-bgcolor); /* TODO Bug 1821203 - Gray use needs to be consolidated */
|
||||||
--button-background-color-hover: var(--button-hover-bgcolor);
|
--button-background-color-hover: var(--button-hover-bgcolor);
|
||||||
--button-background-color-active: var(--button-active-bgcolor);
|
--button-background-color-active: var(--button-active-bgcolor);
|
||||||
--button-text-color: var(--button-color);
|
--button-text-color: var(--button-color);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* DO NOT EDIT this file directly, instead modify design-tokens.json
|
||||||
|
* and run `npm run build` to see your changes. */
|
||||||
|
|
||||||
@layer tokens-foundation, tokens-prefers-contrast, tokens-forced-colors;
|
@layer tokens-foundation, tokens-prefers-contrast, tokens-forced-colors;
|
||||||
|
|
||||||
@layer tokens-foundation {
|
@layer tokens-foundation {
|
||||||
|
|
@ -85,8 +88,7 @@
|
||||||
|
|
||||||
/** Checkbox **/
|
/** Checkbox **/
|
||||||
--checkbox-margin-inline: var(--space-small);
|
--checkbox-margin-inline: var(--space-small);
|
||||||
/* TODO Bug 1876537: Make this em-based, probably? */
|
--checkbox-size: var(--size-item-small); /* TODO Bug 1876537: Make this em-based, probably? */
|
||||||
--checkbox-size: var(--size-item-small);
|
|
||||||
|
|
||||||
/** Color **/
|
/** Color **/
|
||||||
--color-black-a10: rgba(0, 0, 0, 0.1);
|
--color-black-a10: rgba(0, 0, 0, 0.1);
|
||||||
|
|
@ -147,9 +149,11 @@
|
||||||
--input-text-min-height: var(--button-min-height);
|
--input-text-min-height: var(--button-min-height);
|
||||||
|
|
||||||
/** Link **/
|
/** Link **/
|
||||||
/* Not using --focus-outline-offset for links because that's intended for
|
/**
|
||||||
elements with a background, and we only want a slight offset here while not
|
* Not using --force-outline-offset for links because that's intended for
|
||||||
overlapping adjacent text. */
|
* elements with a background, and we only want a slight offset here while
|
||||||
|
* not overlapping adjacent text
|
||||||
|
*/
|
||||||
--link-focus-outline-offset: 1px;
|
--link-focus-outline-offset: 1px;
|
||||||
|
|
||||||
/** Outline Color **/
|
/** Outline Color **/
|
||||||
|
|
@ -226,7 +230,6 @@
|
||||||
|
|
||||||
/* Bug 1879900: Can't nest media queries inside of :host, :root selector
|
/* Bug 1879900: Can't nest media queries inside of :host, :root selector
|
||||||
until Bug 1879349 lands */
|
until Bug 1879349 lands */
|
||||||
/* NOTE: These do not apply in the browser chrome (bug 1878919). */
|
|
||||||
@layer tokens-forced-colors {
|
@layer tokens-forced-colors {
|
||||||
@media (forced-colors) {
|
@media (forced-colors) {
|
||||||
:root,
|
:root,
|
||||||
|
|
@ -238,7 +241,7 @@
|
||||||
--border-color-interactive-disabled: GrayText;
|
--border-color-interactive-disabled: GrayText;
|
||||||
|
|
||||||
/** Button **/
|
/** Button **/
|
||||||
--button-background-color: ButtonFace;
|
--button-background-color: ButtonFace; /* TODO Bug 1821203 - Gray use needs to be consolidated */
|
||||||
--button-background-color-hover: SelectedItemText;
|
--button-background-color-hover: SelectedItemText;
|
||||||
--button-background-color-active: SelectedItemText;
|
--button-background-color-active: SelectedItemText;
|
||||||
--button-background-color-disabled: ButtonFace;
|
--button-background-color-disabled: ButtonFace;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@
|
||||||
skin/classic/global/datetimeinputpickers.css (../../shared/datetimeinputpickers.css)
|
skin/classic/global/datetimeinputpickers.css (../../shared/datetimeinputpickers.css)
|
||||||
skin/classic/global/design-system/text-and-typography.css(../../shared/design-system/text-and-typography.css)
|
skin/classic/global/design-system/text-and-typography.css(../../shared/design-system/text-and-typography.css)
|
||||||
skin/classic/global/design-system/tokens-brand.css (../../shared/design-system/tokens-brand.css)
|
skin/classic/global/design-system/tokens-brand.css (../../shared/design-system/tokens-brand.css)
|
||||||
skin/classic/global/design-system/tokens-shared.css (../../shared/design-system/tokens-shared.css)
|
|
||||||
skin/classic/global/design-system/tokens-platform.css (../../shared/design-system/tokens-platform.css)
|
skin/classic/global/design-system/tokens-platform.css (../../shared/design-system/tokens-platform.css)
|
||||||
|
skin/classic/global/design-system/tokens-shared.css (../../shared/design-system/tokens-shared.css)
|
||||||
skin/classic/global/error-pages.css (../../shared/error-pages.css)
|
skin/classic/global/error-pages.css (../../shared/error-pages.css)
|
||||||
skin/classic/global/findbar.css (../../shared/findbar.css)
|
skin/classic/global/findbar.css (../../shared/findbar.css)
|
||||||
skin/classic/global/global-shared.css (../../shared/global-shared.css)
|
skin/classic/global/global-shared.css (../../shared/global-shared.css)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue