diff --git a/MIGRATION.md b/MIGRATION.md index e54b3ad1..3535977f 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -3,6 +3,7 @@ This guide provides detailed instructions for migrating your project from one version of the `@metamask/design-tokens` to another. - [From version 2.1.1 to 3.0.0](#from-version-211-to-300) +- [From version 3.0.0 to 4.0.0](#from-version-300-to-400) ## From version 2.1.1 to 3.0.0 @@ -29,3 +30,91 @@ import '../../node_modules/@metamask/design-tokens/dist/styles.css'; ``` This new path points to the `dist` directory, ensuring that you're importing the most optimized and production-ready version of the stylesheet. + +## From version 3.0.0 to 4.0.0 + +## Migration from Version 3.0.0 to 4.0.0 + +### Changes to Color Tokens (Breaking Changes) + +In this version, significant updates have been made to color tokens, including additions, modifications, and removals. To upgrade to version 4, ensure that the following tokens are not present in your codebase: + +### Removed + +#### CSS + +``` +--brand-colors-grey-grey030 +--brand-colors-grey-grey040 +--brand-colors-grey-grey750 +--brand-colors-blue-blue000 +--brand-colors-green-green000 +--brand-colors-red-red000 +--brand-colors-yellow-yellow000 +--brand-colors-orange-orange000 +--brand-colors-violet +--brand-colors-white-white010 +--color-overlay-inverse +--color-primary-shadow +--color-primary-disabled +--color-secondary +--color-error-shadow +--color-error-disabled +--color-warning-alternative +--color-warning-disabled +--color-success-alternative +--color-success-disabled +--color-info-alternative +--color-info-disabled +--color-network- +``` + +#### JS + +``` +brandColor.grey030 +brandColor.grey040 +brandColor.grey750 +brandColor.blue000 +brandColor.green000 +brandColor.red000 +brandColor.yellow000 +brandColor.orange000 +brandColor.violet +brandColor.white010 +``` + +### Changed + +#### CSS + +``` +--brand-colors-white-white000 to --brand-colors-white +--brand-colors-black-black000 to --brand-colors-black +``` + +#### JS + +``` +brandColor.white000` to `brandColor.white +brandColor.black000` to `brandColor.black +``` + +### Themed Colors + +- overlay-inverse removed +- primary-shadow removed +- primary-disabled removed +- secondary colors removed +- error-shadow removed +- error-disabled removed +- warning-alternative removed +- warning-disabled removed +- success-alternative removed +- success-disabled removed +- info-alternative removed +- info-disabled removed +- network colors removed +- shadow-primary added +- shadow-error added +- button colors removed diff --git a/automation-scripts/brandColor.js b/automation-scripts/brandColor.js new file mode 100644 index 00000000..c51c7833 --- /dev/null +++ b/automation-scripts/brandColor.js @@ -0,0 +1,67 @@ +// Script not used in build process, but can be run manually `node brandColor.js` to generate TypeScript types and JavaScript object mapping for brand colors based on a JSON file. +// Followed by manual steps to transpile the JSON to JS tokens +const fs = require('fs').promises; + +/** + * Generate TypeScript types and JavaScript object mapping for brand colors based on a JSON file. + * @param {string} inputFilePath - The path to the JSON file containing color definitions. + * @param {string} typesOutputFilePath - The path where the TypeScript types file should be written. + * @param {string} colorsOutputFilePath - The path where the JavaScript colors object file should be written. + */ +async function generateBrandColorFiles( + inputFilePath, + typesOutputFilePath, + colorsOutputFilePath, +) { + try { + const data = await fs.readFile(inputFilePath, 'utf8'); + const colorData = JSON.parse(data); + let tsOutput = 'export type BrandColor = {\n'; + let jsOutput = + "import type { BrandColor } from './brandColor.types';\n\nexport const brandColor: BrandColor = {\n"; + + Object.entries(colorData).forEach(([colorFamily, shades]) => { + Object.entries(shades).forEach(([shade, details]) => { + // Skip shades with a dash followed by numbers and a percent sign (e.g., "500-10%") + if (!/-\d+%/u.test(shade)) { + const comment = `/** ${colorFamily}/${colorFamily}${shade}: ${details.value} */`; + const tsLine = ` ${colorFamily}${shade}: string;`; + tsOutput += ` ${comment}\n ${tsLine}\n`; + + // Add color definition to jsOutput + const jsComment = ` // ${ + colorFamily.charAt(0).toUpperCase() + colorFamily.slice(1) + }\n`; + const jsLine = ` ${colorFamily}${shade}: '${details.value}',\n`; + jsOutput += jsComment + jsLine; + } + }); + }); + + tsOutput += '};\n'; + jsOutput += '};\n'; + + // Write the TypeScript types file + await fs.writeFile(typesOutputFilePath, tsOutput); + console.log( + `TypeScript types file has been created successfully at ${typesOutputFilePath}.`, + ); + + // Write the JavaScript colors file + await fs.writeFile(colorsOutputFilePath, jsOutput); + console.log( + `JavaScript colors file has been created successfully at ${colorsOutputFilePath}.`, + ); + } catch (error) { + console.error('Failed to read or write files:', error); + } +} + +const inputFilePath = '../src/figma/brandColors.json'; +const typesOutputFilePath = '../src/js/brandColor/brandColor.types.ts'; +const colorsOutputFilePath = '../src/js/brandColor/brandColor.ts'; +generateBrandColorFiles( + inputFilePath, + typesOutputFilePath, + colorsOutputFilePath, +); diff --git a/automation-scripts/themeColors.js b/automation-scripts/themeColors.js new file mode 100644 index 00000000..3c459025 --- /dev/null +++ b/automation-scripts/themeColors.js @@ -0,0 +1,73 @@ +// Script not used in build process, but can be run manually `node themeColors.js` to generate TypeScript types and JavaScript object mapping for brand colors based on a JSON file. +// Followed by manual steps to transpile the JSON to JS tokens +const fs = require('fs').promises; + +/** + * Generate JavaScript object mapping for light theme colors based on a JSON file. + * @param {string} inputFilePath - The path to the JSON file containing light theme color definitions. + * @param {string} colorsOutputFilePath - The path where the JavaScript colors object file should be written. + */ +async function generateThemeFiles(inputFilePath, colorsOutputFilePath) { + try { + const data = await fs.readFile(inputFilePath, 'utf8'); + const colorData = JSON.parse(data); + let jsOutput = "import { brandColor } from '../../brandColor';\n"; + jsOutput += "import type { ThemeColors } from '../types';\n\n"; + jsOutput += 'export const colors: ThemeColors = {\n'; + + Object.entries(colorData).forEach(([colorCategory, colorDetails]) => { + jsOutput += ` ${colorCategory}: {\n`; + + Object.entries(colorDetails).forEach(([shade, details]) => { + // Remove asterisks, convert kebab-case to camelCase, and simplify certain names + let cleanShade = shade + .replace(/\*/gu, '') + .replace(/-([a-z])/giu, (_, p1) => p1.toUpperCase()); + cleanShade = cleanShade.replace(/\s*\(strong\)\s*/giu, ''); + + let valueReference; + // Match patterns with and without percentage modifiers + if (details.value.match(/^\{.*?\..*?\}(-\d+%)?$/u)) { + valueReference = details.value.replace( + /\{(.*?)\.(.*?)(-\d+%)?\}/u, + (_, p1, p2, p3) => { + // Replace "-" with "_" and remove "%" for percentage-based modifiers + return `brandColor.${p1}${p2}${ + p3 ? p3.replace(/-/gu, '_').replace(/%/gu, '') : '' + }`; + }, + ); + } else if (details.value.match(/^#[0-9A-Fa-f]{6,8}$/u)) { + // If the value is a hex color, ensure it is in quotes + valueReference = `'${details.value}'`; + } else { + valueReference = details.value; + } + const jsLine = ` ${cleanShade}: ${valueReference}, // ${details.description}\n`; + jsOutput += jsLine; + }); + + jsOutput += ' },\n'; + }); + + jsOutput += '};\n'; + + // Write the JavaScript colors file + await fs.writeFile(colorsOutputFilePath, jsOutput); + console.log( + `JavaScript colors file has been created successfully at ${colorsOutputFilePath}. There are some manual steps to complete in the output files.`, + ); + } catch (error) { + console.error('Failed to read or write files:', error); + } +} + +// Light Theme +const inputFilePathLight = '../src/figma/lightTheme.json'; +const colorsOutputFilePathLight = '../src/js/themes/lightTheme/colors.ts'; +generateThemeFiles(inputFilePathLight, colorsOutputFilePathLight); + +// Dark Theme +const inputFilePathDark = '../src/figma/darkTheme.json'; +const colorsOutputFilePathDark = '../src/js/themes/darkTheme/colors.ts'; +generateThemeFiles(inputFilePathDark, colorsOutputFilePathDark); diff --git a/src/css/brand-colors.css b/src/css/brand-colors.css index 98f54cea..0884a581 100644 --- a/src/css/brand-colors.css +++ b/src/css/brand-colors.css @@ -6,11 +6,7 @@ * theme compatible styles */ :root { - --brand-colors-white-white000: #ffffff; - --brand-colors-white-white010: #fcfcfc; - --brand-colors-black-black000: #000000; - --brand-colors-grey-grey030: #fafbfc; - --brand-colors-grey-grey040: #f2f4f6; + /* Grey */ --brand-colors-grey-grey100: #d6d9dc; --brand-colors-grey-grey200: #bbc0c5; --brand-colors-grey-grey300: #9fa6ae; @@ -18,10 +14,13 @@ --brand-colors-grey-grey500: #6a737d; --brand-colors-grey-grey600: #535a61; --brand-colors-grey-grey700: #3b4046; - --brand-colors-grey-grey750: #2e3339; --brand-colors-grey-grey800: #24272a; --brand-colors-grey-grey900: #141618; - --brand-colors-blue-blue000: #eaf6ff; + --brand-colors-grey-grey1000: #000000; + --brand-colors-grey-grey050: #f2f4f6; + --brand-colors-grey-grey000: #ffffff; + --brand-colors-grey-grey025: #fafbfc; + /* Blue */ --brand-colors-blue-blue100: #a7d9fe; --brand-colors-blue-blue200: #75c4fd; --brand-colors-blue-blue300: #43aefc; @@ -31,43 +30,81 @@ --brand-colors-blue-blue700: #024272; --brand-colors-blue-blue800: #01253f; --brand-colors-blue-blue900: #00080d; - --brand-colors-orange-orange000: #fef5ef; - --brand-colors-orange-orange100: #fde2cf; - --brand-colors-orange-orange200: #fbc49d; - --brand-colors-orange-orange300: #faa66c; - --brand-colors-orange-orange400: #f8883b; - --brand-colors-orange-orange500: #f66a0a; - --brand-colors-orange-orange600: #bf5208; - --brand-colors-orange-orange700: #954005; - --brand-colors-orange-orange800: #632b04; - --brand-colors-orange-orange900: #321602; - --brand-colors-green-green000: #f3fcf5; - --brand-colors-green-green100: #d6ffdf; - --brand-colors-green-green200: #afecbd; - --brand-colors-green-green300: #86e29b; - --brand-colors-green-green400: #5dd879; - --brand-colors-green-green500: #28a745; - --brand-colors-green-green600: #1c8234; + --brand-colors-blue-blue050: #eaf6ff; + --brand-colors-blue-blue025: #eaf6ff; + /* Green */ + --brand-colors-green-green100: #afecbd; + --brand-colors-green-green200: #5dd879; + --brand-colors-green-green300: #28a745; + --brand-colors-green-green400: #28a745; + --brand-colors-green-green500: #1c8234; + --brand-colors-green-green600: #145523; --brand-colors-green-green700: #145523; --brand-colors-green-green800: #0a2c12; --brand-colors-green-green900: #041007; - --brand-colors-red-red000: #fcf2f3; + --brand-colors-green-green050: #d6ffdf; + --brand-colors-green-green025: #f3fcf5; + /* Red */ --brand-colors-red-red100: #f7d5d8; --brand-colors-red-red200: #f1b9be; --brand-colors-red-red300: #e88f97; --brand-colors-red-red400: #e06470; --brand-colors-red-red500: #d73847; - --brand-colors-red-red600: #b92534; - --brand-colors-red-red700: #8e1d28; - --brand-colors-red-red800: #64141c; + --brand-colors-red-red600: #8e1d28; + --brand-colors-red-red700: #64141c; + --brand-colors-red-red800: #3a0c10; --brand-colors-red-red900: #3a0c10; + --brand-colors-red-red050: #fcf2f3; + --brand-colors-red-red025: #fcf2f3; + /* Yellow */ + --brand-colors-yellow-yellow100: #ffdf70; + --brand-colors-yellow-yellow200: #ffc70a; + --brand-colors-yellow-yellow300: #f8883b; + --brand-colors-yellow-yellow400: #f66a0a; + --brand-colors-yellow-yellow500: #bf5208; + --brand-colors-yellow-yellow600: #954005; + --brand-colors-yellow-yellow700: #632b04; + --brand-colors-yellow-yellow800: #321602; + --brand-colors-yellow-yellow900: #321602; + --brand-colors-yellow-yellow050: #fff2c5; + --brand-colors-yellow-yellow025: #fefcde; + /* Orange */ + --brand-colors-orange-orange100: #fbc49d; + --brand-colors-orange-orange200: #faa66c; + --brand-colors-orange-orange300: #f8883b; + --brand-colors-orange-orange400: #f66a0a; + --brand-colors-orange-orange500: #bf5208; + --brand-colors-orange-orange600: #954005; + --brand-colors-orange-orange700: #632b04; + --brand-colors-orange-orange800: #321602; + --brand-colors-orange-orange900: #321602; + --brand-colors-orange-orange050: #fde2cf; + --brand-colors-orange-orange025: #fef5ef; + /* Purple */ + --brand-colors-purple-purple100: #efd2ff; + --brand-colors-purple-purple200: #cfb5f0; + --brand-colors-purple-purple300: #d27dff; + --brand-colors-purple-purple400: #b864f5; --brand-colors-purple-purple500: #8b45b6; - --brand-colors-violet-violet300: #cfb5f0; - --brand-colors-yellow-yellow000: #fffdf8; - --brand-colors-yellow-yellow100: #fefcde; - --brand-colors-yellow-yellow200: #fff2c5; - --brand-colors-yellow-yellow300: #ffeaa3; - --brand-colors-yellow-yellow400: #ffdf70; - --brand-colors-yellow-yellow500: #ffd33d; - --brand-colors-yellow-yellow600: #ffc70a; + --brand-colors-purple-purple600: #6c2ab2; + --brand-colors-purple-purple700: #4c1178; + --brand-colors-purple-purple800: #32054d; + --brand-colors-purple-purple900: #280a00; + --brand-colors-purple-purple050: #fbf2ff; + --brand-colors-purple-purple025: #fcf6ff; + /* Lime */ + --brand-colors-lime-lime100: #b8ef4a; + --brand-colors-lime-lime200: #95ca45; + --brand-colors-lime-lime300: #7ab040; + --brand-colors-lime-lime400: #64993d; + --brand-colors-lime-lime500: #457a39; + --brand-colors-lime-lime600: #275b35; + --brand-colors-lime-lime700: #093a31; + --brand-colors-lime-lime800: #022321; + --brand-colors-lime-lime900: #011515; + --brand-colors-lime-lime025: #effed9; + --brand-colors-lime-lime050: #e3febd; + /* White and Black */ + --brand-colors-white: #ffffff; + --brand-colors-black: #000000; } diff --git a/src/css/dark-theme-colors.css b/src/css/dark-theme-colors.css index f5e81cb2..40ab429f 100644 --- a/src/css/dark-theme-colors.css +++ b/src/css/dark-theme-colors.css @@ -2,64 +2,102 @@ * Dark Theme Colors */ [data-theme='dark'] { + /* For default neutral backgrounds */ --color-background-default: var(--brand-colors-grey-grey800); - --color-background-default-hover: #282b2e; - --color-background-default-pressed: #36383b; + /* For secondary neutral backgrounds. */ --color-background-alternative: var(--brand-colors-grey-grey900); - --color-background-alternative-hover: #191b1d; - --color-background-alternative-pressed: #27292a; - --color-background-hover: #ffffff05; + /* For "hover" states that use background-default. */ + --color-background-default-hover: #313235; + /* For "pressed" states that use background-alternative. */ + --color-background-default-pressed: #3f4145; + /* For "hover" states that use background-alternative. */ + --color-background-alternative-hover: #1f2123; + /* For "pressed" states that use background-alternative. */ + --color-background-alternative-pressed: #2e3033; + /* For "hover" state that use no background fill. */ + --color-background-hover: #ffffff0a; + /* For "pressed" state that use no background fill. */ --color-background-pressed: #ffffff14; - --color-text-default: var(--brand-colors-white-white000); - --color-text-alternative: var(--brand-colors-grey-grey100); + /* For default neutral text. */ + --color-text-default: var(--brand-colors-grey-grey000); + /* For softer contrast neutral text */ + --color-text-alternative: var(--brand-colors-grey-grey200); + /* For the softest contrast neutral text (not accessible) */ --color-text-muted: var(--brand-colors-grey-grey400); - --color-icon-default: var(--brand-colors-white-white000); + /* For default neutral icons */ + --color-icon-default: var(--brand-colors-grey-grey000); + /* For softer neutral icons */ --color-icon-alternative: var(--brand-colors-grey-grey200); + /* For the weakest contrast neutral icons (not accessible) */ --color-icon-muted: var(--brand-colors-grey-grey400); + /* For soft contrast neutral border */ --color-border-default: var(--brand-colors-grey-grey400); - --color-border-muted: var(--brand-colors-grey-grey700); + /* For the weakest contrast neutral border */ + --color-border-muted: #848c9629; + /* For the default shade of screen */ --color-overlay-default: #00000099; + /* For a stronger shade of screen */ --color-overlay-alternative: #000000cc; - --color-shadow-default: #00000080; - --color-overlay-inverse: var(--brand-colors-white-white010); - --color-primary-default: var(--brand-colors-blue-blue400); - --color-primary-default-hover: #0092fa; - --color-primary-default-pressed: #54b6fc; - --color-primary-alternative: var(--brand-colors-blue-blue300); - --color-primary-muted: #1098fc26; + /* For elements used on top of overlay/alternative. Used for text, icon or border */ + --color-overlay-inverse: var(--brand-colors-grey-grey000); + /* For interactive, active, and selected semantics. Used for text, background, icon or border */ + --color-primary-default: var(--brand-colors-blue-blue300); + /* For the stronger contrast primary semantic elements. */ + --color-primary-alternative: var(--brand-colors-blue-blue200); + /* For the weakest contrast primary semantic backgrounds. */ + --color-primary-muted: #43aefc26; + /* For elements used on top of primary/default. Used for text, icon or border */ --color-primary-inverse: var(--brand-colors-grey-grey900); - --color-primary-disabled: #1098fc80; - --color-primary-shadow: #0376c933; - --color-secondary-default: var(--brand-colors-orange-orange400); - --color-secondary-alternative: var(--brand-colors-orange-orange300); - --color-secondary-muted: #f8883b26; - --color-secondary-inverse: var(--brand-colors-grey-grey900); - --color-secondary-disabled: #f8883b80; - --color-error-default: #ff5263; - --color-error-default-hover: #ff4d58; - --color-error-default-pressed: #f9868e; - --color-error-alternative: var(--brand-colors-red-red300); - --color-error-muted: #ff526326; + /* For the "hover" state of primary-default elements */ + --color-primary-default-hover: #26a2fc; + /* For the "pressed" state of primary-default elements */ + --color-primary-default-pressed: #3baafd; + /* For the critical alert semantic elements. Used for text, background, icon or border */ + --color-error-default: var(--brand-colors-red-red300); + /* For the stronger contrast error semantic elements. */ + --color-error-alternative: var(--brand-colors-red-red200); + /* For the weakest contrast critical alert semantic backgrounds. */ + --color-error-muted: #e88f9726; + /* For elements used on top of error/default. Used for text, icon or border */ --color-error-inverse: var(--brand-colors-grey-grey900); - --color-error-disabled: #d7384780; - --color-error-shadow: #ff526366; - --color-warning-default: var(--brand-colors-yellow-yellow500); - --color-warning-default-hover: #ffc60a; - --color-warning-default-pressed: #ffeaa3d1; - --color-warning-alternative: var(--brand-colors-yellow-yellow400); - --color-warning-muted: #ffd33d26; + /* For the "hover" state of error-default elements. */ + --color-error-default-hover: #e47782; + /* For the "pressed" state of error-default elements. */ + --color-error-default-pressed: #e78891; + /* For the caution alert semantic elements. Used for text, background, icon or border */ + --color-warning-default: var(--brand-colors-yellow-yellow100); + /* For the weakest contrast caution alert semantic backgrounds. */ + --color-warning-muted: #ffdf7026; + /* For elements used on top of warning/default. Used for text, icon or border */ --color-warning-inverse: var(--brand-colors-grey-grey900); - --color-warning-disabled: #ffd33d80; - --color-success-default: var(--brand-colors-green-green500); - --color-success-default-hover: #05b82f; - --color-success-default-pressed: #6aec88; - --color-success-alternative: var(--brand-colors-green-green400); + /* For the "hover" state of warning-default elements */ + --color-warning-default-hover: #ffe485; + /* For the "pressed" state of warning-default elements */ + --color-warning-default-pressed: #ffe899; + /* For the positive semantic elements. Used for text, background, icon or border */ + --color-success-default: var(--brand-colors-green-green300); + /* For the weakest contrast positive semantic backgrounds. */ --color-success-muted: #28a74526; + /* For elements used on top of success/default. Used for text, icon or border */ --color-success-inverse: var(--brand-colors-grey-grey900); - --color-success-disabled: #28a74580; - --color-info-default: var(--brand-colors-blue-blue400); - --color-info-alternative: var(--brand-colors-blue-blue300); - --color-info-muted: #1098fc26; + /* For the "hover" state of success-default elements */ + --color-success-default-hover: #2cb94c; + /* For the "pressed" state of success-default elements */ + --color-success-default-pressed: #30ca53; + /* For informational read-only elements. Used for text, background, icon or border */ + --color-info-default: var(--brand-colors-blue-blue300); + /* For the weakest contrast informational semantic backgrounds. */ + --color-info-muted: #43aefc26; + /* For elements used on top of info/default. Used for text, icon or border */ --color-info-inverse: var(--brand-colors-grey-grey900); - --color-info-disabled: #0376c980; + /* For Flask primary accent color. */ + --color-flask-default: var(--brand-colors-purple-purple300); + /* For elements used on top of flask/default. Used for text, icon or border */ + --color-flask-inverse: var(--brand-colors-grey-grey900); + /* For neutral drop shadow color. */ + --color-shadow-default: #00000066; + /* For primary drop shadow color. */ + --color-shadow-primary: #43aefc33; + /* For critical/danger drop shadow color. */ + --color-shadow-error: #ff758466; } diff --git a/src/css/index.css b/src/css/index.css index a8613006..756b749d 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -1,5 +1,5 @@ @import './brand-colors.css'; -@import './light-theme-colors.css'; -@import './dark-theme-colors.css'; @import './typography.css'; @import './shadow.css'; +@import './light-theme-colors.css'; +@import './dark-theme-colors.css'; diff --git a/src/css/light-theme-colors.css b/src/css/light-theme-colors.css index c4ce7de1..8a831ca2 100644 --- a/src/css/light-theme-colors.css +++ b/src/css/light-theme-colors.css @@ -3,79 +3,102 @@ */ :root, [data-theme='light'] { - --color-background-default: var(--brand-colors-white-white000); - --color-background-default-hover: #fafafa; + /* For default neutral backgrounds */ + --color-background-default: var(--brand-colors-grey-grey000); + /* For secondary neutral backgrounds. */ + --color-background-alternative: var(--brand-colors-grey-grey050); + /* For "hover" states that use background-default. */ + --color-background-default-hover: #f5f5f5; + /* For "pressed" states that use background-alternative. */ --color-background-default-pressed: #ebebeb; - --color-background-alternative: var(--brand-colors-grey-grey040); - --color-background-alternative-hover: #edeff1; - --color-background-alternative-pressed: #dfe0e2; - --color-background-hover: #00000005; + /* For "hover" states that use background-alternative. */ + --color-background-alternative-hover: #e7ebee; + /* For "pressed" states that use background-alternative. */ + --color-background-alternative-pressed: #dbe0e6; + /* For "hover" state that use no background fill. */ + --color-background-hover: #0000000a; + /* For "pressed" state that use no background fill. */ --color-background-pressed: #00000014; - --color-text-default: var(--brand-colors-grey-grey800); - --color-text-alternative: var(--brand-colors-grey-grey600); - --color-text-muted: var(--brand-colors-grey-grey200); - --color-icon-default: var(--brand-colors-grey-grey800); + /* For default neutral text. */ + --color-text-default: var(--brand-colors-grey-grey900); + /* For softer contrast neutral text */ + --color-text-alternative: var(--brand-colors-grey-grey500); + /* For the softest contrast neutral text (not accessible) */ + --color-text-muted: var(--brand-colors-grey-grey300); + /* For default neutral icons */ + --color-icon-default: var(--brand-colors-grey-grey900); + /* For softer neutral icons */ --color-icon-alternative: var(--brand-colors-grey-grey500); - --color-icon-muted: var(--brand-colors-grey-grey200); + /* For the weakest contrast neutral icons (not accessible) */ + --color-icon-muted: var(--brand-colors-grey-grey300); + /* For soft contrast neutral border */ --color-border-default: var(--brand-colors-grey-grey200); - --color-border-muted: var(--brand-colors-grey-grey100); + /* For the weakest contrast neutral border */ + --color-border-muted: #bbc0c566; + /* For the default shade of screen */ --color-overlay-default: #00000099; + /* For a stronger shade of screen */ --color-overlay-alternative: #000000cc; - --color-overlay-inverse: var(--brand-colors-white-white010); - --color-shadow-default: #0000001a; + /* For elements used on top of overlay/alternative. Used for text, icon or border */ + --color-overlay-inverse: var(--brand-colors-grey-grey000); + /* For interactive, active, and selected semantics. Used for text, background, icon or border */ --color-primary-default: var(--brand-colors-blue-blue500); - --color-primary-default-hover: #0379ce; - --color-primary-default-pressed: #036db9; + /* For the stronger contrast primary semantic elements. */ --color-primary-alternative: var(--brand-colors-blue-blue600); - --color-primary-muted: #0376c919; - --color-primary-inverse: var(--brand-colors-white-white000); - --color-primary-disabled: #0376c980; - --color-primary-shadow: #0376c933; - --color-secondary-default: var(--brand-colors-orange-orange500); - --color-secondary-alternative: var(--brand-colors-orange-orange600); - --color-secondary-muted: #f66a0a19; - --color-secondary-inverse: var(--brand-colors-white-white000); - --color-secondary-disabled: #f66a0a80; + /* For the weakest contrast primary semantic backgrounds. */ + --color-primary-muted: #0376c91a; + /* For elements used on top of primary/default. Used for text, icon or border */ + --color-primary-inverse: var(--brand-colors-grey-grey000); + /* For the "hover" state of primary-default elements */ + --color-primary-default-hover: #036ab5; + /* For the "pressed" state of primary-default elements */ + --color-primary-default-pressed: #025ea1; + /* For the critical alert semantic elements. Used for text, background, icon or border */ --color-error-default: var(--brand-colors-red-red500); - --color-error-default-hover: #cd4250; - --color-error-default-pressed: #c63441; + /* For the stronger contrast error semantic elements. */ --color-error-alternative: var(--brand-colors-red-red600); - --color-error-muted: #d7384719; - --color-error-inverse: var(--brand-colors-white-white000); - --color-error-disabled: #d7384780; - --color-error-shadow: #d7384766; - --color-warning-default: var(--brand-colors-orange-orange600); - --color-warning-default-hover: #c2540a; - --color-warning-default-pressed: #a24507; - --color-warning-alternative: var(--brand-colors-yellow-yellow600); - --color-warning-muted: #bf520819; - --color-warning-inverse: var(--brand-colors-white-white000); - --color-warning-disabled: #ffd33d80; - --color-success-default: var(--brand-colors-green-green600); - --color-success-default-hover: #208838; - --color-success-default-pressed: #1b7431; - --color-success-alternative: var(--brand-colors-green-green500); - --color-success-muted: #1c823419; - --color-success-inverse: var(--brand-colors-white-white000); - --color-success-disabled: #28a74580; + /* For the weakest contrast critical alert semantic backgrounds. */ + --color-error-muted: #d738471a; + /* For elements used on top of error/default. Used for text, icon or border */ + --color-error-inverse: var(--brand-colors-grey-grey000); + /* For the "hover" state of error-default elements. */ + --color-error-default-hover: #d02a3a; + /* For the "pressed" state of error-default elements. */ + --color-error-default-pressed: #bf2635; + /* For the caution alert semantic elements. Used for text, background, icon or border */ + --color-warning-default: var(--brand-colors-yellow-yellow500); + /* For the weakest contrast caution alert semantic backgrounds. */ + --color-warning-muted: #bf52081a; + /* For elements used on top of warning/default. Used for text, icon or border */ + --color-warning-inverse: var(--brand-colors-grey-grey000); + /* For the "hover" state of warning-default elements */ + --color-warning-default-hover: #ac4a07; + /* For the "pressed" state of warning-default elements */ + --color-warning-default-pressed: #984106; + /* For the positive semantic elements. Used for text, background, icon or border */ + --color-success-default: var(--brand-colors-green-green500); + /* For the weakest contrast positive semantic backgrounds. */ + --color-success-muted: #1c82341a; + /* For elements used on top of success/default. Used for text, icon or border */ + --color-success-inverse: var(--brand-colors-grey-grey000); + /* For the "hover" state of success-default elements */ + --color-success-default-hover: #18712d; + /* For the "pressed" state of success-default elements */ + --color-success-default-pressed: #156127; + /* For informational read-only elements. Used for text, background, icon or border */ --color-info-default: var(--brand-colors-blue-blue500); - --color-info-alternative: var(--brand-colors-blue-blue600); - --color-info-muted: #0376c919; - --color-info-inverse: var(--brand-colors-white-white000); - --color-info-disabled: #0376c980; - --color-network-goerli-default: var(--brand-colors-blue-blue400); - --color-network-goerli-inverse: var(--brand-colors-white-white010); - --color-network-localhost-default: var(--brand-colors-grey-grey200); - --color-network-localhost-inverse: var(--brand-colors-white-white010); - --color-network-sepolia-default: var(--brand-colors-violet-violet300); - --color-network-sepolia-inverse: var(--brand-colors-white-white010); + /* For the weakest contrast informational semantic backgrounds. */ + --color-info-muted: #0376c91a; + /* For elements used on top of info/default. Used for text, icon or border */ + --color-info-inverse: var(--brand-colors-grey-grey000); + /* For Flask primary accent color. */ --color-flask-default: var(--brand-colors-purple-purple500); - --color-flask-inverse: var(--brand-colors-white-white010); - - /* Components */ - /* button */ - --component-button-primary-shadow: var(--shadow-size-sm) - var(--color-primary-shadow); - --component-button-danger-shadow: var(--shadow-size-sm) - var(--color-error-shadow); + /* For elements used on top of flask/default. Used for text, icon or border */ + --color-flask-inverse: var(--brand-colors-grey-grey000); + /* For neutral drop shadow color. */ + --color-shadow-default: #0000001a; + /* For primary drop shadow color. */ + --color-shadow-primary: #0376c933; + /* For critical/danger drop shadow color. */ + --color-shadow-error: #ca354266; } diff --git a/src/figma/darkTheme.json b/src/figma/darkTheme.json index 650ac30a..11f5df7b 100644 --- a/src/figma/darkTheme.json +++ b/src/figma/darkTheme.json @@ -115,6 +115,12 @@ "type": "color", "parent": "Theme Colors/Dark mode", "description": "For a stronger shade of screen" + }, + "inverse": { + "value": "{grey.000}", + "type": "color", + "parent": "Theme Colors/Dark mode", + "description": "For elements used on top of overlay/alternative. Used for text, icon or border" } }, "primary": { diff --git a/src/figma/lightTheme.json b/src/figma/lightTheme.json index 5868878d..8d098c39 100644 --- a/src/figma/lightTheme.json +++ b/src/figma/lightTheme.json @@ -115,6 +115,12 @@ "type": "color", "parent": "Theme Colors/Light mode", "description": "For a stronger shade of screen" + }, + "inverse": { + "value": "{grey.000}", + "type": "color", + "parent": "Theme Colors/Light mode", + "description": "For elements used on top of overlay/alternative. Used for text, icon or border" } }, "primary": { diff --git a/src/js/brandColor/brandColor.test.ts b/src/js/brandColor/brandColor.test.ts index 932e3c78..4be1c64e 100644 --- a/src/js/brandColor/brandColor.test.ts +++ b/src/js/brandColor/brandColor.test.ts @@ -1,410 +1,29 @@ /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ import { brandColor } from './brandColor'; -const designTokens = require('../../figma/tokens.json'); +const designTokens = require('../../figma/brandColors.json'); describe('Brand Color', () => { - describe('White', () => { - it('js tokens for white000 matches figma tokens white000', () => { - expect(brandColor.white000).toStrictEqual( - designTokens.global.brandColors.white.white000.value.toLowerCase(), - ); - }); - - it('js tokens for white010 matches figma tokens white010', () => { - expect(brandColor.white010).toStrictEqual( - designTokens.global.brandColors.white.white010.value.toLowerCase(), - ); - }); - }); - - describe('Black', () => { - it('js tokens for black000 matches figma tokens black000', () => { - expect(brandColor.black000).toStrictEqual( - designTokens.global.brandColors.black.black000.value.toLowerCase(), - ); - }); - }); - - describe('Grey', () => { - it('js tokens for grey030 matches figma tokens grey030', () => { - expect(brandColor.grey030).toStrictEqual( - designTokens.global.brandColors.grey.grey030.value.toLowerCase(), - ); - }); - - it('js tokens for grey040 matches figma tokens grey040', () => { - expect(brandColor.grey040).toStrictEqual( - designTokens.global.brandColors.grey.grey040.value.toLowerCase(), - ); - }); - - it('js tokens for grey100 matches figma tokens grey100', () => { - expect(brandColor.grey100).toStrictEqual( - designTokens.global.brandColors.grey.grey100.value.toLowerCase(), - ); - }); - - it('js tokens for grey200 matches figma tokens grey200', () => { - expect(brandColor.grey200).toStrictEqual( - designTokens.global.brandColors.grey.grey200.value.toLowerCase(), - ); - }); - - it('js tokens for grey300 matches figma tokens grey300', () => { - expect(brandColor.grey300).toStrictEqual( - designTokens.global.brandColors.grey.grey300.value.toLowerCase(), - ); - }); - - it('js tokens for grey400 matches figma tokens grey400', () => { - expect(brandColor.grey400).toStrictEqual( - designTokens.global.brandColors.grey.grey400.value.toLowerCase(), - ); - }); - - it('js tokens for grey500 matches figma tokens grey500', () => { - expect(brandColor.grey500).toStrictEqual( - designTokens.global.brandColors.grey.grey500.value.toLowerCase(), - ); - }); - - it('js tokens for grey600 matches figma tokens grey600', () => { - expect(brandColor.grey600).toStrictEqual( - designTokens.global.brandColors.grey.grey600.value.toLowerCase(), - ); - }); - - it('js tokens for grey700 matches figma tokens grey700', () => { - expect(brandColor.grey700).toStrictEqual( - designTokens.global.brandColors.grey.grey700.value.toLowerCase(), - ); - }); - - it('js tokens for grey750 matches figma tokens grey750', () => { - expect(brandColor.grey750).toStrictEqual( - designTokens.global.brandColors.grey.grey750.value.toLowerCase(), - ); - }); - - it('js tokens for grey800 matches figma tokens grey800', () => { - expect(brandColor.grey800).toStrictEqual( - designTokens.global.brandColors.grey.grey800.value.toLowerCase(), - ); - }); - - it('js tokens for grey900 matches figma tokens grey900', () => { - expect(brandColor.grey900).toStrictEqual( - designTokens.global.brandColors.grey.grey900.value.toLowerCase(), - ); - }); - }); - - describe('Blue', () => { - it('js tokens for blue000 matches figma tokens blue000', () => { - expect(brandColor.blue000).toStrictEqual( - designTokens.global.brandColors.blue.blue000.value.toLowerCase(), - ); - }); - - it('js tokens for blue100 matches figma tokens blue100', () => { - expect(brandColor.blue100).toStrictEqual( - designTokens.global.brandColors.blue.blue100.value.toLowerCase(), - ); - }); - - it('js tokens for blue200 matches figma tokens blue200', () => { - expect(brandColor.blue200).toStrictEqual( - designTokens.global.brandColors.blue.blue200.value.toLowerCase(), - ); - }); - - it('js tokens for blue300 matches figma tokens blue300', () => { - expect(brandColor.blue300).toStrictEqual( - designTokens.global.brandColors.blue.blue300.value.toLowerCase(), - ); - }); - - it('js tokens for blue400 matches figma tokens blue400', () => { - expect(brandColor.blue400).toStrictEqual( - designTokens.global.brandColors.blue.blue400.value.toLowerCase(), - ); - }); - - it('js tokens for blue500 matches figma tokens blue500', () => { - expect(brandColor.blue500).toStrictEqual( - designTokens.global.brandColors.blue.blue500.value.toLowerCase(), - ); - }); - - it('js tokens for blue600 matches figma tokens blue600', () => { - expect(brandColor.blue600).toStrictEqual( - designTokens.global.brandColors.blue.blue600.value.toLowerCase(), - ); - }); - - it('js tokens for blue700 matches figma tokens blue700', () => { - expect(brandColor.blue700).toStrictEqual( - designTokens.global.brandColors.blue.blue700.value.toLowerCase(), - ); - }); - - it('js tokens for blue800 matches figma tokens blue800', () => { - expect(brandColor.blue800).toStrictEqual( - designTokens.global.brandColors.blue.blue800.value.toLowerCase(), - ); - }); - - it('js tokens for blue900 matches figma tokens blue900', () => { - expect(brandColor.blue900).toStrictEqual( - designTokens.global.brandColors.blue.blue900.value.toLowerCase(), - ); - }); - }); - - describe('Orange', () => { - it('js tokens for orange000 matches figma tokens orange000', () => { - expect(brandColor.orange000).toStrictEqual( - designTokens.global.brandColors.orange.orange000.value.toLowerCase(), - ); - }); - - it('js tokens for orange100 matches figma tokens orange100', () => { - expect(brandColor.orange100).toStrictEqual( - designTokens.global.brandColors.orange.orange100.value.toLowerCase(), - ); - }); - - it('js tokens for orange200 matches figma tokens orange200', () => { - expect(brandColor.orange200).toStrictEqual( - designTokens.global.brandColors.orange.orange200.value.toLowerCase(), - ); - }); - - it('js tokens for orange300 matches figma tokens orange300', () => { - expect(brandColor.orange300).toStrictEqual( - designTokens.global.brandColors.orange.orange300.value.toLowerCase(), - ); - }); - - it('js tokens for orange400 matches figma tokens orange400', () => { - expect(brandColor.orange400).toStrictEqual( - designTokens.global.brandColors.orange.orange400.value.toLowerCase(), - ); - }); - - it('js tokens for orange500 matches figma tokens orange500', () => { - expect(brandColor.orange500).toStrictEqual( - designTokens.global.brandColors.orange.orange500.value.toLowerCase(), - ); - }); - - it('js tokens for orange600 matches figma tokens orange600', () => { - expect(brandColor.orange600).toStrictEqual( - designTokens.global.brandColors.orange.orange600.value.toLowerCase(), - ); - }); - - it('js tokens for orange700 matches figma tokens orange700', () => { - expect(brandColor.orange700).toStrictEqual( - designTokens.global.brandColors.orange.orange700.value.toLowerCase(), - ); - }); - - it('js tokens for orange800 matches figma tokens orange800', () => { - expect(brandColor.orange800).toStrictEqual( - designTokens.global.brandColors.orange.orange800.value.toLowerCase(), - ); - }); - - it('js tokens for orange900 matches figma tokens orange900', () => { - expect(brandColor.orange900).toStrictEqual( - designTokens.global.brandColors.orange.orange900.value.toLowerCase(), - ); - }); - }); - - describe('Green', () => { - it('js tokens for green000 matches figma tokens green000', () => { - expect(brandColor.green000).toStrictEqual( - designTokens.global.brandColors.green.green000.value.toLowerCase(), - ); - }); - - it('js tokens for green100 matches figma tokens green100', () => { - expect(brandColor.green100).toStrictEqual( - designTokens.global.brandColors.green.green100.value.toLowerCase(), - ); - }); - - it('js tokens for green200 matches figma tokens green200', () => { - expect(brandColor.green200).toStrictEqual( - designTokens.global.brandColors.green.green200.value.toLowerCase(), - ); - }); - - it('js tokens for green300 matches figma tokens green300', () => { - expect(brandColor.green300).toStrictEqual( - designTokens.global.brandColors.green.green300.value.toLowerCase(), - ); - }); - - it('js tokens for green400 matches figma tokens green400', () => { - expect(brandColor.green400).toStrictEqual( - designTokens.global.brandColors.green.green400.value.toLowerCase(), - ); - }); - - it('js tokens for green500 matches figma tokens green500', () => { - expect(brandColor.green500).toStrictEqual( - designTokens.global.brandColors.green.green500.value.toLowerCase(), - ); - }); - - it('js tokens for green600 matches figma tokens green600', () => { - expect(brandColor.green600).toStrictEqual( - designTokens.global.brandColors.green.green600.value.toLowerCase(), - ); - }); - - it('js tokens for green700 matches figma tokens green700', () => { - expect(brandColor.green700).toStrictEqual( - designTokens.global.brandColors.green.green700.value.toLowerCase(), - ); - }); - - it('js tokens for green800 matches figma tokens green800', () => { - expect(brandColor.green800).toStrictEqual( - designTokens.global.brandColors.green.green800.value.toLowerCase(), - ); - }); - - it('js tokens for green900 matches figma tokens green900', () => { - expect(brandColor.green900).toStrictEqual( - designTokens.global.brandColors.green.green900.value.toLowerCase(), - ); - }); - }); - - describe('Red', () => { - it('js tokens for red000 matches figma tokens red000', () => { - expect(brandColor.red000).toStrictEqual( - designTokens.global.brandColors.red.red000.value.toLowerCase(), - ); - }); - - it('js tokens for red100 matches figma tokens red100', () => { - expect(brandColor.red100).toStrictEqual( - designTokens.global.brandColors.red.red100.value.toLowerCase(), - ); - }); - - it('js tokens for red200 matches figma tokens red200', () => { - expect(brandColor.red200).toStrictEqual( - designTokens.global.brandColors.red.red200.value.toLowerCase(), - ); - }); - - it('js tokens for red300 matches figma tokens red300', () => { - expect(brandColor.red300).toStrictEqual( - designTokens.global.brandColors.red.red300.value.toLowerCase(), - ); - }); - - it('js tokens for red400 matches figma tokens red400', () => { - expect(brandColor.red400).toStrictEqual( - designTokens.global.brandColors.red.red400.value.toLowerCase(), - ); - }); - - it('js tokens for red500 matches figma tokens red500', () => { - expect(brandColor.red500).toStrictEqual( - designTokens.global.brandColors.red.red500.value.toLowerCase(), - ); - }); - - it('js tokens for red600 matches figma tokens red600', () => { - expect(brandColor.red600).toStrictEqual( - designTokens.global.brandColors.red.red600.value.toLowerCase(), - ); - }); - - it('js tokens for red700 matches figma tokens red700', () => { - expect(brandColor.red700).toStrictEqual( - designTokens.global.brandColors.red.red700.value.toLowerCase(), - ); - }); - - it('js tokens for red800 matches figma tokens red800', () => { - expect(brandColor.red800).toStrictEqual( - designTokens.global.brandColors.red.red800.value.toLowerCase(), - ); - }); - - it('js tokens for red900 matches figma tokens red900', () => { - expect(brandColor.red900).toStrictEqual( - designTokens.global.brandColors.red.red900.value.toLowerCase(), - ); - }); - }); - - describe('Purple', () => { - it('js tokens for purple500 matches figma tokens purple500', () => { - expect(brandColor.purple500).toStrictEqual( - designTokens.global.brandColors.purple.purple500.value.toLowerCase(), - ); - }); - }); - - describe('Violet', () => { - it('js tokens for violet300 matches figma tokens violet300', () => { - expect(brandColor.violet300).toStrictEqual( - designTokens.global.brandColors.violet.violet300.value.toLowerCase(), - ); - }); - }); - - describe('Yellow', () => { - it('js tokens for yellow000 matches figma tokens yellow000', () => { - expect(brandColor.yellow000).toStrictEqual( - designTokens.global.brandColors.yellow.yellow000.value.toLowerCase(), - ); - }); - - it('js tokens for yellow100 matches figma tokens yellow100', () => { - expect(brandColor.yellow100).toStrictEqual( - designTokens.global.brandColors.yellow.yellow100.value.toLowerCase(), - ); - }); - - it('js tokens for yellow200 matches figma tokens yellow200', () => { - expect(brandColor.yellow200).toStrictEqual( - designTokens.global.brandColors.yellow.yellow200.value.toLowerCase(), - ); - }); - - it('js tokens for yellow300 matches figma tokens yellow300', () => { - expect(brandColor.yellow300).toStrictEqual( - designTokens.global.brandColors.yellow.yellow300.value.toLowerCase(), - ); - }); - - it('js tokens for yellow400 matches figma tokens yellow400', () => { - expect(brandColor.yellow400).toStrictEqual( - designTokens.global.brandColors.yellow.yellow400.value.toLowerCase(), - ); - }); - - it('js tokens for yellow500 matches figma tokens yellow500', () => { - expect(brandColor.yellow500).toStrictEqual( - designTokens.global.brandColors.yellow.yellow500.value.toLowerCase(), - ); - }); - - it('js tokens for yellow600 matches figma tokens yellow600', () => { - expect(brandColor.yellow600).toStrictEqual( - designTokens.global.brandColors.yellow.yellow600.value.toLowerCase(), - ); + Object.entries(brandColor).forEach(([key, value]) => { + const colorFamily = key.replace(/\d+.*$/u, ''); // Extracts 'grey' from 'grey000' + const shadeMatch = key.match(/\d+/gu); // Extracts ['000'] from 'grey000' + // if no numeric key is found, skip the test + if (!shadeMatch?.[0]) { + describe(`${colorFamily.toUpperCase()} `, () => { + it(`js tokens for ${key} matches figma brandColor ${colorFamily}`, () => { + const tokenValue = designTokens[colorFamily]?.value ?? ''; + expect(value.toLowerCase()).toStrictEqual(tokenValue.toLowerCase()); + }); + }); + return; + } + const shadeKey = shadeMatch[0]; // Ensures there's a valid shade key + + describe(`${colorFamily.toUpperCase()} ${shadeKey}`, () => { + it(`js tokens for ${key} matches figma brandColor ${colorFamily}${shadeKey}`, () => { + const tokenValue = designTokens[colorFamily][shadeKey]?.value ?? ''; + expect(value.toLowerCase()).toStrictEqual(tokenValue.toLowerCase()); + }); }); }); }); diff --git a/src/js/brandColor/brandColor.ts b/src/js/brandColor/brandColor.ts index 5761b3ec..e127111c 100644 --- a/src/js/brandColor/brandColor.ts +++ b/src/js/brandColor/brandColor.ts @@ -1,78 +1,188 @@ import type { BrandColor } from './brandColor.types'; export const brandColor: BrandColor = { - // White - white000: '#ffffff', - white010: '#fcfcfc', - // Black - black000: '#000000', // Grey - grey030: '#fafbfc', - grey040: '#f2f4f6', grey100: '#d6d9dc', + // Grey grey200: '#bbc0c5', + // Grey grey300: '#9fa6ae', + // Grey grey400: '#848c96', + // Grey grey500: '#6a737d', + // Grey grey600: '#535a61', + // Grey grey700: '#3b4046', - grey750: '#2e3339', + // Grey grey800: '#24272a', + // Grey grey900: '#141618', + // Grey + grey1000: '#000000', + // Grey + grey050: '#f2f4f6', + // Grey + grey000: '#ffffff', + // Grey + grey025: '#fafbfc', // Blue - blue000: '#eaf6ff', blue100: '#a7d9fe', + // Blue blue200: '#75c4fd', + // Blue blue300: '#43aefc', + // Blue blue400: '#1098fc', + // Blue blue500: '#0376c9', + // Blue blue600: '#0260a4', + // Blue blue700: '#024272', + // Blue blue800: '#01253f', + // Blue blue900: '#00080d', - // Orange - orange000: '#fef5ef', - orange100: '#fde2cf', - orange200: '#fbc49d', - orange300: '#faa66c', - orange400: '#f8883b', - orange500: '#f66a0a', - orange600: '#bf5208', - orange700: '#954005', - orange800: '#632b04', - orange900: '#321602', + // Blue + blue050: '#eaf6ff', + // Blue + blue025: '#eaf6ff', + // Green + green100: '#afecbd', + // Green + green200: '#5dd879', + // Green + green300: '#28a745', + // Green + green400: '#28a745', + // Green + green500: '#1c8234', + // Green + green600: '#145523', // Green - green000: '#f3fcf5', - green100: '#d6ffdf', - green200: '#afecbd', - green300: '#86e29b', - green400: '#5dd879', - green500: '#28a745', - green600: '#1c8234', green700: '#145523', + // Green green800: '#0a2c12', + // Green green900: '#041007', + // Green + green050: '#d6ffdf', + // Green + green025: '#f3fcf5', // Red - red000: '#fcf2f3', red100: '#f7d5d8', + // Red red200: '#f1b9be', + // Red red300: '#e88f97', + // Red red400: '#e06470', + // Red red500: '#d73847', - red600: '#b92534', - red700: '#8e1d28', - red800: '#64141c', + // Red + red600: '#8e1d28', + // Red + red700: '#64141c', + // Red + red800: '#3a0c10', + // Red red900: '#3a0c10', + // Red + red050: '#fcf2f3', + // Red + red025: '#fcf2f3', + // Yellow + yellow100: '#ffdf70', + // Yellow + yellow200: '#ffc70a', + // Yellow + yellow300: '#f8883b', + // Yellow + yellow400: '#f66a0a', + // Yellow + yellow500: '#bf5208', + // Yellow + yellow600: '#954005', + // Yellow + yellow700: '#632b04', + // Yellow + yellow800: '#321602', + // Yellow + yellow900: '#321602', + // Yellow + yellow050: '#fff2c5', + // Yellow + yellow025: '#fefcde', + // Orange + orange100: '#fbc49d', + // Orange + orange200: '#faa66c', + // Orange + orange300: '#f8883b', + // Orange + orange400: '#f66a0a', + // Orange + orange500: '#bf5208', + // Orange + orange600: '#954005', + // Orange + orange700: '#632b04', + // Orange + orange800: '#321602', + // Orange + orange900: '#321602', + // Orange + orange050: '#fde2cf', + // Orange + orange025: '#fef5ef', + // Purple + purple100: '#efd2ff', + // Purple + purple200: '#cfb5f0', + // Purple + purple300: '#d27dff', + // Purple + purple400: '#b864f5', // Purple purple500: '#8b45b6', - // Violet - violet300: '#cfb5f0', - // Yellow - yellow000: '#fffdf8', - yellow100: '#fefcde', - yellow200: '#fff2c5', - yellow300: '#ffeaa3', - yellow400: '#ffdf70', - yellow500: '#ffd33d', - yellow600: '#ffc70a', + // Purple + purple600: '#6c2ab2', + // Purple + purple700: '#4c1178', + // Purple + purple800: '#32054d', + // Purple + purple900: '#280a00', + // Purple + purple050: '#fbf2ff', + // Purple + purple025: '#fcf6ff', + // Lime + lime100: '#b8ef4a', + // Lime + lime200: '#95ca45', + // Lime + lime300: '#7ab040', + // Lime + lime400: '#64993d', + // Lime + lime500: '#457a39', + // Lime + lime600: '#275b35', + // Lime + lime700: '#093a31', + // Lime + lime800: '#022321', + // Lime + lime900: '#011515', + // Lime + lime025: '#effed9', + // Lime + lime050: '#e3febd', + // White + white: '#ffffff', + // Black + black: '#000000', }; diff --git a/src/js/brandColor/brandColor.types.ts b/src/js/brandColor/brandColor.types.ts index 1f323420..bc89df05 100644 --- a/src/js/brandColor/brandColor.types.ts +++ b/src/js/brandColor/brandColor.types.ts @@ -1,14 +1,4 @@ export type BrandColor = { - /** white/white000: #ffffff */ - white000: string; - /** white/white010: #fcfcfc */ - white010: string; - /** black/black000: #000000 */ - black000: string; - /** grey/grey030: #fafbfc */ - grey030: string; - /** grey/grey040: #f2f4f6 */ - grey040: string; /** grey/grey100: #d6d9dc */ grey100: string; /** grey/grey200: #bbc0c5 */ @@ -23,14 +13,18 @@ export type BrandColor = { grey600: string; /** grey/grey700: #3b4046 */ grey700: string; - /** grey/grey750: #2e3339 */ - grey750: string; /** grey/grey800: #24272a */ grey800: string; /** grey/grey900: #141618 */ grey900: string; - /** blue/blue000: #eaf6ff */ - blue000: string; + /** grey/grey1000: #000000 */ + grey1000: string; + /** grey/grey050: #f2f4f6 */ + grey050: string; + /** grey/grey000: #ffffff */ + grey000: string; + /** grey/grey025: #fafbfc */ + grey025: string; /** blue/blue100: #a7d9fe */ blue100: string; /** blue/blue200: #75c4fd */ @@ -49,39 +43,21 @@ export type BrandColor = { blue800: string; /** blue/blue900: #00080d */ blue900: string; - /** orange/orange000: #fef5ef */ - orange000: string; - /** orange/orange100: #fde2cf */ - orange100: string; - /** orange/orange200: #fbc49d */ - orange200: string; - /** orange/orange300: #faa66c */ - orange300: string; - /** orange/orange400: #f8883b */ - orange400: string; - /** orange/orange500: #f66a0a */ - orange500: string; - /** orange/orange600: #c65507 */ - orange600: string; - /** orange/orange700: #954005 */ - orange700: string; - /** orange/orange800: #632b04 */ - orange800: string; - /** orange/orange900: #321602 */ - orange900: string; - /** green/green000: #f3fcf5 */ - green000: string; - /** green/green100: #d6ffdf */ + /** blue/blue050: #eaf6ff */ + blue050: string; + /** blue/blue025: #eaf6ff */ + blue025: string; + /** green/green100: #afecbd */ green100: string; - /** green/green200: #afecbd */ + /** green/green200: #5dd879 */ green200: string; - /** green/green300: #86e29b */ + /** green/green300: #28a745 */ green300: string; - /** green/green400: #5dd879 */ + /** green/green400: #28a745 */ green400: string; - /** green/green500: #28a745 */ + /** green/green500: #1c8234 */ green500: string; - /** green/green600: #1e7e34 */ + /** green/green600: #145523 */ green600: string; /** green/green700: #145523 */ green700: string; @@ -89,8 +65,10 @@ export type BrandColor = { green800: string; /** green/green900: #041007 */ green900: string; - /** red/red000: #fcf2f3 */ - red000: string; + /** green/green050: #d6ffdf */ + green050: string; + /** green/green025: #f3fcf5 */ + green025: string; /** red/red100: #f7d5d8 */ red100: string; /** red/red200: #f1b9be */ @@ -101,30 +79,108 @@ export type BrandColor = { red400: string; /** red/red500: #d73847 */ red500: string; - /** red/red600: #b92534 */ + /** red/red600: #8e1d28 */ red600: string; - /** red/red700: #8e1d28 */ + /** red/red700: #64141c */ red700: string; - /** red/red800: #64141c */ + /** red/red800: #3a0c10 */ red800: string; /** red/red900: #3a0c10 */ red900: string; - /** purple/purple500: #8b45b6 */ - purple500: string; - /** violet/violet300: #cfb5f0 */ - violet300: string; - /** yellow/yellow000: #fffdf8 */ - yellow000: string; - /** yellow/yellow100: #fefcde */ + /** red/red050: #fcf2f3 */ + red050: string; + /** red/red025: #fcf2f3 */ + red025: string; + /** yellow/yellow100: #ffdf70 */ yellow100: string; - /** yellow/yellow200: #fff2c5 */ + /** yellow/yellow200: #ffc70a */ yellow200: string; - /** yellow/yellow300: #ffeaa3 */ + /** yellow/yellow300: #f8883b */ yellow300: string; - /** yellow/yellow400: #ffdf70 */ + /** yellow/yellow400: #f66a0a */ yellow400: string; - /** yellow/yellow500: #ffd33d */ + /** yellow/yellow500: #bf5208 */ yellow500: string; - /** yellow/yellow600: #ffc70a */ + /** yellow/yellow600: #954005 */ yellow600: string; + /** yellow/yellow700: #632b04 */ + yellow700: string; + /** yellow/yellow800: #321602 */ + yellow800: string; + /** yellow/yellow900: #321602 */ + yellow900: string; + /** yellow/yellow050: #fff2c5 */ + yellow050: string; + /** yellow/yellow025: #fefcde */ + yellow025: string; + /** orange/orange100: #fbc49d */ + orange100: string; + /** orange/orange200: #faa66c */ + orange200: string; + /** orange/orange300: #f8883b */ + orange300: string; + /** orange/orange400: #f66a0a */ + orange400: string; + /** orange/orange500: #bf5208 */ + orange500: string; + /** orange/orange600: #954005 */ + orange600: string; + /** orange/orange700: #632b04 */ + orange700: string; + /** orange/orange800: #321602 */ + orange800: string; + /** orange/orange900: #321602 */ + orange900: string; + /** orange/orange050: #fde2cf */ + orange050: string; + /** orange/orange025: #fef5ef */ + orange025: string; + /** purple/purple100: #efd2ff */ + purple100: string; + /** purple/purple200: #cfb5f0 */ + purple200: string; + /** purple/purple300: #d27dff */ + purple300: string; + /** purple/purple400: #b864f5 */ + purple400: string; + /** purple/purple500: #8b45b6 */ + purple500: string; + /** purple/purple600: #6c2ab2 */ + purple600: string; + /** purple/purple700: #4c1178 */ + purple700: string; + /** purple/purple800: #32054d */ + purple800: string; + /** purple/purple900: #280a00 */ + purple900: string; + /** purple/purple050: #fbf2ff */ + purple050: string; + /** purple/purple025: #fcf6ff */ + purple025: string; + /** lime/lime100: #b8ef4a */ + lime100: string; + /** lime/lime200: #95ca45 */ + lime200: string; + /** lime/lime300: #7ab040 */ + lime300: string; + /** lime/lime400: #64993d */ + lime400: string; + /** lime/lime500: #457a39 */ + lime500: string; + /** lime/lime600: #275b35 */ + lime600: string; + /** lime/lime700: #093a31 */ + lime700: string; + /** lime/lime800: #022321 */ + lime800: string; + /** lime/lime900: #011515 */ + lime900: string; + /** lime/lime025: #effed9 */ + lime025: string; + /** lime/lime050: #e3febd */ + lime050: string; + /** white: #ffffff */ + white: string; + /** black: #000000 */ + black: string; }; diff --git a/src/js/brandColor/index.ts b/src/js/brandColor/index.ts index 56ff4c6c..e4230eb8 100644 --- a/src/js/brandColor/index.ts +++ b/src/js/brandColor/index.ts @@ -1 +1,2 @@ export { brandColor } from './brandColor'; +export type { BrandColor } from './brandColor.types'; diff --git a/src/js/index.ts b/src/js/index.ts index 6ee62b4a..1cd35654 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -1,7 +1,6 @@ export type { Theme } from './themes'; -export { lightTheme } from './themes'; -export { darkTheme } from './themes'; export { brandColor } from './brandColor'; +export { lightTheme, darkTheme } from './themes'; // DEPRECATED in favor of importing theme objects above export { colors } from './colors'; diff --git a/src/js/themes/darkTheme/colors.test.ts b/src/js/themes/darkTheme/colors.test.ts index ffb1724c..0b590e9f 100644 --- a/src/js/themes/darkTheme/colors.test.ts +++ b/src/js/themes/darkTheme/colors.test.ts @@ -1,390 +1,62 @@ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ -import { colors as importableColors } from './colors'; - -const designTokens = require('../../../figma/tokens.json'); - -describe('Dark Theme Colors', () => { - it('js tokens for background.default matches figma tokens background.default', () => { - expect(importableColors.background.default).toStrictEqual( - designTokens.dark.colors.background.default.value, - ); - }); - - it('js tokens for background.defaultHover matches figma tokens background.defaultHover', () => { - expect(importableColors.background.defaultHover).toStrictEqual( - designTokens.dark.colors.background['default-hover'].value, - ); - }); - - it('js tokens for background.defaultPressed matches figma tokens background.defaultPressed', () => { - expect(importableColors.background.defaultPressed).toStrictEqual( - designTokens.dark.colors.background['default-pressed'].value, - ); - }); - - it('js tokens for background.alternative matches figma tokens background.alternative', () => { - expect(importableColors.background.alternative).toStrictEqual( - designTokens.dark.colors.background.alternative.value, - ); - }); - - it('js tokens for background.alternativeHover matches figma tokens background.alternativeHover', () => { - expect(importableColors.background.alternativeHover).toStrictEqual( - designTokens.dark.colors.background['alternative-hover'].value, - ); - }); - - it('js tokens for background.alternativePressed matches figma tokens background.alternativePressed', () => { - expect(importableColors.background.alternativePressed).toStrictEqual( - designTokens.dark.colors.background['alternative-pressed'].value, - ); - }); - - it('js tokens for background.hover matches figma tokens background.hover', () => { - expect(importableColors.background.hover).toStrictEqual( - designTokens.dark.colors.background.hover.value, - ); - }); - - it('js tokens for background.pressed matches figma tokens background.pressed', () => { - expect(importableColors.background.pressed).toStrictEqual( - designTokens.dark.colors.background.pressed.value, - ); - }); - - it('js tokens for text.default matches figma tokens text.default', () => { - expect(importableColors.text.default).toStrictEqual( - designTokens.dark.colors.text.default.value, - ); - }); - - it('js tokens for text.alternative matches figma tokens text.alternative', () => { - expect(importableColors.text.alternative).toStrictEqual( - designTokens.dark.colors.text.alternative.value, - ); - }); - - it('js tokens for text.muted matches figma tokens text.muted', () => { - expect(importableColors.text.muted).toStrictEqual( - designTokens.dark.colors.text.muted.value, - ); - }); - - it('js tokens for icon.default matches figma tokens icon.default', () => { - expect(importableColors.icon.default).toStrictEqual( - designTokens.dark.colors.icon.default.value, - ); - }); - - it('js tokens for icon.alternative matches figma tokens icon.alternative', () => { - expect(importableColors.icon.alternative).toStrictEqual( - designTokens.dark.colors.icon.alternative.value, - ); - }); - - it('js tokens for icon.muted matches figma tokens icon.muted', () => { - expect(importableColors.icon.muted).toStrictEqual( - designTokens.dark.colors.icon.muted.value, - ); - }); - - it('js tokens for border.default matches figma tokens border.default', () => { - expect(importableColors.border.default).toStrictEqual( - designTokens.dark.colors.border.default.value, - ); - }); - - it('js tokens for border.muted matches figma tokens border.muted', () => { - expect(importableColors.border.muted).toStrictEqual( - designTokens.dark.colors.border.muted.value, - ); - }); - - it('js tokens for overlay.default matches figma tokens overlay.default', () => { - expect(importableColors.overlay.default).toStrictEqual( - designTokens.dark.colors.overlay.default.value, - ); - }); - - it('js tokens for overlay.alternative matches figma tokens overlay.alternative', () => { - expect(importableColors.overlay.alternative).toStrictEqual( - designTokens.dark.colors.overlay.alternative.value, - ); - }); - - it('js tokens for overlay.inverse matches figma tokens overlay.inverse', () => { - expect(importableColors.overlay.inverse).toStrictEqual( - designTokens.dark.colors.overlay.inverse.value, - ); - }); - - it('js tokens for shadow.default matches figma tokens dark.shadows.xs.value.color', () => { - expect(importableColors.shadow.default).toStrictEqual( - designTokens.dark.shadows.xs.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.dark.shadows.sm.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.dark.shadows.md.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.dark.shadows.lg.value.color, - ); - }); - - it('js tokens for primary.default matches figma tokens primary.default', () => { - expect(importableColors.primary.default).toStrictEqual( - designTokens.dark.colors.primary.default.value, - ); - }); - - it('js tokens for primary.default-hover matches figma tokens primary.default-hover in dark mode', () => { - expect(importableColors.primary.defaultHover).toStrictEqual( - designTokens.dark.colors.primary['default-hover'].value, - ); - }); - - it('js tokens for primary.default-pressed matches figma tokens primary.default-pressed in dark mode', () => { - expect(importableColors.primary.defaultPressed).toStrictEqual( - designTokens.dark.colors.primary['default-pressed'].value, - ); - }); - - it('js tokens for primary.alternative matches figma tokens primary.alternative', () => { - expect(importableColors.primary.alternative).toStrictEqual( - designTokens.dark.colors.primary.alternative.value, - ); - }); - - it('js tokens for primary.muted matches figma tokens primary.muted', () => { - expect(importableColors.primary.muted).toStrictEqual( - designTokens.dark.colors.primary.muted.value, - ); - }); - - it('js tokens for primary.inverse matches figma tokens primary.inverse', () => { - expect(importableColors.primary.inverse).toStrictEqual( - designTokens.dark.colors.primary.inverse.value, - ); - }); - - it('js tokens for primary.shadow matches figma tokens shadows.primary', () => { - expect(importableColors.primary.shadow).toStrictEqual( - designTokens.dark.shadows.primary.value.color, - ); - }); - - it('js tokens for secondary.default matches figma tokens secondary.default', () => { - expect(importableColors.secondary.default).toStrictEqual( - designTokens.dark.colors.secondary.default.value, - ); - }); - - it('js tokens for secondary.alternative matches figma tokens secondary.alternative', () => { - expect(importableColors.secondary.alternative).toStrictEqual( - designTokens.dark.colors.secondary.alternative.value, - ); - }); - - it('js tokens for secondary.muted matches figma tokens secondary.muted', () => { - expect(importableColors.secondary.muted).toStrictEqual( - designTokens.dark.colors.secondary.muted.value, - ); - }); - - it('js tokens for secondary.inverse matches figma tokens secondary.inverse', () => { - expect(importableColors.secondary.inverse).toStrictEqual( - designTokens.dark.colors.secondary.inverse.value, - ); - }); - - it('js tokens for error.default matches figma tokens error.default', () => { - expect(importableColors.error.default).toStrictEqual( - designTokens.dark.colors.error.default.value, - ); - }); - - it('js tokens for error.default-hover matches figma tokens error.default-hover in dark mode', () => { - expect(importableColors.error.defaultHover).toStrictEqual( - designTokens.dark.colors.error['default-hover'].value, - ); - }); - - it('js tokens for error.default-pressed matches figma tokens error.default-pressed in dark mode', () => { - expect(importableColors.error.defaultPressed).toStrictEqual( - designTokens.dark.colors.error['default-pressed'].value, - ); - }); - - it('js tokens for error.alternative matches figma tokens error.alternative', () => { - expect(importableColors.error.alternative).toStrictEqual( - designTokens.dark.colors.error.alternative.value, - ); - }); - - it('js tokens for error.muted matches figma tokens error.muted', () => { - expect(importableColors.error.muted).toStrictEqual( - designTokens.dark.colors.error.muted.value, - ); - }); - - it('js tokens for error.inverse matches figma tokens error.inverse', () => { - expect(importableColors.error.inverse).toStrictEqual( - designTokens.dark.colors.error.inverse.value, - ); - }); - - it('js tokens for error.shadow matches figma tokens shadows.error', () => { - expect(importableColors.error.shadow).toStrictEqual( - designTokens.dark.shadows.error.value.color, - ); - }); - - it('js tokens for warning.default matches figma tokens warning.default', () => { - expect(importableColors.warning.default).toStrictEqual( - designTokens.dark.colors.warning.default.value, - ); - }); - - it('js tokens for warning.default-hover matches figma tokens warning.default-hover in dark mode', () => { - expect(importableColors.warning.defaultHover).toStrictEqual( - designTokens.dark.colors.warning['default-hover'].value, - ); - }); - - it('js tokens for warning.default-pressed matches figma tokens warning.default-pressed in dark mode', () => { - expect(importableColors.warning.defaultPressed).toStrictEqual( - designTokens.dark.colors.warning['default-pressed'].value, - ); - }); - - it('js tokens for warning.alternative matches figma tokens warning.alternative', () => { - expect(importableColors.warning.alternative).toStrictEqual( - designTokens.dark.colors.warning.alternative.value, - ); - }); - - it('js tokens for warning.muted matches figma tokens warning.muted', () => { - expect(importableColors.warning.muted).toStrictEqual( - designTokens.dark.colors.warning.muted.value, - ); - }); - - it('js tokens for warning.inverse matches figma tokens warning.inverse', () => { - expect(importableColors.warning.inverse).toStrictEqual( - designTokens.dark.colors.warning.inverse.value, - ); - }); - - it('js tokens for success.default matches figma tokens success.default', () => { - expect(importableColors.success.default).toStrictEqual( - designTokens.dark.colors.success.default.value, - ); - }); - - it('js tokens for success.default-hover matches figma tokens success.default-hover in dark mode', () => { - expect(importableColors.success.defaultHover).toStrictEqual( - designTokens.dark.colors.success['default-hover'].value, - ); - }); - - it('js tokens for success.default-pressed matches figma tokens success.default-pressed in dark mode', () => { - expect(importableColors.success.defaultPressed).toStrictEqual( - designTokens.dark.colors.success['default-pressed'].value, - ); - }); - - it('js tokens for success.alternative matches figma tokens success.alternative', () => { - expect(importableColors.success.alternative).toStrictEqual( - designTokens.dark.colors.success.alternative.value, - ); - }); - - it('js tokens for success.muted matches figma tokens success.muted', () => { - expect(importableColors.success.muted).toStrictEqual( - designTokens.dark.colors.success.muted.value, - ); - }); - - it('js tokens for success.inverse matches figma tokens success.inverse', () => { - expect(importableColors.success.inverse).toStrictEqual( - designTokens.dark.colors.success.inverse.value, - ); - }); - - it('js tokens for info.default matches figma tokens info.default', () => { - expect(importableColors.info.default).toStrictEqual( - designTokens.dark.colors.info.default.value, - ); - }); - - it('js tokens for info.alternative matches figma tokens info.alternative', () => { - expect(importableColors.info.alternative).toStrictEqual( - designTokens.dark.colors.info.alternative.value, - ); - }); - - it('js tokens for info.muted matches figma tokens info.muted', () => { - expect(importableColors.info.muted).toStrictEqual( - designTokens.dark.colors.info.muted.value, - ); - }); - - it('js tokens for info.inverse matches figma tokens info.inverse', () => { - expect(importableColors.info.inverse).toStrictEqual( - designTokens.dark.colors.info.inverse.value, - ); - }); - - it('js tokens for networks.goerli.default matches figma tokens networks.goerli.default', () => { - expect(importableColors.networks.goerli.default).toStrictEqual( - designTokens.dark.colors.networks.goerli.default.value, - ); - }); - - it('js tokens for networks.goerli.inverse matches figma tokens networks.goerli.inverse', () => { - expect(importableColors.networks.goerli.inverse).toStrictEqual( - designTokens.dark.colors.networks.goerli.inverse.value, - ); - }); - - it('js tokens for networks.localhost.default matches figma tokens networks.localhost.default', () => { - expect(importableColors.networks.localhost.default).toStrictEqual( - designTokens.dark.colors.networks.localhost.default.value, - ); - }); - - it('js tokens for networks.localhost.inverse matches figma tokens networks.localhost.inverse', () => { - expect(importableColors.networks.localhost.inverse).toStrictEqual( - designTokens.dark.colors.networks.localhost.inverse.value, - ); - }); - - it('js tokens for networks.sepolia.default matches figma tokens networks.sepolia.default', () => { - expect(importableColors.networks.sepolia.default).toStrictEqual( - designTokens.dark.colors.networks.sepolia.default.value, - ); - }); - - it('js tokens for networks.sepolia.inverse matches figma tokens networks.sepolia.inverse', () => { - expect(importableColors.networks.sepolia.inverse).toStrictEqual( - designTokens.dark.colors.networks.sepolia.inverse.value, - ); - }); - - it('js tokens for flask.default matches figma tokens flask.default', () => { - expect(importableColors.flask.default).toStrictEqual( - designTokens.dark.colors.flask.default.value, - ); - }); - - it('js tokens for flask.inverse matches figma tokens flask.inverse', () => { - expect(importableColors.flask.inverse).toStrictEqual( - designTokens.dark.colors.flask.inverse.value, - ); +import * as brandColors from '../../../figma/brandColors.json'; +import * as darkTheme from '../../../figma/darkTheme.json'; +import { colors as definedColors } from './colors'; + +type ColorDetails = { + value: string; + type: string; + parent: string; + description: string; +}; + +/** + * Recursively resolve color references in a theme object. + * @param theme - Object containing theme definitions. + * @param colors - Object containing color definitions. + * @param rootTheme - Root theme object. + */ +function resolveColorReferences( + theme: any, + colors: any, + rootTheme?: any, +): void { + Object.keys(theme).forEach((key) => { + if (typeof theme[key] === 'object' && theme[key] !== null) { + resolveColorReferences(theme[key], colors, rootTheme || theme); + } else if (typeof theme[key] === 'string' && theme[key].startsWith('{')) { + const match = theme[key].match(/\{(.+?)\}/u); + if (match) { + const [colorFamily, shade] = match[1].split('.'); + if (colors[colorFamily]?.[shade]) { + theme[key] = colors[colorFamily][shade].value; + } else if (rootTheme?.[colorFamily]?.[shade]?.value) { + theme[key] = rootTheme[colorFamily][shade].value; + } + } + } + }); +} + +describe('Theme Color Resolution', () => { + const clonedTheme = JSON.parse(JSON.stringify(darkTheme)) as { + [key: string]: { [key: string]: ColorDetails }; + }; + resolveColorReferences(clonedTheme, brandColors, clonedTheme); + + Object.entries(clonedTheme).forEach(([category, details]) => { + if (category !== 'default') { + // Skip 'default' category if it's not part of definedColors + Object.entries(details).forEach(([key, detail]) => { + const cleanKey = key + .replace(/\*/gu, '') + .replace(/-([a-z])/gu, (_, p1) => p1.toUpperCase()) + .replace(/\s*\(strong\)\s*/gu, ''); + it(`ensures ${category}.${cleanKey} matches defined color`, () => { + expect((definedColors as any)[category][cleanKey]).toStrictEqual( + detail.value, + ); + }); + }); + } }); }); diff --git a/src/js/themes/darkTheme/colors.ts b/src/js/themes/darkTheme/colors.ts index 09c9f1f1..ed8219f7 100644 --- a/src/js/themes/darkTheme/colors.ts +++ b/src/js/themes/darkTheme/colors.ts @@ -1,110 +1,78 @@ +import { brandColor } from '../../brandColor'; import type { ThemeColors } from '../types'; -/** - * Dark theme colors - */ - export const colors: ThemeColors = { background: { - default: '#24272A', - defaultHover: '#282B2E', - defaultPressed: '#36383B', - alternative: '#141618', - alternativeHover: '#191B1D', - alternativePressed: '#27292A', - hover: '#FFFFFF05', - pressed: '#FFFFFF14', + default: brandColor.grey800, // For default neutral backgrounds + alternative: brandColor.grey900, // For secondary neutral backgrounds. + defaultHover: '#313235', // For "hover" states that use background-default. + defaultPressed: '#3f4145', // For "pressed" states that use background-alternative. + alternativeHover: '#1f2123', // For "hover" states that use background-alternative. + alternativePressed: '#2e3033', // For "pressed" states that use background-alternative. + hover: '#ffffff0a', // For "hover" state that use no background fill. + pressed: '#ffffff14', // For "pressed" state that use no background fill. }, text: { - default: '#FFFFFF', - alternative: '#D6D9DC', - muted: '#9FA6AE', + default: brandColor.grey000, // For default neutral text. + alternative: brandColor.grey200, // For softer contrast neutral text + muted: brandColor.grey400, // For the softest contrast neutral text (not accessible) }, icon: { - default: '#FFFFFF', - alternative: '#BBC0C5', - muted: '#9FA6AE', + default: brandColor.grey000, // For default neutral icons + alternative: brandColor.grey200, // For softer neutral icons + muted: brandColor.grey400, // For the weakest contrast neutral icons (not accessible) }, border: { - default: '#848C96', - muted: '#3B4046', + default: brandColor.grey400, // For soft contrast neutral border + muted: '#848c9629', // For the weakest contrast neutral border }, overlay: { - default: '#00000099', - inverse: '#FCFCFC', - alternative: '#000000CC', - }, - shadow: { - default: '#00000066', + default: '#00000099', // For the default shade of screen + alternative: '#000000cc', // For a stronger shade of screen + inverse: brandColor.grey000, // For elements used on top of overlay/alternative. Used for text, icon or border }, primary: { - default: '#1098FC', - defaultHover: '#0092FA', - defaultPressed: '#54B6FC', - alternative: '#43AEFC', - muted: '#1098FC26', - inverse: '#141618', - disabled: '#1098FC80', - shadow: '#1098FC66', - }, - secondary: { - default: '#F8883B', - alternative: '#FAA66C', - muted: '#F8883B26', - inverse: '#FCFCFC', - disabled: '#F8883B80', + default: brandColor.blue300, // For interactive, active, and selected semantics. Used for text, background, icon or border + alternative: brandColor.blue200, // For the stronger contrast primary semantic elements. + muted: '#43aefc26', // For the weakest contrast primary semantic backgrounds. + inverse: brandColor.grey900, // For elements used on top of primary/default. Used for text, icon or border + defaultHover: '#26a2fc', // For the "hover" state of primary-default elements + defaultPressed: '#3baafd', // For the "pressed" state of primary-default elements }, error: { - default: '#FF5263', - defaultHover: '#FF4D58', - defaultPressed: '#F9868E', - alternative: '#E88F97', - muted: '#FF526326', - inverse: '#141618', - disabled: '#D7384780', - shadow: '#FF526366', + default: brandColor.red300, // For the critical alert semantic elements. Used for text, background, icon or border + alternative: brandColor.red200, // For the stronger contrast error semantic elements. + muted: '#e88f9726', // For the weakest contrast critical alert semantic backgrounds. + inverse: brandColor.grey900, // For elements used on top of error/default. Used for text, icon or border + defaultHover: '#e47782', // For the "hover" state of error-default elements. + defaultPressed: '#e78891', // For the "pressed" state of error-default elements. }, warning: { - default: '#FFD33D', - defaultHover: '#FFC60A', - defaultPressed: '#FFEAA3D1', - alternative: '#FFDF70', - muted: '#FFD33D26', - inverse: '#141618', - disabled: '#FFD33D80', + default: brandColor.yellow100, // For the caution alert semantic elements. Used for text, background, icon or border + muted: '#ffdf7026', // For the weakest contrast caution alert semantic backgrounds. + inverse: brandColor.grey900, // For elements used on top of warning/default. Used for text, icon or border + defaultHover: '#ffe485', // For the "hover" state of warning-default elements + defaultPressed: '#ffe899', // For the "pressed" state of warning-default elements }, success: { - default: '#28A745', - defaultHover: '#05B82F', - defaultPressed: '#6AEC88', - alternative: '#5DD879', - muted: '#28A74526', - inverse: '#141618', - disabled: '#28A74580', + default: brandColor.green300, // For the positive semantic elements. Used for text, background, icon or border + muted: '#28a74526', // For the weakest contrast positive semantic backgrounds. + inverse: brandColor.grey900, // For elements used on top of success/default. Used for text, icon or border + defaultHover: '#2cb94c', // For the "hover" state of success-default elements + defaultPressed: '#30ca53', // For the "pressed" state of success-default elements }, info: { - default: '#1098FC', - alternative: '#43AEFC', - muted: '#1098FC26', - inverse: '#141618', - disabled: '#0376C980', - }, - networks: { - goerli: { - default: '#1098FC', - inverse: '#FCFCFC', - }, - localhost: { - default: '#BBC0C5', - inverse: '#FCFCFC', - }, - sepolia: { - default: '#CFB5F0', - inverse: '#FCFCFC', - }, + default: brandColor.blue300, // For informational read-only elements. Used for text, background, icon or border + muted: '#43aefc26', // For the weakest contrast informational semantic backgrounds. + inverse: brandColor.grey900, // For elements used on top of info/default. Used for text, icon or border }, flask: { - default: '#8B45B6', - inverse: '#FCFCFC', + default: brandColor.purple300, // For Flask primary accent color. + inverse: brandColor.grey900, // For elements used on top of flask/default. Used for text, icon or border + }, + shadow: { + default: '#00000066', // For neutral drop shadow color. + primary: '#43aefc33', // For primary drop shadow color. + error: '#ff758466', // For critical/danger drop shadow color. }, }; diff --git a/src/js/themes/darkTheme/darkTheme.test.ts b/src/js/themes/darkTheme/darkTheme.test.ts index a064f55f..7e28962c 100644 --- a/src/js/themes/darkTheme/darkTheme.test.ts +++ b/src/js/themes/darkTheme/darkTheme.test.ts @@ -3,11 +3,9 @@ import { darkTheme } from './darkTheme'; const designTokens = require('../../../figma/tokens.json'); -describe('dark Theme', () => { +describe('Dark Theme', () => { it('color tokens are exported from darkTheme by checking first color token', () => { - expect(darkTheme.colors.background.default).toStrictEqual( - designTokens.dark.colors.background.default.value, - ); + expect(darkTheme.colors.background.default).toBe('#24272a'); }); it('typography tokens are exported from darkTheme by checking first typography token', () => { @@ -18,7 +16,7 @@ describe('dark Theme', () => { it('shadow tokens are exported from darkTheme by checking first shadow size object', () => { expect(darkTheme.shadows.size.xs).toStrictEqual({ - shadowColor: designTokens.dark.shadows.xs.value.color, + shadowColor: designTokens.dark.shadows.xs.value.color.toLowerCase(), shadowOffset: { width: Number(designTokens.dark.shadows.xs.value.x), height: Number(designTokens.dark.shadows.xs.value.y), diff --git a/src/js/themes/lightTheme/colors.test.ts b/src/js/themes/lightTheme/colors.test.ts index 91b13cf7..5c4e04f5 100644 --- a/src/js/themes/lightTheme/colors.test.ts +++ b/src/js/themes/lightTheme/colors.test.ts @@ -1,390 +1,62 @@ -/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ -import { colors as importableColors } from './colors'; - -const designTokens = require('../../../figma/tokens.json'); - -describe('Light Theme Colors', () => { - it('js tokens for background.default matches figma tokens background.default', () => { - expect(importableColors.background.default).toStrictEqual( - designTokens.light.colors.background.default.value, - ); - }); - - it('js tokens for background.defaultHover matches figma tokens background.defaultHover', () => { - expect(importableColors.background.defaultHover).toStrictEqual( - designTokens.light.colors.background['default-hover'].value, - ); - }); - - it('js tokens for background.defaultPressed matches figma tokens background.defaultPressed', () => { - expect(importableColors.background.defaultPressed).toStrictEqual( - designTokens.light.colors.background['default-pressed'].value, - ); - }); - - it('js tokens for background.alternative matches figma tokens background.alternative', () => { - expect(importableColors.background.alternative).toStrictEqual( - designTokens.light.colors.background.alternative.value, - ); - }); - - it('js tokens for background.alternativeHover matches figma tokens background.alternativeHover', () => { - expect(importableColors.background.alternativeHover).toStrictEqual( - designTokens.light.colors.background['alternative-hover'].value, - ); - }); - - it('js tokens for background.alternativePressed matches figma tokens background.alternativePressed', () => { - expect(importableColors.background.alternativePressed).toStrictEqual( - designTokens.light.colors.background['alternative-pressed'].value, - ); - }); - - it('js tokens for background.hover matches figma tokens background.hover', () => { - expect(importableColors.background.hover).toStrictEqual( - designTokens.light.colors.background.hover.value, - ); - }); - - it('js tokens for background.pressed matches figma tokens background.pressed', () => { - expect(importableColors.background.pressed).toStrictEqual( - designTokens.light.colors.background.pressed.value, - ); - }); - - it('js tokens for text.default matches figma tokens text.default', () => { - expect(importableColors.text.default).toStrictEqual( - designTokens.light.colors.text.default.value, - ); - }); - - it('js tokens for text.alternative matches figma tokens text.alternative', () => { - expect(importableColors.text.alternative).toStrictEqual( - designTokens.light.colors.text.alternative.value, - ); - }); - - it('js tokens for text.muted matches figma tokens text.muted', () => { - expect(importableColors.text.muted).toStrictEqual( - designTokens.light.colors.text.muted.value, - ); - }); - - it('js tokens for icon.default matches figma tokens icon.default', () => { - expect(importableColors.icon.default).toStrictEqual( - designTokens.light.colors.icon.default.value, - ); - }); - - it('js tokens for icon.alternative matches figma tokens icon.alternative', () => { - expect(importableColors.icon.alternative).toStrictEqual( - designTokens.light.colors.icon.alternative.value, - ); - }); - - it('js tokens for icon.muted matches figma tokens icon.muted', () => { - expect(importableColors.icon.muted).toStrictEqual( - designTokens.light.colors.icon.muted.value, - ); - }); - - it('js tokens for border.default matches figma tokens border.default', () => { - expect(importableColors.border.default).toStrictEqual( - designTokens.light.colors.border.default.value, - ); - }); - - it('js tokens for border.muted matches figma tokens border.muted', () => { - expect(importableColors.border.muted).toStrictEqual( - designTokens.light.colors.border.muted.value, - ); - }); - - it('js tokens for overlay.default matches figma tokens overlay.default', () => { - expect(importableColors.overlay.default).toStrictEqual( - designTokens.light.colors.overlay.default.value, - ); - }); - - it('js tokens for overlay.alternative matches figma tokens overlay.alternative', () => { - expect(importableColors.overlay.alternative).toStrictEqual( - designTokens.light.colors.overlay.alternative.value, - ); - }); - - it('js tokens for overlay.inverse matches figma tokens overlay.inverse', () => { - expect(importableColors.overlay.inverse).toStrictEqual( - designTokens.light.colors.overlay.inverse.value, - ); - }); - - it('js tokens for shadow.default matches figma tokens light.shadows.xs.value.color', () => { - expect(importableColors.shadow.default).toStrictEqual( - designTokens.light.shadows.xs.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.light.shadows.sm.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.light.shadows.md.value.color, - ); - - expect(importableColors.shadow.default).toStrictEqual( - designTokens.light.shadows.lg.value.color, - ); - }); - - it('js tokens for primary.default matches figma tokens primary.default', () => { - expect(importableColors.primary.default).toStrictEqual( - designTokens.light.colors.primary.default.value, - ); - }); - - it('js tokens for primary.default-hover matches figma tokens primary.default-hover', () => { - expect(importableColors.primary.defaultHover).toStrictEqual( - designTokens.light.colors.primary['default-hover'].value, - ); - }); - - it('js tokens for primary.default-pressed matches figma tokens primary.default-pressed', () => { - expect(importableColors.primary.defaultPressed).toStrictEqual( - designTokens.light.colors.primary['default-pressed'].value, - ); - }); - - it('js tokens for primary.alternative matches figma tokens primary.alternative', () => { - expect(importableColors.primary.alternative).toStrictEqual( - designTokens.light.colors.primary.alternative.value, - ); - }); - - it('js tokens for primary.muted matches figma tokens primary.muted', () => { - expect(importableColors.primary.muted).toStrictEqual( - designTokens.light.colors.primary.muted.value, - ); - }); - - it('js tokens for primary.inverse matches figma tokens primary.inverse', () => { - expect(importableColors.primary.inverse).toStrictEqual( - designTokens.light.colors.primary.inverse.value, - ); - }); - - it('js tokens for primary.shadow matches figma tokens shadows.primary', () => { - expect(importableColors.primary.shadow).toStrictEqual( - designTokens.light.shadows.primary.value.color, - ); - }); - - it('js tokens for secondary.default matches figma tokens secondary.default', () => { - expect(importableColors.secondary.default).toStrictEqual( - designTokens.light.colors.secondary.default.value, - ); - }); - - it('js tokens for secondary.alternative matches figma tokens secondary.alternative', () => { - expect(importableColors.secondary.alternative).toStrictEqual( - designTokens.light.colors.secondary.alternative.value, - ); - }); - - it('js tokens for secondary.muted matches figma tokens secondary.muted', () => { - expect(importableColors.secondary.muted).toStrictEqual( - designTokens.light.colors.secondary.muted.value, - ); - }); - - it('js tokens for secondary.inverse matches figma tokens secondary.inverse', () => { - expect(importableColors.secondary.inverse).toStrictEqual( - designTokens.light.colors.secondary.inverse.value, - ); - }); - - it('js tokens for error.default matches figma tokens error.default', () => { - expect(importableColors.error.default).toStrictEqual( - designTokens.light.colors.error.default.value, - ); - }); - - it('js tokens for error.default-hover matches figma tokens error.default-hover', () => { - expect(importableColors.error.defaultHover).toStrictEqual( - designTokens.light.colors.error['default-hover'].value, - ); - }); - - it('js tokens for error.default-pressed matches figma tokens error.default-pressed', () => { - expect(importableColors.error.defaultPressed).toStrictEqual( - designTokens.light.colors.error['default-pressed'].value, - ); - }); - - it('js tokens for error.alternative matches figma tokens error.alternative', () => { - expect(importableColors.error.alternative).toStrictEqual( - designTokens.light.colors.error.alternative.value, - ); - }); - - it('js tokens for error.muted matches figma tokens error.muted', () => { - expect(importableColors.error.muted).toStrictEqual( - designTokens.light.colors.error.muted.value, - ); - }); - - it('js tokens for error.inverse matches figma tokens error.inverse', () => { - expect(importableColors.error.inverse).toStrictEqual( - designTokens.light.colors.error.inverse.value, - ); - }); - - it('js tokens for error.shadow matches figma tokens shadows.error', () => { - expect(importableColors.error.shadow).toStrictEqual( - designTokens.light.shadows.error.value.color, - ); - }); - - it('js tokens for warning.default matches figma tokens warning.default', () => { - expect(importableColors.warning.default).toStrictEqual( - designTokens.light.colors.warning.default.value, - ); - }); - - it('js tokens for warning.default-hover matches figma tokens warning.default-hover', () => { - expect(importableColors.warning.defaultHover).toStrictEqual( - designTokens.light.colors.warning['default-hover'].value, - ); - }); - - it('js tokens for warning.default-pressed matches figma tokens warning.default-pressed', () => { - expect(importableColors.warning.defaultPressed).toStrictEqual( - designTokens.light.colors.warning['default-pressed'].value, - ); - }); - - it('js tokens for warning.alternative matches figma tokens warning.alternative', () => { - expect(importableColors.warning.alternative).toStrictEqual( - designTokens.light.colors.warning.alternative.value, - ); - }); - - it('js tokens for warning.muted matches figma tokens warning.muted', () => { - expect(importableColors.warning.muted).toStrictEqual( - designTokens.light.colors.warning.muted.value, - ); - }); - - it('js tokens for warning.inverse matches figma tokens warning.inverse', () => { - expect(importableColors.warning.inverse).toStrictEqual( - designTokens.light.colors.warning.inverse.value, - ); - }); - - it('js tokens for success.default matches figma tokens success.default', () => { - expect(importableColors.success.default).toStrictEqual( - designTokens.light.colors.success.default.value, - ); - }); - - it('js tokens for success.default-hover matches figma tokens success.default-hover', () => { - expect(importableColors.success.defaultHover).toStrictEqual( - designTokens.light.colors.success['default-hover'].value, - ); - }); - - it('js tokens for success.default-pressed matches figma tokens success.default-pressed', () => { - expect(importableColors.success.defaultPressed).toStrictEqual( - designTokens.light.colors.success['default-pressed'].value, - ); - }); - - it('js tokens for success.alternative matches figma tokens success.alternative', () => { - expect(importableColors.success.alternative).toStrictEqual( - designTokens.light.colors.success.alternative.value, - ); - }); - - it('js tokens for success.muted matches figma tokens success.muted', () => { - expect(importableColors.success.muted).toStrictEqual( - designTokens.light.colors.success.muted.value, - ); - }); - - it('js tokens for success.inverse matches figma tokens success.inverse', () => { - expect(importableColors.success.inverse).toStrictEqual( - designTokens.light.colors.success.inverse.value, - ); - }); - - it('js tokens for info.default matches figma tokens info.default', () => { - expect(importableColors.info.default).toStrictEqual( - designTokens.light.colors.info.default.value, - ); - }); - - it('js tokens for info.alternative matches figma tokens info.alternative', () => { - expect(importableColors.info.alternative).toStrictEqual( - designTokens.light.colors.info.alternative.value, - ); - }); - - it('js tokens for info.muted matches figma tokens info.muted', () => { - expect(importableColors.info.muted).toStrictEqual( - designTokens.light.colors.info.muted.value, - ); - }); - - it('js tokens for info.inverse matches figma tokens info.inverse', () => { - expect(importableColors.info.inverse).toStrictEqual( - designTokens.light.colors.info.inverse.value, - ); - }); - - it('js tokens for networks.goerli.default matches figma tokens networks.goerli.default', () => { - expect(importableColors.networks.goerli.default).toStrictEqual( - designTokens.light.colors.networks.goerli.default.value, - ); - }); - - it('js tokens for networks.goerli.inverse matches figma tokens networks.goerli.inverse', () => { - expect(importableColors.networks.goerli.inverse).toStrictEqual( - designTokens.light.colors.networks.goerli.inverse.value, - ); - }); - - it('js tokens for networks.localhost.default matches figma tokens networks.localhost.default', () => { - expect(importableColors.networks.localhost.default).toStrictEqual( - designTokens.light.colors.networks.localhost.default.value, - ); - }); - - it('js tokens for networks.localhost.inverse matches figma tokens networks.localhost.inverse', () => { - expect(importableColors.networks.localhost.inverse).toStrictEqual( - designTokens.light.colors.networks.localhost.inverse.value, - ); - }); - - it('js tokens for networks.sepolia.default matches figma tokens networks.sepolia.default', () => { - expect(importableColors.networks.sepolia.default).toStrictEqual( - designTokens.light.colors.networks.sepolia.default.value, - ); - }); - - it('js tokens for networks.sepolia.inverse matches figma tokens networks.sepolia.inverse', () => { - expect(importableColors.networks.sepolia.inverse).toStrictEqual( - designTokens.light.colors.networks.sepolia.inverse.value, - ); - }); - - it('js tokens for flask.default matches figma tokens flask.default', () => { - expect(importableColors.flask.default).toStrictEqual( - designTokens.light.colors.flask.default.value, - ); - }); - - it('js tokens for flask.inverse matches figma tokens flask.inverse', () => { - expect(importableColors.flask.inverse).toStrictEqual( - designTokens.light.colors.flask.inverse.value, - ); +import * as brandColors from '../../../figma/brandColors.json'; +import * as lightTheme from '../../../figma/lightTheme.json'; +import { colors as definedColors } from './colors'; + +type ColorDetails = { + value: string; + type: string; + parent: string; + description: string; +}; + +/** + * Recursively resolve color references in a theme object. + * @param theme - Object containing theme definitions. + * @param colors - Object containing color definitions. + * @param rootTheme - Root theme object. + */ +function resolveColorReferences( + theme: any, + colors: any, + rootTheme?: any, +): void { + Object.keys(theme).forEach((key) => { + if (typeof theme[key] === 'object' && theme[key] !== null) { + resolveColorReferences(theme[key], colors, rootTheme || theme); + } else if (typeof theme[key] === 'string' && theme[key].startsWith('{')) { + const match = theme[key].match(/\{(.+?)\}/u); + if (match) { + const [colorFamily, shade] = match[1].split('.'); + if (colors[colorFamily]?.[shade]) { + theme[key] = colors[colorFamily][shade].value; + } else if (rootTheme?.[colorFamily]?.[shade]?.value) { + theme[key] = rootTheme[colorFamily][shade].value; + } + } + } + }); +} + +describe('Theme Color Resolution', () => { + const clonedTheme = JSON.parse(JSON.stringify(lightTheme)) as { + [key: string]: { [key: string]: ColorDetails }; + }; + resolveColorReferences(clonedTheme, brandColors, clonedTheme); + + Object.entries(clonedTheme).forEach(([category, details]) => { + if (category !== 'default') { + // Skip 'default' category if it's not part of definedColors + Object.entries(details).forEach(([key, detail]) => { + const cleanKey = key + .replace(/\*/gu, '') + .replace(/-([a-z])/gu, (_, p1) => p1.toUpperCase()) + .replace(/\s*\(strong\)\s*/gu, ''); + it(`ensures ${category}.${cleanKey} matches defined color`, () => { + expect((definedColors as any)[category][cleanKey]).toStrictEqual( + detail.value, + ); + }); + }); + } }); }); diff --git a/src/js/themes/lightTheme/colors.ts b/src/js/themes/lightTheme/colors.ts index 39a54114..9dc1d0a1 100644 --- a/src/js/themes/lightTheme/colors.ts +++ b/src/js/themes/lightTheme/colors.ts @@ -1,110 +1,78 @@ +import { brandColor } from '../../brandColor'; import type { ThemeColors } from '../types'; -/** - * Light theme colors - */ - export const colors: ThemeColors = { background: { - default: '#FFFFFF', - defaultHover: '#FAFAFA', - defaultPressed: '#EBEBEB', - alternative: '#F2F4F6', - alternativeHover: '#EDEFF1', - alternativePressed: '#DFE0E2', - hover: '#00000005', - pressed: '#00000014', + default: brandColor.grey000, // For default neutral backgrounds + alternative: brandColor.grey050, // For secondary neutral backgrounds. + defaultHover: '#f5f5f5', // For "hover" states that use background-default. + defaultPressed: '#ebebeb', // For "pressed" states that use background-alternative. + alternativeHover: '#e7ebee', // For "hover" states that use background-alternative. + alternativePressed: '#dbe0e6', // For "pressed" states that use background-alternative. + hover: '#0000000a', // For "hover" state that use no background fill. + pressed: '#00000014', // For "pressed" state that use no background fill. }, text: { - default: '#24272A', - alternative: '#535A61', - muted: '#BBC0C5', + default: brandColor.grey900, // For default neutral text. + alternative: brandColor.grey500, // For softer contrast neutral text + muted: brandColor.grey300, // For the softest contrast neutral text (not accessible) }, icon: { - default: '#24272A', - alternative: '#6A737D', - muted: '#BBC0C5', + default: brandColor.grey900, // For default neutral icons + alternative: brandColor.grey500, // For softer neutral icons + muted: brandColor.grey300, // For the weakest contrast neutral icons (not accessible) }, border: { - default: '#BBC0C5', - muted: '#D6D9DC', + default: brandColor.grey200, // For soft contrast neutral border + muted: '#bbc0c566', // For the weakest contrast neutral border }, overlay: { - default: '#00000099', - inverse: '#FCFCFC', - alternative: '#000000CC', - }, - shadow: { - default: '#0000001A', + default: '#00000099', // For the default shade of screen + alternative: '#000000cc', // For a stronger shade of screen + inverse: brandColor.grey000, // For elements used on top of overlay/alternative. Used for text, icon or border }, primary: { - default: '#0376C9', - defaultHover: '#0379CE', - defaultPressed: '#036DB9', - alternative: '#0260A4', - muted: '#0376C919', - inverse: '#FFFFFF', - disabled: '#0376C980', - shadow: '#0376C933', - }, - secondary: { - default: '#F66A0A', - alternative: '#BF5208', - muted: '#F66A0A19', - inverse: '#FCFCFC', - disabled: '#F66A0A80', + default: brandColor.blue500, // For interactive, active, and selected semantics. Used for text, background, icon or border + alternative: brandColor.blue600, // For the stronger contrast primary semantic elements. + muted: '#0376c91a', // For the weakest contrast primary semantic backgrounds. + inverse: brandColor.grey000, // For elements used on top of primary/default. Used for text, icon or border + defaultHover: '#036ab5', // For the "hover" state of primary-default elements + defaultPressed: '#025ea1', // For the "pressed" state of primary-default elements }, error: { - default: '#D73847', - defaultHover: '#CD4250', - defaultPressed: '#C63441', - alternative: '#B92534', - muted: '#D7384719', - inverse: '#FFFFFF', - disabled: '#D7384780', - shadow: '#D7384766', + default: brandColor.red500, // For the critical alert semantic elements. Used for text, background, icon or border + alternative: brandColor.red600, // For the stronger contrast error semantic elements. + muted: '#d738471a', // For the weakest contrast critical alert semantic backgrounds. + inverse: brandColor.grey000, // For elements used on top of error/default. Used for text, icon or border + defaultHover: '#d02a3a', // For the "hover" state of error-default elements. + defaultPressed: '#bf2635', // For the "pressed" state of error-default elements. }, warning: { - default: '#BF5208', - defaultHover: '#C2540A', - defaultPressed: '#A24507', - alternative: '#FFC70A', - muted: '#BF520819', - inverse: '#FFFFFF', - disabled: '#FFD33D80', + default: brandColor.yellow500, // For the caution alert semantic elements. Used for text, background, icon or border + muted: '#bf52081a', // For the weakest contrast caution alert semantic backgrounds. + inverse: brandColor.grey000, // For elements used on top of warning/default. Used for text, icon or border + defaultHover: '#ac4a07', // For the "hover" state of warning-default elements + defaultPressed: '#984106', // For the "pressed" state of warning-default elements }, success: { - default: '#1C8234', - defaultHover: '#208838', - defaultPressed: '#1B7431', - alternative: '#1C8234', - muted: '#1C823419', - inverse: '#FFFFFF', - disabled: '#28A74580', + default: brandColor.green500, // For the positive semantic elements. Used for text, background, icon or border + muted: '#1c82341a', // For the weakest contrast positive semantic backgrounds. + inverse: brandColor.grey000, // For elements used on top of success/default. Used for text, icon or border + defaultHover: '#18712d', // For the "hover" state of success-default elements + defaultPressed: '#156127', // For the "pressed" state of success-default elements }, info: { - default: '#0376C9', - alternative: '#0260A4', - muted: '#0376C919', - inverse: '#FFFFFF', - disabled: '#0376C980', - }, - networks: { - goerli: { - default: '#1098FC', - inverse: '#FCFCFC', - }, - localhost: { - default: '#BBC0C5', - inverse: '#FCFCFC', - }, - sepolia: { - default: '#CFB5F0', - inverse: '#FCFCFC', - }, + default: brandColor.blue500, // For informational read-only elements. Used for text, background, icon or border + muted: '#0376c91a', // For the weakest contrast informational semantic backgrounds. + inverse: brandColor.grey000, // For elements used on top of info/default. Used for text, icon or border }, flask: { - default: '#8B45B6', - inverse: '#FCFCFC', + default: brandColor.purple500, // For Flask primary accent color. + inverse: brandColor.grey000, // For elements used on top of flask/default. Used for text, icon or border + }, + shadow: { + default: '#0000001a', // For neutral drop shadow color. + primary: '#0376c933', // For primary drop shadow color. + error: '#ca354266', // For critical/danger drop shadow color. }, }; diff --git a/src/js/themes/lightTheme/lightTheme.test.ts b/src/js/themes/lightTheme/lightTheme.test.ts index 29a8b927..a12e73c3 100644 --- a/src/js/themes/lightTheme/lightTheme.test.ts +++ b/src/js/themes/lightTheme/lightTheme.test.ts @@ -5,9 +5,7 @@ const designTokens = require('../../../figma/tokens.json'); describe('Light Theme', () => { it('color tokens are exported from lightTheme by checking first color token', () => { - expect(lightTheme.colors.background.default).toStrictEqual( - designTokens.light.colors.background.default.value, - ); + expect(lightTheme.colors.background.default).toBe('#ffffff'); }); it('typography tokens are exported from lightTheme by checking first typography token', () => { @@ -18,7 +16,7 @@ describe('Light Theme', () => { it('shadow tokens are exported from lightTheme by checking first shadow size object', () => { expect(lightTheme.shadows.size.xs).toStrictEqual({ - shadowColor: designTokens.light.shadows.xs.value.color, + shadowColor: designTokens.light.shadows.xs.value.color.toLowerCase(), shadowOffset: { width: Number(designTokens.light.shadows.xs.value.x), height: Number(designTokens.light.shadows.xs.value.y), diff --git a/src/js/themes/lightTheme/shadows.test.ts b/src/js/themes/lightTheme/shadows.test.ts index ec77d717..67e42ca5 100644 --- a/src/js/themes/lightTheme/shadows.test.ts +++ b/src/js/themes/lightTheme/shadows.test.ts @@ -5,7 +5,7 @@ const designTokens = require('../../../figma/tokens.json'); describe('Shadows', () => { it('js tokens shadows.size.xs matches figma tokens shadows.xs', () => { - expect(shadows.size.xs.shadowColor).toStrictEqual( + expect(shadows.size.xs.shadowColor.toUpperCase()).toStrictEqual( designTokens.light.shadows.xs.value.color, ); @@ -25,7 +25,7 @@ describe('Shadows', () => { }); it('js tokens shadows.size.sm matches figma tokens shadows.sm', () => { - expect(shadows.size.sm.shadowColor).toStrictEqual( + expect(shadows.size.sm.shadowColor.toUpperCase()).toStrictEqual( designTokens.light.shadows.sm.value.color, ); @@ -45,7 +45,7 @@ describe('Shadows', () => { }); it('js tokens shadows.size.md matches figma tokens shadows.md', () => { - expect(shadows.size.md.shadowColor).toStrictEqual( + expect(shadows.size.md.shadowColor.toUpperCase()).toStrictEqual( designTokens.light.shadows.md.value.color, ); @@ -65,7 +65,7 @@ describe('Shadows', () => { }); it('js tokens shadows.size.lg matches figma tokens shadows.lg', () => { - expect(shadows.size.lg.shadowColor).toStrictEqual( + expect(shadows.size.lg.shadowColor.toUpperCase()).toStrictEqual( designTokens.light.shadows.lg.value.color, ); diff --git a/src/js/themes/types.ts b/src/js/themes/types.ts index 91858d58..08e51932 100644 --- a/src/js/themes/types.ts +++ b/src/js/themes/types.ts @@ -102,17 +102,25 @@ export type ThemeColors = { /** * {string} overlay.alternative - For a stronger shading layer option behind modality screens */ - inverse: string; + alternative: string; /** - * {string} overlay.inverse - [DEPRECATED] Should be used for elements over an overlay + * {string} overlay.inverse - For elements used on top of overlay/alternative. Used for text, icon or border */ - alternative: string; + inverse: string; }; shadow: { /** * {string} shadow.default - For neutral shadows */ default: string; + /** + * {string} shadow.primary - For primary shadows + */ + primary: string; + /** + * {string} shadow.error - For error shadows + */ + error: string; }; primary: { /** @@ -139,36 +147,6 @@ export type ThemeColors = { * {string} primary.inverse - For elements used on top of primary/default. (Example: label of primary button, check in a checkbox)disabled state */ inverse: string; - /** - * {string} primary.disabled - [DEPRECATED] Should be used for disabled state - */ - disabled: string; - /** - * {string} primary.shadow - For primary button hover - */ - shadow: string; - }; - secondary: { - /** - * {string} secondary.default - [DEPRECATED] Should be used for any secondary actions. It should not be used for any negative connotations such as warnings or errors as it is quite closely tied to the MetaMask Fox - */ - default: string; - /** - * {string} secondary.alternative - [DEPRECATED] Should be used as an alternative to secondary.default for things such as hover states - */ - alternative: string; - /** - * {string} secondary.muted - [DEPRECATED] It’s a very low contrasting secondary variant for things such as alert backgrounds. secondary.muted and secondary.inverse should not be used together in a foreground and background combination - */ - muted: string; - /** - * {string} secondary.inverse - [DEPRECATED] Should be used only as the foreground element on top of primary/default and primary/alternative. It is intended to be the most contrasting color to primary/default. It should meet all AA and AAA accessibility standards such as the text or icon of a primary button - */ - inverse: string; - /** - * {string} secondary.disabled - [DEPRECATED] Should be used for all disabled secondary action components - */ - disabled: string; }; error: { /** @@ -195,14 +173,6 @@ export type ThemeColors = { * {string} error.inverse - For elements used on top of error/default (Example: label of danger/critical button) */ inverse: string; - /** - * {string} error.disabled - [DEPRECATED] Should be used for disabled state - */ - disabled: string; - /** - * {string} error.shadow - For error danger/critical button hover - */ - shadow: string; }; warning: { /** @@ -217,10 +187,6 @@ export type ThemeColors = { * {string} defaultPressed - For the "pressed" state of interactive elements */ defaultPressed: string; - /** - * {string} warning.alternative - [DEPRECATED] Should be used as an alternative to warning/default for things like hover or pressed states - */ - alternative: string; /** * {string} warning.muted - For lowest contrast background used in warning elements. (Example: notification background) */ @@ -229,10 +195,6 @@ export type ThemeColors = { * {string} warning.inverse - For elements used on top of warning/default. Used for text, icon or border */ inverse: string; - /** - * {string} warning.disabled - [DEPRECATED] Should be used for disabled state - */ - disabled: string; }; success: { /** @@ -247,10 +209,6 @@ export type ThemeColors = { * {string} defaultPressed - For the "pressed" state of interactive elements */ defaultPressed: string; - /** - * {string} success.alternative - [DEPRECATED] Should be used as an alternative to success/default for things like hover or pressed states - */ - alternative: string; /** * {string} success.muted - For lowest contrast background used in success semantic. (Example: notification background) */ @@ -259,20 +217,12 @@ export type ThemeColors = { * {string} success.inverse - For elements used on top of success/default. Used for text, icon or border */ inverse: string; - /** - * {string} success.disabled - [DEPRECATED] Should be used for disabled state - */ - disabled: string; }; info: { /** * {string} info.default - For informational semantic elements. Used for text, background, icon or border */ default: string; - /** - * {string} info.alternative - [DEPRECATED] Should be used as an alternative to info/default for things like hover or pressed states - */ - alternative: string; /** * {string} info.muted - For lowest contrast background used in informational semantic. (Example: notification background) */ @@ -281,42 +231,6 @@ export type ThemeColors = { * {string} info.inverse - For elements used on top of info/default. Used for text, icon or border */ inverse: string; - /** - * {string} info.disabled - [DEPRECATED] Should be used for disabled state - */ - disabled: string; - }; - networks: { - goerli: { - /** - * {string} networks.goerli.default - For goerli test network colored elements - */ - default: string; - /** - * {string} networks.goerli.inverse - For elements used on top of networks/goerli/default - */ - inverse: string; - }; - localhost: { - /** - * {string} networks.localhost.default - For localhost test network colored elements - */ - default: string; - /** - * {string} networks.localhost.inverse - For elements used on top of networks/localhost/default - */ - inverse: string; - }; - sepolia: { - /** - * {string} networks.sepolia.default - For sepolia test network colored elements - */ - default: string; - /** - * {string} networks.sepolia.inverse - For elements used on top of networks/sepolia/default - */ - inverse: string; - }; }; flask: { /**