From daed101714d4aebc1eb848767a83ea1bc47bf9b3 Mon Sep 17 00:00:00 2001
From: James Stuckey Weber
Date: Tue, 15 Aug 2023 10:49:14 -0400
Subject: [PATCH 1/6] Compute contrast based on premultipled fg
---
src/lib/components/colors/Header.svelte | 21 +++++++++++++++++++++
src/lib/components/colors/index.svelte | 11 ++++++++---
src/lib/components/ratio/index.svelte | 14 ++++++++++----
src/lib/stores.ts | 5 ++++-
src/lib/utils.ts | 20 +++++++++++++++++++-
5 files changed, 62 insertions(+), 9 deletions(-)
diff --git a/src/lib/components/colors/Header.svelte b/src/lib/components/colors/Header.svelte
index 7e339c1b..04882063 100644
--- a/src/lib/components/colors/Header.svelte
+++ b/src/lib/components/colors/Header.svelte
@@ -9,12 +9,16 @@
export let type: 'bg' | 'fg';
export let color: Writable;
export let format: ColorFormatId;
+ export let premultipliedFg: PlainColorObject | null;
$: targetSpace = getSpaceFromFormatId(format);
$: display = serialize($color, { inGamut: false, format });
$: displayType = type === 'bg' ? 'Background' : 'Foreground';
$: editing = false;
$: inputValue = '';
+ $: displayPremultipliedFg = premultipliedFg
+ ? serialize(premultipliedFg, { inGamut: false, format })
+ : '';
let hasError = false;
// When not editing, sync input value with color (e.g. when sliders change)
@@ -89,6 +93,15 @@
{#if hasError}
Could not parse input as a valid color.
{/if}
+ {#if premultipliedFg}
+
+ {displayPremultipliedFg}
+
+
+ {/if}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index f6abef9f..1ebb089a 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -7,10 +7,6 @@ import { FORMATS } from '$lib/constants';
export const getSpaceFromFormatId = (formatId: ColorFormatId) =>
formatId === 'hex' ? 'srgb' : formatId;
-// hsl should be mixed in the srgb space for a more uniform hue gradient
-export const getMixSpaceFromFormatId = (formatId: ColorFormatId) =>
- ['hex', 'hsl'].includes(formatId) ? 'srgb' : formatId;
-
export const sliderGradient = (
color: PlainColorObject,
channel: string,
@@ -102,9 +98,11 @@ export const premultiplyFG = ([fg, bg, format]: [
bgNoAlpha.alpha = 1;
const fgNoAlpha = clone(fg);
fgNoAlpha.alpha = 1;
- const space = getMixSpaceFromFormatId(format);
+
return mix(fgNoAlpha, bgNoAlpha, 1 - fg.alpha, {
- space,
- outputSpace: space,
+ // We always mix in srgb, as we are approximating the color as it will be
+ // displayed on a monitor.
+ space: 'srgb',
+ outputSpace: format,
});
};
From 797229dfcc1ccfe4ff463692a45cbbc525e7a0c1 Mon Sep 17 00:00:00 2001
From: James Stuckey Weber
Date: Thu, 17 Aug 2023 13:56:14 -0400
Subject: [PATCH 4/6] Handle hex
---
src/lib/utils.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 1ebb089a..0efff719 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -103,6 +103,6 @@ export const premultiplyFG = ([fg, bg, format]: [
// We always mix in srgb, as we are approximating the color as it will be
// displayed on a monitor.
space: 'srgb',
- outputSpace: format,
+ outputSpace: getSpaceFromFormatId(format),
});
};
From b5ffa4da28b5b98426de636e63d5d88601c0dd95 Mon Sep 17 00:00:00 2001
From: James Stuckey Weber
Date: Thu, 17 Aug 2023 15:47:46 -0400
Subject: [PATCH 5/6] Add approximate message, hide premultiplied colors when
no alpha
---
src/lib/components/ratio/index.svelte | 17 +++++++++++------
src/lib/utils.ts | 1 +
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/src/lib/components/ratio/index.svelte b/src/lib/components/ratio/index.svelte
index 5878fe85..e1ae704b 100644
--- a/src/lib/components/ratio/index.svelte
+++ b/src/lib/components/ratio/index.svelte
@@ -11,7 +11,8 @@
$: {
const bgNoAlpha = clone($bg);
bgNoAlpha.alpha = 1;
- ratio = contrast(bgNoAlpha, $premultipliedFg, 'WCAG21');
+
+ ratio = contrast(bgNoAlpha, $premultipliedFg || $fg, 'WCAG21');
}
$: displayRatio = Math.round((ratio + Number.EPSILON) * 100) / 100;
$: pass = ratio >= RATIOS.AA.Large;
@@ -35,12 +36,16 @@
-
-
With alpha
-
- Alpha premultipled
+ {#if $premultipliedFg}
+ Because WCAG 2 doesn't account for alpha, this is approximated by
+ premultiplying the foreground color in the sRGB space.
+
+
With alpha
+
+ Alpha premultipled
+
-
+ {/if}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 0efff719..471f640f 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -94,6 +94,7 @@ export const premultiplyFG = ([fg, bg, format]: [
bg: PlainColorObject,
format: ColorFormatId,
]) => {
+ if (fg.alpha === 1) return;
const bgNoAlpha = clone(bg);
bgNoAlpha.alpha = 1;
const fgNoAlpha = clone(fg);
From 84d573bed39b4a5305f43c51cfca0e9510136f09 Mon Sep 17 00:00:00 2001
From: James Stuckey Weber
Date: Thu, 17 Aug 2023 15:53:26 -0400
Subject: [PATCH 6/6] Fix tests
---
test/js/lib/components/colors/Header.spec.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/js/lib/components/colors/Header.spec.ts b/test/js/lib/components/colors/Header.spec.ts
index 7849c24f..3dc428e8 100644
--- a/test/js/lib/components/colors/Header.spec.ts
+++ b/test/js/lib/components/colors/Header.spec.ts
@@ -11,6 +11,7 @@ describe('Header', () => {
const { getByLabelText } = render(Header, {
type: 'bg',
color,
+ premultipliedFg: HSL_WHITE,
format: 'hsl',
});
const input = getByLabelText('Background Color');
@@ -31,6 +32,7 @@ describe('Header', () => {
const { getByText, getByLabelText } = render(Header, {
type: 'fg',
color,
+ premultipliedFg: HSL_WHITE,
format: 'hsl',
});
const input = getByLabelText('Foreground Color');
@@ -55,6 +57,7 @@ describe('Header', () => {
const { getByText, getByLabelText } = render(Header, {
type: 'fg',
color,
+ premultipliedFg: HSL_WHITE,
format: 'hsl',
});
const input = getByLabelText('Foreground Color');
@@ -78,6 +81,7 @@ describe('Header', () => {
const { getByLabelText } = render(Header, {
type: 'fg',
color,
+ premultipliedFg: HSL_WHITE,
format: 'hsl',
});
const input = getByLabelText('Foreground Color');