From b815eececbf2a3c90f0f72b57f9a8da8515cc79b Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Wed, 1 Jul 2026 19:35:13 +0200 Subject: [PATCH 1/3] Theme: Restrict seed colors to opaque values --- packages/theme/README.md | 2 +- .../theme/src/color-ramps/lib/color-utils.ts | 22 +++++++++++++------ .../src/color-ramps/test/seed-input.test.ts | 11 ++++++---- packages/theme/src/types.ts | 18 +++++++-------- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/theme/README.md b/packages/theme/README.md index cc24b49c33b71f..a10b0ff0757fe6 100644 --- a/packages/theme/README.md +++ b/packages/theme/README.md @@ -83,7 +83,7 @@ The `color` prop accepts an object with the following optional properties: - `primary`: The primary/accent seed color (default: `'#3858e9'`). - `background`: The background seed color (default: `'#f8f8f8'`). -Both properties accept an sRGB-parseable string: a hex value (e.g. `#3858e9`), an `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Other CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and will throw an error. The theme system automatically generates appropriate color ramps and determines light/dark mode based on these seed colors. +Both properties accept a fully opaque sRGB-parseable string: a hex value (e.g. `#3858e9`), an `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha values, `transparent`, and other CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and will throw an error. The theme system automatically generates appropriate color ramps and determines light/dark mode based on these seed colors. The `cursor` prop accepts an object with the following optional properties: diff --git a/packages/theme/src/color-ramps/lib/color-utils.ts b/packages/theme/src/color-ramps/lib/color-utils.ts index 3dcc5e5369c6d7..b2f0fce2052a3e 100644 --- a/packages/theme/src/color-ramps/lib/color-utils.ts +++ b/packages/theme/src/color-ramps/lib/color-utils.ts @@ -39,8 +39,8 @@ export function getContrast( } /** - * Assert that a seed-color string is sRGB-parseable (hex, `rgb()`/`rgba()`, or - * a CSS named color), throwing otherwise. + * Assert that a seed-color string is sRGB-parseable and fully opaque (hex, + * `rgb()`/`rgba()`, or a CSS named color), throwing otherwise. * * Rejection is deterministic regardless of which `ColorSpace`s are globally * registered: `clampToGamut` registers `OKLCH`, which would otherwise make @@ -48,27 +48,35 @@ export function getContrast( * are still rejected. * * @param seed The seed-color string to validate. - * @throws If `seed` is not an sRGB-parseable string. + * @throws If `seed` is not an sRGB-parseable, fully opaque string. */ export function assertValidSeedColor( seed: string ): void { ALLOWED_SEED_COLOR_SPACES.forEach( ( space ) => ColorSpace.register( space ) ); - let spaceId: string; + let parsedColor: ReturnType< typeof parse >; try { - ( { spaceId } = parse( seed ) ); + parsedColor = parse( seed ); } catch { throw new Error( - `Unsupported seed color "${ seed }": expected a hex value, an \`rgb()\`/\`rgba()\` string, or a CSS named color.` + `Unsupported seed color "${ seed }": expected a fully opaque hex value, an \`rgb()\`/\`rgba()\` string, or a CSS named color.` ); } + const { alpha = 1, spaceId } = parsedColor; + if ( ! ALLOWED_SEED_COLOR_SPACES.some( ( space ) => space.id === spaceId ) ) { throw new Error( - `Unsupported seed color "${ seed }": expected a hex value, an \`rgb()\`/\`rgba()\` string, or a CSS named color, but received a \`${ spaceId }\` color.` + `Unsupported seed color "${ seed }": expected a fully opaque hex value, an \`rgb()\`/\`rgba()\` string, or a CSS named color, but received a \`${ spaceId }\` color.` + ); + } + + if ( alpha !== 1 ) { + throw new Error( + `Unsupported seed color "${ seed }": expected a fully opaque color.` ); } } diff --git a/packages/theme/src/color-ramps/test/seed-input.test.ts b/packages/theme/src/color-ramps/test/seed-input.test.ts index 99c4120bc5eb7c..17d7a9dd4699a0 100644 --- a/packages/theme/src/color-ramps/test/seed-input.test.ts +++ b/packages/theme/src/color-ramps/test/seed-input.test.ts @@ -5,15 +5,18 @@ import { BG_RAMP_CONFIG } from '../lib/ramp-configs'; const ACCEPTED_SEEDS = [ '#3858e9', - '#3858e94d', + '#3858e9ff', 'rgb(56,88,233)', - 'rgb(56 88 233 / 0.3)', - 'rgba(56,88,233,0.3)', + 'rgb(56 88 233 / 1)', + 'rgba(56,88,233,1)', 'blue', - 'transparent', ]; const REJECTED_SEEDS = [ + '#3858e94d', + 'rgb(56 88 233 / 0.3)', + 'rgba(56,88,233,0.3)', + 'transparent', 'oklch(0.7 0.15 250)', 'hsl(230 80% 56%)', 'lab(50% 40 59)', diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index e8107fb8b22451..1920ca5ae1cf13 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -8,22 +8,22 @@ export interface ThemeProviderSettings { */ color?: { /** - * The primary seed color to use for the theme. Accepts an + * The primary seed color to use for the theme. Accepts a fully opaque * sRGB-parseable string: a hex value (e.g. `#3858e9`), an - * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Other - * CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted - * and throw an error. + * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha + * values, `transparent`, and other CSS color spaces (e.g. `hsl()`, + * `oklch()`, `lab()`) are not accepted and throw an error. * * By default, it inherits from parent `ThemeProvider`, * and fallbacks to statically built CSS. */ primary?: string; /** - * The background seed color to use for the theme. Accepts an - * sRGB-parseable string: a hex value (e.g. `#f8f8f8`), an - * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Other - * CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted - * and throw an error. + * The background seed color to use for the theme. Accepts a fully + * opaque sRGB-parseable string: a hex value (e.g. `#f8f8f8`), an + * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha + * values, `transparent`, and other CSS color spaces (e.g. `hsl()`, + * `oklch()`, `lab()`) are not accepted and throw an error. * * By default, it inherits from parent `ThemeProvider`, * and fallbacks to statically built CSS. From 27182c86bc5bc7947ab505914dcf08c9b03d73f9 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Wed, 1 Jul 2026 19:47:12 +0200 Subject: [PATCH 2/3] Theme: Add opaque seed colors changelog --- packages/theme/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 17c7f201da1ea1..929b12d8e52ef4 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -5,6 +5,7 @@ ### Breaking Changes - Rename `--wpds-color-background-thumb-neutral-disabled` to `--wpds-color-background-thumb-neutral-weak-disabled` so the disabled token belongs to the existing neutral weak thumb family ([#79770](https://github.com/WordPress/gutenberg/pull/79770)). +- `ThemeProvider`: reject partially transparent and `transparent` seed colors. `color.primary` and `color.background` now only accept fully opaque seed colors ([#79773](https://github.com/WordPress/gutenberg/pull/79773)). ### Bug Fixes From 05be2c2574954cdda942929bbe355585df3f3cf6 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Thu, 9 Jul 2026 14:04:25 +0200 Subject: [PATCH 3/3] Theme: Clarify opaque seed color docs --- packages/theme/README.md | 2 +- packages/theme/src/types.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/theme/README.md b/packages/theme/README.md index a10b0ff0757fe6..72b2c6ed380da3 100644 --- a/packages/theme/README.md +++ b/packages/theme/README.md @@ -83,7 +83,7 @@ The `color` prop accepts an object with the following optional properties: - `primary`: The primary/accent seed color (default: `'#3858e9'`). - `background`: The background seed color (default: `'#f8f8f8'`). -Both properties accept a fully opaque sRGB-parseable string: a hex value (e.g. `#3858e9`), an `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha values, `transparent`, and other CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and will throw an error. The theme system automatically generates appropriate color ramps and determines light/dark mode based on these seed colors. +Both properties accept a fully opaque sRGB-parseable string: a hex value (e.g. `#3858e9`), an `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Non-opaque alpha values, `transparent`, and other CSS color spaces (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and will throw an error. The theme system automatically generates appropriate color ramps and determines light/dark mode based on these seed colors. The `cursor` prop accepts an object with the following optional properties: diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index 1920ca5ae1cf13..838db3c0c68a3b 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -10,9 +10,10 @@ export interface ThemeProviderSettings { /** * The primary seed color to use for the theme. Accepts a fully opaque * sRGB-parseable string: a hex value (e.g. `#3858e9`), an - * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha - * values, `transparent`, and other CSS color spaces (e.g. `hsl()`, - * `oklch()`, `lab()`) are not accepted and throw an error. + * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). + * Non-opaque alpha values, `transparent`, and other CSS color spaces + * (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and throw an + * error. * * By default, it inherits from parent `ThemeProvider`, * and fallbacks to statically built CSS. @@ -21,9 +22,10 @@ export interface ThemeProviderSettings { /** * The background seed color to use for the theme. Accepts a fully * opaque sRGB-parseable string: a hex value (e.g. `#f8f8f8`), an - * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). Alpha - * values, `transparent`, and other CSS color spaces (e.g. `hsl()`, - * `oklch()`, `lab()`) are not accepted and throw an error. + * `rgb()`/`rgba()` string, or a CSS named color (e.g. `'blue'`). + * Non-opaque alpha values, `transparent`, and other CSS color spaces + * (e.g. `hsl()`, `oklch()`, `lab()`) are not accepted and throw an + * error. * * By default, it inherits from parent `ThemeProvider`, * and fallbacks to statically built CSS.