Bug 2051263 - Override color tokens that can't be imported from Figma r=desktop-theme-reviewers,hjones,fchasen

Figma's limitations mean that we need to override certain tokens in code. To better keep track of which tokens are being overridden, this also updates the build process to output audit files that we can reference to more easily identify tokens that need to be added or corrected in Figma.

Some tokens are moved from `tokens-shared.css` to `tokens-brand.css` and some tokens that are the same in Nova as Proton are removed, since the override isn't necessary.

Differential Revision: https://phabricator.services.mozilla.com/D320176
This commit is contained in:
Dustin Whisman
2026-09-03 18:00:26 +00:00
committed by dwhisman@mozilla.com
parent 80681147a0
commit 54d524b326
29 changed files with 456 additions and 393 deletions
+3
View File
@@ -392,6 +392,9 @@ browser/components/storybook/component-status/components.json
# Ignore design-system node_modules
toolkit/themes/shared/design-system/node_modules/
# Ignore design-system generated files
toolkit/themes/shared/design-system/dist/token-audit
# Ignore TypeScript declarations reference file updated by tooling.
tools/@types/index.d.ts
+3
View File
@@ -382,6 +382,9 @@ tps_result\.json$
# Ignore design-system node_modules
toolkit/themes/shared/design-system/node_modules/
# Ignore design-system generated files
toolkit/themes/shared/design-system/dist/token-audit
# Ignore TypeScript declarations reference file updated by tooling.
^tools/@types/index.d.ts
@@ -29,11 +29,10 @@
--border-color: light-dark(var(--color-gray-30), var(--color-gray-40));
--border-color-deemphasized: light-dark(var(--color-gray-20), var(--color-gray-50));
--border-color-error: light-dark(var(--color-red-50), var(--color-red-20));
--border-color-interactive: light-dark(var(--color-gray-35), var(--color-gray-40));
--border-color-interactive-hover: light-dark(var(--color-gray-45), var(--color-gray-20));
--border-color-interactive-active: light-dark(var(--color-gray-50), var(--color-gray-15));
--border-color-interactive-disabled: light-dark(var(--color-gray-25), var(--color-gray-55));
--border-color-transparent: transparent;
--border-color-interactive: light-dark(var(--color-gray-35), var(--color-gray-40));
--border-radius-xsmall: 4px;
--border-radius-small: 8px;
--border-radius-medium: 12px;
@@ -56,7 +55,6 @@
--button-background-color-destructive-hover: light-dark(var(--color-red-60), var(--color-red-20));
--button-background-color-destructive-active: light-dark(var(--color-red-70), var(--color-red-10));
--button-background-color-ghost: var(--button-background-color);
--button-background-color-ghost-disabled: var(--button-background-color-ghost);
--button-background-color-ghost-selected: var(--button-background-color-selected);
--button-background-color-menu: var(--button-background-color-ghost);
--button-background-color-muted: light-dark(var(--color-gray-20), var(--color-gray-55));
@@ -95,7 +93,6 @@
--button-text-color-destructive: light-dark(var(--color-white), var(--button-text-color-primary));
--button-text-color-destructive-disabled: var(--button-text-color-destructive);
--button-text-color-destructive-selected: light-dark(var(--button-text-color-destructive), var(--button-text-color-destructive-active));
--button-text-color-ghost: var(--button-text-color);
--button-text-color-ghost-hover: var(--button-text-color-ghost);
--button-text-color-ghost-active: var(--button-text-color-ghost);
--button-text-color-ghost-disabled: var(--button-text-color-ghost);
@@ -113,7 +110,6 @@
--button-text-color-selected: var(--button-text-color);
/** card **/
--card-border-color: light-dark(rgba(0, 0, 0, 6%), rgba(255, 255, 255, 4%));
--card-gap: var(--space-medium);
--card-header-background-color: var(--button-background-color);
--card-header-border-color: transparent;
@@ -280,13 +276,13 @@
--popup-border-radius: var(--border-radius-xlarge);
/** table **/
--table-row-background-color: var(--background-color-canvas);
/* TODO Bug 1821203 - Gray use needs to be consolidated */
--table-row-background-color-alternate: light-dark(var(--color-gray-20), var(--color-gray-65));
/** text-color **/
--text-color: light-dark(var(--color-violet-desaturated-90), var(--color-violet-desaturated-0));
--text-color-accent-primary-selected: light-dark(var(--color-white), var(--color-gray-55));
--text-color-error: light-dark(var(--color-red-50), var(--color-red-20));
/** toolbar **/
@@ -304,8 +300,6 @@
--toolbarbutton-icon-fill-attention: var(--color-accent-primary);
--toolbarbutton-opacity-disabled: 0.4;
--toolbarbutton-outline-color: transparent;
--toolbarbutton-outline-color-hover: transparent;
--toolbarbutton-outline-color-active: transparent;
--toolbarbutton-outline-color-selected: var(--toolbarbutton-outline-color-active);
--toolbarbutton-outline-offset: -1px;
@@ -321,24 +315,11 @@
@media (forced-colors) {
:root.nova-tokens {
/** background-color **/
--background-color-box: var(--background-color-canvas);
--background-color-box-info: var(--background-color-canvas);
--background-color-canvas: Canvas;
--background-color-critical: var(--background-color-canvas);
--background-color-information: var(--background-color-canvas);
--background-color-success: var(--background-color-canvas);
--background-color-warning: var(--background-color-canvas);
/** border **/
--border-color: CanvasText;
--border-color-deemphasized: CanvasText;
--border-color-error: var(--border-color);
--border-color-interactive: ButtonText;
--border-color-interactive-hover: SelectedItem;
--border-color-interactive-active: ButtonText;
--border-color-interactive-disabled: GrayText;
--border-color-transparent: CanvasText;
/** box-shadow **/
--box-shadow-color-darker-layer-1: transparent;
@@ -355,7 +336,6 @@
--button-background-color-destructive: var(--button-background-color-primary);
--button-background-color-destructive-hover: var(--button-background-color-primary-hover);
--button-background-color-destructive-active: var(--button-background-color-primary-active);
--button-background-color-ghost-disabled: var(--button-background-color-disabled);
--button-background-color-menu: var(--button-background-color);
--button-background-color-menu-hover: ButtonText;
--button-background-color-menu-active: ButtonText;
@@ -366,7 +346,6 @@
--button-background-color-muted-selected: var(--button-background-color-ghost-active);
--button-background-color-primary-disabled: GrayText;
--button-background-color-selected: SelectedItem;
--button-border-color: var(--border-color-interactive);
--button-border-color-destructive: var(--button-border-color-primary);
--button-border-color-destructive-selected: var(--button-border-color-destructive-active);
--button-border-color-ghost: var(--button-border-color);
@@ -389,7 +368,6 @@
--button-text-color-destructive-selected: var(--button-text-color-destructive-active);
--button-text-color-ghost: ButtonText;
--button-text-color-ghost-hover: var(--button-text-color-ghost-active);
--button-text-color-ghost-active: var(--button-text-color-active);
--button-text-color-ghost-disabled: GrayText;
--button-text-color-menu-hover: ButtonFace;
--button-text-color-menu-active: ButtonFace;
@@ -405,7 +383,6 @@
--button-text-color-selected: SelectedItemText;
/** card **/
--card-border-color: CanvasText;
--card-header-border-color: var(--button-border-color);
/** color **/
@@ -417,19 +394,10 @@
/** icon **/
--icon-color-accent-primary-desaturated: CanvasText;
--icon-color-critical: var(--icon-color);
--icon-color-information: var(--icon-color);
--icon-color-success: var(--icon-color);
--icon-color-warning: var(--icon-color);
/** popup **/
--popup-border-color: var(--border-color);
/** table **/
/* TODO Bug 1821203 - Gray use needs to be consolidated */
--table-row-background-color-alternate: var(--background-color-canvas);
/** text-color **/
--text-color-accent-primary-selected: SelectedItemText;
+2 -1
View File
@@ -32,11 +32,12 @@ GeneratedFile(
"aiwindow-nova/manifest.in.json",
"/browser/themes/shared/tabbrowser/tab.nova.tokens.json",
"/browser/themes/shared/urlbar/urlbarview.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/background.nova.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/background.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/color.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/color.nova.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/focus.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/base/text.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/components/card.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/components/card.nova.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/components/sidebar.tokens.json",
"/toolkit/themes/shared/design-system/src/tokens/components/toolbar.tokens.json",
+5
View File
@@ -26,6 +26,11 @@ def _pick_variant(resolved, variant):
return resolved[variant]
if "default" in resolved:
return resolved["default"]
if "brand" in resolved:
if variant in resolved["brand"]:
return resolved["brand"][variant]
else:
return resolved["brand"]
return resolved
@@ -2,6 +2,7 @@
* 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/. */
import { sep } from "node:path";
import { getLayerString } from "../desktop-format/get-layer-string.mjs";
const getFileName = file => {
@@ -9,7 +10,8 @@ const getFileName = file => {
return "the relevant *.tokens.json file";
}
const cssFileName = file.destination.split("/").at(-1);
// Windows file separators can end up mixed with forward slashes in these paths, so we check for them as well
const cssFileName = file.destination.split("/").at(-1).split(sep).at(-1);
return cssFileName.replace(".css", ".json");
};
@@ -10,7 +10,7 @@ export const createNovaNewtabFormat =
() =>
({ dictionary }) => {
let content = newtabFileHeader();
content += getNewtabTokenCSS({ dictionary, overrideIdentifier: "nova" });
content += getNewtabTokenCSS({ dictionary });
return postProcessNovaNewtab(`${content}\n`);
};
@@ -2,15 +2,12 @@
* 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/. */
import { getTokensByLayer } from "../desktop-format/get-tokens-by-layer.mjs";
import { getNewtabTokensByLayer } from "./get-newtab-tokens-by-layer.mjs";
export const getNewtabTokenCSS = ({ dictionary, overrideIdentifier }) => {
export const getNewtabTokenCSS = ({ dictionary }) => {
let content = "";
const { foundation, forcedColors } = getTokensByLayer({
dictionary,
overrideIdentifier,
});
const { foundation, forcedColors } = getNewtabTokensByLayer(dictionary);
if (foundation.length) {
content += `:root.nova-tokens {${foundation.join("\n ").replaceAll(" \n", "\n")}
@@ -0,0 +1,72 @@
/* 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/. */
import { formatToken } from "../desktop-format/format-token.mjs";
import { groupAndSortTokens } from "../desktop-format/group-and-sort-tokens.mjs";
import { shouldSkipToken } from "../desktop-format/should-skip-token.mjs";
/**
* Tokens grouped by layers.
*
* @typedef {object} layers
* @property {string[]} foundation - Foundation tokens
* @property {string[]} forcedColors - Forced colors tokens
*/
/**
* Get foundation and forced colors tokens that are different in Nova, checking
* for brand tokens, then falling back to default values.
*
* @param {object} dictionary - The token dictionary, provided by style-dictionary.
* @returns {layers}
*/
export const getNewtabTokensByLayer = dictionary => {
const overrideIdentifier = "nova";
const tokens = dictionary.allTokens;
const layers = {
foundation: [],
forcedColors: [],
};
tokens.forEach(token => {
if (shouldSkipToken({ overrideIdentifier, token })) {
return;
}
const comment = token.comment;
const originalName = token.name;
let originalValue = token.original.value;
if (token.original.value.nova?.value) {
originalValue = token.original.value.nova.value;
}
const foundationToken = formatToken({
originalName,
originalValue: originalValue.brand ?? originalValue,
tokens: dictionary.tokens,
comment,
overrideIdentifier,
});
if (foundationToken) {
layers.foundation.push(foundationToken);
}
const forcedColorsToken = formatToken({
originalName,
originalValue:
originalValue.brand?.forcedColors ?? originalValue.forcedColors,
tokens: dictionary.tokens,
comment,
overrideIdentifier,
});
if (forcedColorsToken) {
layers.forcedColors.push(forcedColorsToken);
}
});
return {
foundation: groupAndSortTokens({ tokens: layers.foundation }),
forcedColors: groupAndSortTokens({ tokens: layers.forcedColors }),
};
};
@@ -2,57 +2,37 @@
"background/color/box": {
"light": "{Colors$color/white}",
"dark": "{Colors$color/gray/70}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"background/color/box/info": {
"light": "{Colors$color/gray/15}",
"dark": "{Colors$color/gray/65}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"background/color/canvas": {
"light": "{Colors$color/gray/05}",
"dark": "{Colors$color/gray/85}",
"forcedColors": "{HCM Theme$Canvas}"
"forcedColors": "transparent"
},
"background/color/critical": {
"light": "{Colors$color/red/10}",
"dark": "{Colors$color/red/70}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"background/color/information": {
"light": "{Colors$color/violet/10}",
"dark": "{Colors$color/violet/70}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"background/color/success": {
"light": "{Colors$color/green/10}",
"dark": "{Colors$color/green/70}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"background/color/warning": {
"light": "{Colors$color/yellow/10}",
"dark": "{Colors$color/yellow/70}",
"forcedColors": "{Theme$background/color/canvas}"
},
"border/color": {
"light": "{Colors$color/gray/30}",
"dark": "{Colors$color/gray/40}",
"forcedColors": "{HCM Theme$CanvasText}"
},
"border/color/transparent": {
"light": "transparent",
"dark": "transparent",
"forcedColors": "{HCM Theme$CanvasText}"
},
"border/color/deemphasized": {
"light": "{Colors$color/gray/20}",
"dark": "{Colors$color/gray/50}",
"forcedColors": "{HCM Theme$CanvasText}"
},
"border/color/interactive": {
"light": "{Colors$color/gray/35}",
"dark": "{Colors$color/gray/40}",
"forcedColors": "{HCM Theme$ButtonText}"
"forcedColors": "transparent"
},
"border/color/interactive/hover": {
"light": "{Colors$color/gray/45}",
@@ -69,10 +49,25 @@
"dark": "{Colors$color/gray/55}",
"forcedColors": "{HCM Theme$GrayText}"
},
"border/color": {
"light": "{Colors$color/gray/30}",
"dark": "{Colors$color/gray/40}",
"forcedColors": "transparent"
},
"border/color/deemphasized": {
"light": "{Colors$color/gray/20}",
"dark": "{Colors$color/gray/50}",
"forcedColors": "{HCM Theme$CanvasText}"
},
"border/color/interactive": {
"light": "{Colors$color/gray/35}",
"dark": "{Colors$color/gray/40}",
"forcedColors": "transparent"
},
"border/color/error": {
"light": "{Colors$color/red/50}",
"dark": "{Colors$color/red/20}",
"forcedColors": "{Theme$border/color}"
"forcedColors": "transparent"
},
"box-shadow/color/darker/layer-1": {
"light": "rgba(0, 0, 0, 0.15)",
@@ -179,11 +174,6 @@
"dark": "{Theme$button/background/color}",
"forcedColors": "{Theme$button/background/color}"
},
"button/background/color/ghost/disabled": {
"light": "{Theme$button/background/color/ghost}",
"dark": "{Theme$button/background/color/ghost}",
"forcedColors": "{Theme$button/background/color/disabled}"
},
"button/background/color/ghost/selected": {
"light": "{Theme$button/background/color/selected}",
"dark": "{Theme$button/background/color/selected}",
@@ -224,11 +214,6 @@
"dark": "{Theme$button/background/color/active}",
"forcedColors": "{HCM Theme$SelectedItem}"
},
"button/border/color": {
"light": "{Theme$color/accent/primary}",
"dark": "{Theme$color/accent/primary}",
"forcedColors": "{Theme$border/color/interactive}"
},
"button/border/color/destructive": {
"light": "{Theme$button/border/color/ghost}",
"dark": "{Theme$button/border/color/ghost}",
@@ -334,26 +319,6 @@
"dark": "{Theme$button/text/color/destructive/active}",
"forcedColors": "{Theme$button/text/color/destructive/active}"
},
"button/text/color/ghost": {
"light": "{Theme$button/text/color}",
"dark": "{Theme$button/text/color}",
"forcedColors": "{HCM Theme$ButtonText}"
},
"button/text/color/ghost/active": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{Theme$button/text/color/active}"
},
"button/text/color/ghost/disabled": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{HCM Theme$GrayText}"
},
"button/text/color/ghost/hover": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{Theme$button/text/color/ghost/active}"
},
"button/text/color/muted": {
"light": "{Theme$button/text/color}",
"dark": "{Theme$button/text/color}",
@@ -429,6 +394,31 @@
"dark": "transparent",
"forcedColors": "{HCM Theme$ButtonText}"
},
"button/border/color": {
"light": "{Theme$color/accent/primary}",
"dark": "{Theme$color/accent/primary}",
"forcedColors": "{Theme$color/accent/primary}"
},
"button/text/color/ghost": {
"light": "transparent",
"dark": "transparent",
"forcedColors": "transparent"
},
"button/text/color/ghost/active": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{Theme$button/text/color/ghost}"
},
"button/text/color/ghost/disabled": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{Theme$button/text/color/ghost}"
},
"button/text/color/ghost/hover": {
"light": "{Theme$button/text/color/ghost}",
"dark": "{Theme$button/text/color/ghost}",
"forcedColors": "{Theme$button/text/color/ghost/active}"
},
"button/text/color/menu/active": {
"light": "{Theme$button/text/color/ghost/active}",
"dark": "{Theme$button/text/color/active}",
@@ -439,11 +429,6 @@
"dark": "{Theme$button/text/color/hover}",
"forcedColors": "{HCM Theme$ButtonFace}"
},
"card/border/color": {
"light": "rgba(0, 0, 0, 0.06)",
"dark": "rgba(255, 255, 255, 0.04)",
"forcedColors": "{HCM Theme$CanvasText}"
},
"card/header/background/color": {
"light": "{Theme$button/background/color}",
"dark": "{Theme$button/background/color}",
@@ -467,22 +452,22 @@
"icon/color/information": {
"light": "{Colors$color/violet/50}",
"dark": "{Colors$color/violet/20}",
"forcedColors": "{Theme$icon/color}"
"forcedColors": "transparent"
},
"icon/color/success": {
"light": "{Colors$color/green/50}",
"dark": "{Colors$color/green/20}",
"forcedColors": "{Theme$icon/color}"
"forcedColors": "transparent"
},
"icon/color/warning": {
"light": "{Colors$color/yellow/50}",
"dark": "{Colors$color/yellow/20}",
"forcedColors": "{Theme$icon/color}"
"forcedColors": "transparent"
},
"icon/color/critical": {
"light": "{Colors$color/red/50}",
"dark": "{Colors$color/red/20}",
"forcedColors": "{Theme$icon/color}"
"forcedColors": "transparent"
},
"input/text/background/color": {
"light": "{Theme$background/color/box}",
@@ -514,15 +499,10 @@
"dark": "{Colors$color/gray/65}",
"forcedColors": "{Theme$border/color}"
},
"table/row/background/color": {
"light": "{Theme$background/color/canvas}",
"dark": "{Theme$background/color/canvas}",
"forcedColors": "{Theme$background/color/canvas}"
},
"table/row/background/color/alternate": {
"light": "{Colors$color/gray/20}",
"dark": "{Colors$color/gray/65}",
"forcedColors": "{Theme$background/color/canvas}"
"forcedColors": "transparent"
},
"toolbar/field/border/color": {
"light": "{Colors$color/gray/20}",
@@ -574,6 +554,11 @@
"dark": "transparent",
"forcedColors": "{Theme$button/border/color}"
},
"toolbarbutton/outline/color/selected": {
"light": "{Theme$toolbarbutton/outline/color/active}",
"dark": "{Theme$toolbarbutton/outline/color/active}",
"forcedColors": "{Theme$toolbarbutton/outline/color/active}"
},
"toolbarbutton/outline/color/hover": {
"light": "transparent",
"dark": "transparent",
@@ -584,11 +569,6 @@
"dark": "transparent",
"forcedColors": "{Theme$button/border/color/active}"
},
"toolbarbutton/outline/color/selected": {
"light": "{Theme$toolbarbutton/outline/color/active}",
"dark": "{Theme$toolbarbutton/outline/color/active}",
"forcedColors": "{Theme$toolbarbutton/outline/color/active}"
},
"toolbox/background/color/inactive": {
"light": "transparent",
"dark": "transparent",
@@ -471,7 +471,7 @@ export const tokensTable = {
name: "--table-header-background-color",
},
{
value: { default: "var(--background-color-canvas)" },
value: "var(--background-color-canvas)",
name: "--table-row-background-color",
},
{
@@ -4699,7 +4699,7 @@ export const variableLookupTable = {
},
platform: { default: "AccentColorText" },
},
"table-row-background-color": { default: "var(--background-color-canvas)" },
"table-row-background-color": "var(--background-color-canvas)",
"table-row-background-color-alternate": {
forcedColors: "var(--background-color-canvas)",
brand: {
@@ -73,8 +73,33 @@
@media -moz-pref("browser.nova.enabled") {
@layer tokens-foundation-brand-nova {
/** background-color **/
--background-color-box: light-dark(var(--color-white), var(--color-gray-70));
--background-color-box-info: light-dark(var(--color-gray-15), var(--color-gray-65));
--background-color-canvas: light-dark(var(--color-gray-05), var(--color-gray-85));
/** border **/
--border-color: light-dark(var(--color-gray-30), var(--color-gray-40));
--border-color-deemphasized: light-dark(var(--color-gray-20), var(--color-gray-50));
--border-color-interactive: light-dark(var(--color-gray-35), var(--color-gray-40));
/** button **/
--button-text-color-ghost-disabled: var(--button-text-color-ghost);
/** table **/
/* TODO Bug 1821203 - Gray use needs to be consolidated */
--table-row-background-color-alternate: light-dark(var(--color-gray-20), var(--color-gray-65));
/** text-color **/
--text-color-accent-primary-selected: light-dark(var(--color-white), var(--color-gray-55));
}
@layer tokens-forced-colors-nova {
@media (forced-colors) {
/** button **/
--button-text-color-ghost: ButtonText;
--button-text-color-ghost-disabled: GrayText;
}
}
}
}
@@ -744,23 +744,16 @@
@media -moz-pref("browser.nova.enabled") {
@layer tokens-foundation-nova {
/** background-color **/
--background-color-box: light-dark(var(--color-white), var(--color-gray-70));
--background-color-box-info: light-dark(var(--color-gray-15), var(--color-gray-65));
--background-color-canvas: light-dark(var(--color-gray-05), var(--color-gray-85));
--background-color-critical: light-dark(var(--color-red-10), var(--color-red-70));
--background-color-information: light-dark(var(--color-violet-10), var(--color-violet-70));
--background-color-success: light-dark(var(--color-green-10), var(--color-green-70));
--background-color-warning: light-dark(var(--color-yellow-10), var(--color-yellow-70));
/** border **/
--border-color: light-dark(var(--color-gray-30), var(--color-gray-40));
--border-color-deemphasized: light-dark(var(--color-gray-20), var(--color-gray-50));
--border-color-error: light-dark(var(--color-red-50), var(--color-red-20));
--border-color-interactive: light-dark(var(--color-gray-35), var(--color-gray-40));
--border-color-interactive-hover: light-dark(var(--color-gray-45), var(--color-gray-20));
--border-color-interactive-active: light-dark(var(--color-gray-50), var(--color-gray-15));
--border-color-interactive-disabled: light-dark(var(--color-gray-25), var(--color-gray-55));
--border-color-transparent: transparent;
--border-radius-xsmall: 4px;
--border-radius-small: 8px;
--border-radius-medium: 12px;
@@ -782,7 +775,6 @@
--button-background-color-destructive-hover: light-dark(var(--color-red-60), var(--color-red-20));
--button-background-color-destructive-active: light-dark(var(--color-red-70), var(--color-red-10));
--button-background-color-ghost: var(--button-background-color);
--button-background-color-ghost-disabled: var(--button-background-color-ghost);
--button-background-color-ghost-selected: var(--button-background-color-selected);
--button-background-color-menu: var(--button-background-color-ghost);
--button-background-color-muted: light-dark(var(--color-gray-20), var(--color-gray-55));
@@ -821,10 +813,8 @@
--button-text-color-destructive: light-dark(var(--color-white), var(--button-text-color-primary));
--button-text-color-destructive-disabled: var(--button-text-color-destructive);
--button-text-color-destructive-selected: light-dark(var(--button-text-color-destructive), var(--button-text-color-destructive-active));
--button-text-color-ghost: var(--button-text-color);
--button-text-color-ghost-hover: var(--button-text-color-ghost);
--button-text-color-ghost-active: var(--button-text-color-ghost);
--button-text-color-ghost-disabled: var(--button-text-color-ghost);
--button-text-color-menu-hover: light-dark(var(--button-text-color-ghost-hover), var(--button-text-color-hover));
--button-text-color-menu-active: light-dark(var(--button-text-color-ghost-active), var(--button-text-color-active));
--button-text-color-menu-disabled: light-dark(var(--button-text-color-ghost-disabled), var(--button-text-color-disabled));
@@ -839,7 +829,6 @@
--button-text-color-selected: var(--button-text-color);
/** card **/
--card-border-color: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.04));
--card-gap: var(--space-medium);
--card-header-background-color: var(--button-background-color);
--card-header-border-color: transparent;
@@ -1005,11 +994,6 @@
--popup-border-color: light-dark(var(--color-gray-10), var(--color-gray-65));
--popup-border-radius: var(--border-radius-xlarge);
/** table **/
--table-row-background-color: var(--background-color-canvas);
/* TODO Bug 1821203 - Gray use needs to be consolidated */
--table-row-background-color-alternate: light-dark(var(--color-gray-20), var(--color-gray-65));
/** text-color **/
--text-color: light-dark(var(--color-violet-desaturated-90), var(--color-violet-desaturated-0));
--text-color-error: light-dark(var(--color-red-50), var(--color-red-20));
@@ -1029,8 +1013,6 @@
--toolbarbutton-icon-fill-attention: var(--color-accent-primary);
--toolbarbutton-opacity-disabled: 0.4;
--toolbarbutton-outline-color: transparent;
--toolbarbutton-outline-color-hover: transparent;
--toolbarbutton-outline-color-active: transparent;
--toolbarbutton-outline-color-selected: var(--toolbarbutton-outline-color-active);
--toolbarbutton-outline-offset: -1px;
@@ -1060,24 +1042,11 @@
@layer tokens-forced-colors-nova {
@media (forced-colors) {
/** background-color **/
--background-color-box: var(--background-color-canvas);
--background-color-box-info: var(--background-color-canvas);
--background-color-canvas: Canvas;
--background-color-critical: var(--background-color-canvas);
--background-color-information: var(--background-color-canvas);
--background-color-success: var(--background-color-canvas);
--background-color-warning: var(--background-color-canvas);
/** border **/
--border-color: CanvasText;
--border-color-deemphasized: CanvasText;
--border-color-error: var(--border-color);
--border-color-interactive: ButtonText;
--border-color-interactive-hover: SelectedItem;
--border-color-interactive-active: ButtonText;
--border-color-interactive-disabled: GrayText;
--border-color-transparent: CanvasText;
/** box-shadow **/
--box-shadow-color-darker-layer-1: transparent;
@@ -1093,7 +1062,6 @@
--button-background-color-destructive: var(--button-background-color-primary);
--button-background-color-destructive-hover: var(--button-background-color-primary-hover);
--button-background-color-destructive-active: var(--button-background-color-primary-active);
--button-background-color-ghost-disabled: var(--button-background-color-disabled);
--button-background-color-menu: var(--button-background-color);
--button-background-color-menu-hover: ButtonText;
--button-background-color-menu-active: ButtonText;
@@ -1104,7 +1072,6 @@
--button-background-color-muted-selected: var(--button-background-color-ghost-active);
--button-background-color-primary-disabled: GrayText;
--button-background-color-selected: SelectedItem;
--button-border-color: var(--border-color-interactive);
--button-border-color-destructive: var(--button-border-color-primary);
--button-border-color-destructive-selected: var(--button-border-color-destructive-active);
--button-border-color-ghost: var(--button-border-color);
@@ -1125,10 +1092,7 @@
--button-text-color-destructive: var(--button-text-color-primary);
--button-text-color-destructive-disabled: var(--button-text-color-primary);
--button-text-color-destructive-selected: var(--button-text-color-destructive-active);
--button-text-color-ghost: ButtonText;
--button-text-color-ghost-hover: var(--button-text-color-ghost-active);
--button-text-color-ghost-active: var(--button-text-color-active);
--button-text-color-ghost-disabled: GrayText;
--button-text-color-menu-hover: ButtonFace;
--button-text-color-menu-active: ButtonFace;
--button-text-color-menu-disabled: var(--button-text-color-disabled);
@@ -1143,7 +1107,6 @@
--button-text-color-selected: SelectedItemText;
/** card **/
--card-border-color: CanvasText;
--card-header-border-color: var(--button-border-color);
/** color **/
@@ -1155,18 +1118,10 @@
/** icon **/
--icon-color-accent-primary-desaturated: CanvasText;
--icon-color-critical: var(--icon-color);
--icon-color-information: var(--icon-color);
--icon-color-success: var(--icon-color);
--icon-color-warning: var(--icon-color);
/** popup **/
--popup-border-color: var(--border-color);
/** table **/
/* TODO Bug 1821203 - Gray use needs to be consolidated */
--table-row-background-color-alternate: var(--background-color-canvas);
/** text-color **/
--text-color-accent-primary-selected: SelectedItemText;
+2 -2
View File
@@ -455,7 +455,7 @@ export const tokensTable = {
name: "--sidebar-background-color",
},
{
value: { default: "var(--background-color-canvas)" },
value: "var(--background-color-canvas)",
name: "--table-row-background-color",
},
{
@@ -4701,7 +4701,7 @@ export const variableLookupTable = {
},
platform: { default: "AccentColorText" },
},
"table-row-background-color": { default: "var(--background-color-canvas)" },
"table-row-background-color": "var(--background-color-canvas)",
"table-row-background-color-alternate": {
forcedColors: "var(--background-color-canvas)",
brand: {
@@ -4,6 +4,7 @@
import {
existsSync,
mkdirSync,
readdirSync,
readFileSync,
unlinkSync,
@@ -414,6 +415,84 @@ export function computeNovaValues(exportData) {
// `figma-variables-all.json` is only a full mirror it diffs against.
export const IMPORTED_VARIABLES_FILENAME = "nova-export-clean-variables.json";
/**
* Compare tokens from Figma to tokens defined in code, and
* write their definitions in files for three cases:
* - tokens that only exist in Figma
* - tokens that only exist in code
* - tokens that are overridden in code due to incorrect values in Figma or limitations in Figma
*
* @param {object} figmaTokens
* @param {object} codeTokens
*/
const writeTokenAuditData = (figmaTokens, codeTokens) => {
const unusedFigmaTokens = {};
const codeOnlyTokens = {};
const codeOverrideTokens = {};
for (const [tokenName, tokenValue] of Object.entries(figmaTokens)) {
const normalizedTokenName = tokenName.replace("/@base", "");
if (!codeTokens[normalizedTokenName]) {
unusedFigmaTokens[normalizedTokenName] = tokenValue;
} else {
codeOverrideTokens[normalizedTokenName] = {
figma: tokenValue,
code: codeTokens[normalizedTokenName],
};
}
}
for (const [tokenName, tokenValue] of Object.entries(codeTokens)) {
const normalizedTokenName = tokenName.replace("/@base", "");
if (!figmaTokens[normalizedTokenName]) {
codeOnlyTokens[normalizedTokenName] = tokenValue;
}
const normalizedTokenValue = {
light: figmaTokens[`${normalizedTokenName}/light`],
dark: figmaTokens[`${normalizedTokenName}/dark`],
forcedColors: figmaTokens[`${normalizedTokenName}/forcedColors`],
};
if (
normalizedTokenValue.light ||
normalizedTokenValue.dark ||
normalizedTokenValue.forcedColors
) {
codeOverrideTokens[normalizedTokenName] = {
figma: normalizedTokenValue,
code: tokenValue,
};
delete codeOnlyTokens[normalizedTokenName];
delete unusedFigmaTokens[`${normalizedTokenName}/light`];
delete unusedFigmaTokens[`${normalizedTokenName}/dark`];
delete unusedFigmaTokens[`${normalizedTokenName}/forcedColors`];
}
}
const OUTPUT_PATH = "../dist/token-audit";
if (!existsSync(joinRelativePath(OUTPUT_PATH))) {
mkdirSync(joinRelativePath(OUTPUT_PATH));
}
writeFileSync(
joinRelativePath(OUTPUT_PATH, "unused-figma-tokens.json"),
JSON.stringify(unusedFigmaTokens, null, 2),
"utf8"
);
writeFileSync(
joinRelativePath(OUTPUT_PATH, "code-only-tokens.json"),
JSON.stringify(codeOnlyTokens, null, 2),
"utf8"
);
writeFileSync(
joinRelativePath(OUTPUT_PATH, "code-override-tokens.json"),
JSON.stringify(codeOverrideTokens, null, 2),
"utf8"
);
};
const isMain = process.argv[1] === fileURLToPath(import.meta.url);
if (isMain) {
const exportData = JSON.parse(
@@ -428,11 +507,5 @@ if (isMain) {
}
writeTokens();
// eslint-disable-next-line no-console
console.log("Remaining Figma vars:", figmaVars);
// eslint-disable-next-line no-console
console.log(
"Tokens in code that take precedence over Figma:",
localOverrides
);
writeTokenAuditData(figmaVars, localOverrides);
}
@@ -1,55 +0,0 @@
{
"color": {
"box": {
"@base": {
"value": {
"light": "{color.white.@base}",
"dark": "{color.gray.70}",
"forcedColors": "{background.color.canvas}"
}
},
"info": {
"value": {
"light": "{color.gray.15}",
"dark": "{color.gray.65}",
"forcedColors": "{background.color.canvas}"
}
}
},
"canvas": {
"value": {
"light": "{color.gray.05}",
"dark": "{color.gray.85}",
"forcedColors": "Canvas"
}
},
"critical": {
"value": {
"light": "{color.red.10}",
"dark": "{color.red.70}",
"forcedColors": "{background.color.canvas}"
}
},
"information": {
"value": {
"light": "{color.violet.10}",
"dark": "{color.violet.70}",
"forcedColors": "{background.color.canvas}"
}
},
"success": {
"value": {
"light": "{color.green.10}",
"dark": "{color.green.70}",
"forcedColors": "{background.color.canvas}"
}
},
"warning": {
"value": {
"light": "{color.yellow.10}",
"dark": "{color.yellow.70}",
"forcedColors": "{background.color.canvas}"
}
}
}
}
@@ -5,7 +5,16 @@
"value": {
"light": "{color.white.@base}",
"dark": "{color.gray.80}",
"prefersContrast": "{background.color.canvas}"
"prefersContrast": "{background.color.canvas}",
"nova": {
"comment": "Maintain the brand/platform split and use prefersContrast over forcedColors",
"value": {
"brand": {
"light": "{color.white.@base}",
"dark": "{color.gray.70}"
}
}
}
}
},
"info": {
@@ -17,6 +26,15 @@
},
"platform": {
"default": "color-mix(in srgb, currentColor 6%, transparent)"
},
"nova": {
"comment": "Maintain the brand/platform split and use prefersContrast over forcedColors",
"value": {
"brand": {
"light": "{color.gray.15}",
"dark": "{color.gray.65}"
}
}
}
}
}
@@ -30,6 +48,15 @@
},
"platform": {
"default": "Canvas"
},
"nova": {
"comment": "Maintain the brand/platform split and use prefersContrast over forcedColors",
"value": {
"brand": {
"light": "{color.gray.05}",
"dark": "{color.gray.85}"
}
}
}
}
},
@@ -37,28 +64,56 @@
"value": {
"light": "{color.red.0}",
"dark": "{color.red.90}",
"prefersContrast": "{background.color.canvas}"
"prefersContrast": "{background.color.canvas}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.red.10}",
"dark": "{color.red.70}"
}
}
}
},
"information": {
"value": {
"light": "{color.blue.0}",
"dark": "{color.blue.90}",
"prefersContrast": "{background.color.canvas}"
"prefersContrast": "{background.color.canvas}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.violet.10}",
"dark": "{color.violet.70}"
}
}
}
},
"success": {
"value": {
"light": "{color.green.0}",
"dark": "{color.green.90}",
"prefersContrast": "{background.color.canvas}"
"prefersContrast": "{background.color.canvas}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.green.10}",
"dark": "{color.green.70}"
}
}
}
},
"warning": {
"value": {
"light": "{color.yellow.0}",
"dark": "{color.yellow.90}",
"prefersContrast": "{background.color.canvas}"
"prefersContrast": "{background.color.canvas}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.yellow.10}",
"dark": "{color.yellow.70}"
}
}
}
},
"overlay": {
@@ -1,35 +1,6 @@
{
"color": {
"@base": {
"value": {
"light": "{color.gray.30}",
"dark": "{color.gray.40}",
"forcedColors": "CanvasText"
}
},
"transparent": {
"value": {
"default": "transparent",
"forcedColors": "CanvasText"
}
},
"deemphasized": {
"@base": {
"value": {
"light": "{color.gray.20}",
"dark": "{color.gray.50}",
"forcedColors": "CanvasText"
}
}
},
"interactive": {
"@base": {
"value": {
"light": "{color.gray.35}",
"dark": "{color.gray.40}",
"forcedColors": "ButtonText"
}
},
"hover": {
"value": {
"light": "{color.gray.45}",
@@ -51,13 +22,6 @@
"forcedColors": "GrayText"
}
}
},
"error": {
"value": {
"light": "{color.red.50}",
"dark": "{color.red.20}",
"forcedColors": "{border.color.@base}"
}
}
},
"radius": {
@@ -9,10 +9,20 @@
"prefersContrast": "CanvasText",
"platform": {
"default": "color-mix(in srgb, currentColor 50%, transparent)"
},
"nova": {
"comment": "Maintain the brand/platform split and use prefersContrast over forcedColors",
"value": {
"brand": {
"light": "{color.gray.30}",
"dark": "{color.gray.40}"
}
}
}
}
},
"transparent": {
"ignoreFigma": "Use prefersContrast over forcedColors",
"value": {
"default": "transparent",
"prefersContrast": "CanvasText"
@@ -29,7 +39,17 @@
"default": "color-mix(in srgb, currentColor 24%, transparent)"
},
"prefersContrast": "currentColor",
"forcedColors": "ButtonText"
"forcedColors": "ButtonText",
"nova": {
"comment": "Maintain the brand/platform split",
"value": {
"brand": {
"light": "{color.gray.20}",
"dark": "{color.gray.50}"
},
"forcedColors": "CanvasText"
}
}
}
}
},
@@ -44,6 +64,15 @@
},
"platform": {
"default": "color-mix(in srgb, currentColor 15%, {color.gray.60})"
},
"nova": {
"comment": "Maintain the brand/platform split",
"value": {
"brand": {
"light": "{color.gray.35}",
"dark": "{color.gray.40}"
}
}
}
}
},
@@ -76,7 +105,14 @@
"value": {
"light": "{color.red.70}",
"dark": "{color.red.20}",
"prefersContrast": "{border.color.@base}"
"prefersContrast": "{border.color.@base}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.red.50}",
"dark": "{color.red.20}"
}
}
}
}
},
@@ -52,12 +52,6 @@
"default": "{button.background.color.@base}"
}
},
"disabled": {
"value": {
"default": "{button.background.color.ghost.@base}",
"forcedColors": "{button.background.color.disabled}"
}
},
"selected": {
"value": "{button.background.color.selected}"
}
@@ -115,12 +109,6 @@
},
"border": {
"color": {
"@base": {
"value": {
"default": "{color.accent.primary.@base}",
"forcedColors": "{border.color.interactive.@base}"
}
},
"destructive": {
"@base": {
"value": {
@@ -290,32 +278,6 @@
}
}
},
"ghost": {
"@base": {
"value": {
"default": "{button.text.color.@base}",
"forcedColors": "ButtonText"
}
},
"active": {
"value": {
"default": "{button.text.color.ghost.@base}",
"forcedColors": "{button.text.color.active}"
}
},
"disabled": {
"value": {
"default": "{button.text.color.ghost.@base}",
"forcedColors": "GrayText"
}
},
"hover": {
"value": {
"default": "{button.text.color.ghost.@base}",
"forcedColors": "{button.text.color.ghost.active}"
}
}
},
"muted": {
"@base": {
"value": {
@@ -145,6 +145,7 @@
"value": "{button.background.color.active}"
},
"disabled": {
"ignoreFigma": "Preserve token structure that can't be replicated in Figma",
"value": {
"default": "{button.background.color.ghost.@base}",
"brand": {
@@ -265,7 +266,13 @@
"value": {
"default": "transparent",
"prefersContrast": "{button.text.color.@base}",
"forcedColors": "{border.color.interactive.@base}"
"forcedColors": "{border.color.interactive.@base}",
"nova": {
"comment": "Preserve prefersContrast value",
"value": {
"default": "{color.accent.primary.@base}"
}
}
}
},
"active": {
@@ -614,6 +621,14 @@
"brand": {
"prefersContrast": "{button.text.color.@base}",
"forcedColors": "{button.text.color.@base}"
},
"nova": {
"comment": "Preserve token structure that can't be replicated in Figma",
"value": {
"brand": {
"forcedColors": "ButtonText"
}
}
}
}
},
@@ -621,7 +636,13 @@
"value": {
"default": "inherit",
"prefersContrast": "{button.text.color.active}",
"forcedColors": "{button.text.color.active}"
"forcedColors": "{button.text.color.active}",
"nova": {
"comment": "Preserve prefersContrast value",
"value": {
"default": "{button.text.color.ghost.@base}"
}
}
}
},
"disabled": {
@@ -630,6 +651,15 @@
"brand": {
"prefersContrast": "{button.text.color.disabled}",
"forcedColors": "{button.text.color.disabled}"
},
"nova": {
"comment": "Preserve token structure that can't be replicated in Figma",
"value": {
"brand": {
"default": "{button.text.color.ghost.@base}",
"forcedColors": "GrayText"
}
}
}
}
},
@@ -637,7 +667,14 @@
"value": {
"default": "inherit",
"prefersContrast": "{button.text.color.hover}",
"forcedColors": "{button.text.color.hover}"
"forcedColors": "{button.text.color.hover}",
"nova": {
"comment": "Preserve prefersContrast value",
"value": {
"default": "{button.text.color.ghost.@base}",
"forcedColors": "{button.text.color.ghost.active}"
}
}
}
},
"selected": {
@@ -1,13 +1,4 @@
{
"border": {
"color": {
"value": {
"light": "rgba(0, 0, 0, 0.06)",
"dark": "rgba(255, 255, 255, 0.04)",
"forcedColors": "CanvasText"
}
}
},
"gap": {
"@base": {
"value": "{space.medium}"
@@ -13,6 +13,7 @@
"value": "{border.width}"
},
"color": {
"ignoreFigma": "color-mix with currentColor cannot be expressed in Figma",
"value": {
"light": "color-mix(in srgb, currentColor 10%, transparent)",
"dark": "color-mix(in srgb, currentColor 6%, transparent)",
@@ -13,34 +13,6 @@
}
}
}
},
"information": {
"value": {
"light": "{color.violet.50}",
"dark": "{color.violet.20}",
"forcedColors": "{icon.color.@base}"
}
},
"success": {
"value": {
"light": "{color.green.50}",
"dark": "{color.green.20}",
"forcedColors": "{icon.color.@base}"
}
},
"warning": {
"value": {
"light": "{color.yellow.50}",
"dark": "{color.yellow.20}",
"forcedColors": "{icon.color.@base}"
}
},
"critical": {
"value": {
"light": "{color.red.50}",
"dark": "{color.red.20}",
"forcedColors": "{icon.color.@base}"
}
}
},
"size": {
@@ -19,28 +19,56 @@
"value": {
"light": "{color.blue.60}",
"dark": "{color.blue.20}",
"prefersContrast": "{icon.color.@base}"
"prefersContrast": "{icon.color.@base}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.violet.50}",
"dark": "{color.violet.20}"
}
}
}
},
"success": {
"value": {
"light": "{color.green.60}",
"dark": "{color.green.20}",
"prefersContrast": "{icon.color.@base}"
"prefersContrast": "{icon.color.@base}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.green.50}",
"dark": "{color.green.20}"
}
}
}
},
"warning": {
"value": {
"light": "{color.yellow.60}",
"dark": "{color.yellow.20}",
"prefersContrast": "{icon.color.@base}"
"prefersContrast": "{icon.color.@base}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.yellow.50}",
"dark": "{color.yellow.20}"
}
}
}
},
"critical": {
"value": {
"light": "{color.red.60}",
"dark": "{color.red.20}",
"prefersContrast": "{icon.color.@base}"
"prefersContrast": "{icon.color.@base}",
"nova": {
"comment": "Use prefersContrast over forcedColors",
"value": {
"light": "{color.red.50}",
"dark": "{color.red.20}"
}
}
}
}
},
@@ -1,19 +0,0 @@
{
"row": {
"background": {
"color": {
"@base": {
"value": "{background.color.canvas}"
},
"alternate": {
"comment": "TODO Bug 1821203 - Gray use needs to be consolidated",
"value": {
"light": "{color.gray.20}",
"dark": "{color.gray.65}",
"forcedColors": "{background.color.canvas}"
}
}
}
}
}
}
@@ -46,9 +46,7 @@
"background": {
"color": {
"@base": {
"value": {
"default": "{background.color.canvas}"
}
"value": "{background.color.canvas}"
},
"alternate": {
"comment": "TODO Bug 1821203 - Gray use needs to be consolidated",
@@ -61,6 +59,15 @@
"platform": {
"light": "rgba(0, 0, 0, 0.05)",
"dark": "rgba(255, 255, 255, 0.05)"
},
"nova": {
"comment": "Maintain the brand/platform split",
"value": {
"brand": {
"light": "{color.gray.20}",
"dark": "{color.gray.65}"
}
}
}
}
}
@@ -32,18 +32,6 @@
"forcedColors": "{button.border.color.@base}"
}
},
"hover": {
"value": {
"default": "transparent",
"forcedColors": "{button.border.color.hover}"
}
},
"active": {
"value": {
"default": "transparent",
"forcedColors": "{button.border.color.active}"
}
},
"selected": {
"value": "{toolbarbutton.outline.color.active}"
}
@@ -138,14 +138,26 @@
"value": {
"default": "transparent",
"prefersContrast": "currentColor",
"forcedColors": "SelectedItem"
"forcedColors": "SelectedItem",
"nova": {
"comment": "Preserve the base prefersContrast value",
"value": {
"forcedColors": "{button.border.color.hover}"
}
}
}
},
"active": {
"value": {
"default": "transparent",
"prefersContrast": "currentColor",
"forcedColors": "ButtonText"
"forcedColors": "ButtonText",
"nova": {
"comment": "Preserve the base prefersContrast value",
"value": {
"forcedColors": "{button.border.color.active}"
}
}
}
},
"selected": {