Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group formats #137

Merged
merged 20 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/lib/components/colors/FormatGroup.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts">
import { inGamut } from 'colorjs.io/fn';
import type { PlainColorObject } from 'colorjs.io/types/src/color';

import Output from '$lib/components/colors/Output.svelte';
import type { FormatGroup } from '$lib/constants';
import { ColorSpace } from '$lib/stores';
import { getSpaceFromFormatId } from '$lib/utils';

import ExternalLink from '../util/ExternalLink.svelte';

export let type: 'bg' | 'fg';
export let color: PlainColorObject;
export let formatGroup: FormatGroup;

function inGamutForSpace(color: PlainColorObject) {
if (!formatGroup.gamutFormat) return true;
const gamutSpace = ColorSpace.get(
getSpaceFromFormatId(formatGroup.gamutFormat),
);
return inGamut(color, gamutSpace);
}
$: isInGamut = inGamutForSpace(color);
</script>

<div data-content="format-group">
<h5>{formatGroup.name}</h5>
{#if !isInGamut}
<span data-color-info="warning"
>Selected color is <ExternalLink
href="https://www.w3.org/TR/css-color-4/#out-of-gamut"
>outside the {formatGroup.gamutName} gamut.</ExternalLink
></span
>
{/if}
{#each formatGroup.formats as format (format)}
<Output {type} {color} {format} />
{/each}
</div>

<style lang="scss">
[data-color-info='warning'] {
grid-area: message;
}
</style>
28 changes: 22 additions & 6 deletions src/lib/components/colors/Formats.svelte
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
<script lang="ts">
import type { PlainColorObject } from 'colorjs.io/types/src/color';

import Output from '$lib/components/colors/Output.svelte';
import type { ColorFormatId } from '$lib/constants';
import { FORMATS } from '$lib/constants';
import FormatGroup from '$lib/components/colors/FormatGroup.svelte';
import type {
ColorFormatId,
FormatGroup as FormatGroupType,
} from '$lib/constants';
import { FORMAT_GROUPS } from '$lib/constants';

export let type: 'bg' | 'fg';
export let color: PlainColorObject;
export let format: ColorFormatId;

function otherFormatGroups(
selectedFormat: ColorFormatId,
): typeof FORMAT_GROUPS {
const otherFormats: FormatGroupType[] = [];
FORMAT_GROUPS.forEach((group) => {
const groupFormats = group.formats.filter((s) => s !== selectedFormat);
if (groupFormats.length) {
otherFormats.push({ ...group, formats: groupFormats });
}
});
return otherFormats;
}

$: displayType = type === 'bg' ? 'Background' : 'Foreground';
$: otherFormats = FORMATS.filter((s) => s !== format);
$: otherFormats = otherFormatGroups(format);
</script>

<div data-content="formats" data-column="tool">
<h4 class="small-only label">{displayType} Color</h4>
{#each otherFormats as format (format)}
<Output {type} {color} {format} />
{#each otherFormats as formatGroup}
<FormatGroup {type} {color} {formatGroup} />
{/each}
</div>

Expand Down
14 changes: 2 additions & 12 deletions src/lib/components/colors/Output.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { inGamut, serialize, to } from 'colorjs.io/fn';
import { serialize, to } from 'colorjs.io/fn';
import type { PlainColorObject } from 'colorjs.io/types/src/color';

import SupportWarning from '$lib/components/colors/SupportWarning.svelte';
Expand All @@ -13,23 +13,17 @@

$: targetSpace = getSpaceFromFormatId(format);
$: targetColor = to(color, targetSpace);
$: isInGamut = inGamut(targetColor);
$: targetColorValue = serialize(targetColor, {
format,
inGamut: false,
});
</script>

<ul data-group="output {type}">
<li>
<li data-testid={`format-${format}`}>
<CopyButton text={targetColorValue} />
<span data-color-info="value">{targetColorValue}</span>
<SupportWarning {format} />
{#if !isInGamut}
<span data-color-info="warning"
>This color is outside the {targetColor.space.name} gamut.</span
>
{/if}
</li>
</ul>

Expand All @@ -45,8 +39,4 @@
[data-color-info='value'] {
grid-area: color;
}

[data-color-info='warning'] {
grid-area: message;
}
</style>
23 changes: 23 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ export const FORMATS: ColorFormatId[] = [
'srgb',
];

export type FormatGroup = {
name: string;
formats: ColorFormatId[];
gamutFormat?: ColorFormatId;
gamutName?: string;
};

export const FORMAT_GROUPS: FormatGroup[] = [
{
name: 'sRGB Formats',
formats: ['hex', 'hsl', 'srgb'],
gamutFormat: 'srgb',
gamutName: 'sRGB',
},
{ name: 'Unbounded Spaces', formats: ['lab', 'lch', 'oklab', 'oklch'] },
{
name: 'Display p3 Space',
formats: ['p3'],
gamutFormat: 'p3',
gamutName: 'p3',
jgerigmeyer marked this conversation as resolved.
Show resolved Hide resolved
},
];

export const RATIOS = {
AA: {
Normal: 4.5,
Expand Down
6 changes: 6 additions & 0 deletions test/js/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ export const HSL_BLACK: PlainColorObject = {
};

export const HSL_WHITE_SERIALIZED = serialize(HSL_WHITE, { inGamut: false });

export const OUT_OF_BOUNDED_GAMUTS: PlainColorObject = {
space: ColorSpace.get('oklch'),
coords: [1, 1, 1],
alpha: 1,
};
36 changes: 36 additions & 0 deletions test/js/lib/components/colors/FormatGroup.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { render } from '@testing-library/svelte';

import FormatGroup from '$lib/components/colors/FormatGroup.svelte';
import { FORMAT_GROUPS } from '$src/lib/constants';
import { HSL_WHITE, OUT_OF_BOUNDED_GAMUTS } from '$test/fixtures';

describe('FormatGroup', () => {
it('renders selected group', () => {
const FORMAT_GROUP = FORMAT_GROUPS[0]!;
const { getByTestId, getByText } = render(FormatGroup, {
type: 'bg',
color: HSL_WHITE,
formatGroup: FORMAT_GROUP,
});

expect(getByText(FORMAT_GROUP.name)).toBeVisible();
FORMAT_GROUP.formats.forEach((format) => {
expect(getByTestId(`format-${format}`)).toBeVisible();
});
});

it('renders warning if out of gamut', () => {
const FORMAT_GROUP = FORMAT_GROUPS[0]!;
const { getByTestId, getByText } = render(FormatGroup, {
type: 'bg',
color: OUT_OF_BOUNDED_GAMUTS,
formatGroup: FORMAT_GROUP,
});

expect(getByText(FORMAT_GROUP.name)).toBeVisible();
FORMAT_GROUP.formats.forEach((format) => {
expect(getByTestId(`format-${format}`)).toBeVisible();
});
expect(getByText('outside the sRGB gamut.')).toBeVisible();
});
});
17 changes: 0 additions & 17 deletions test/js/lib/components/colors/Output.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { render } from '@testing-library/svelte';
import { serialize, to } from 'colorjs.io/fn';
import type { PlainColorObject } from 'colorjs.io/types/src/color';

import Output from '$lib/components/colors/Output.svelte';
import { ColorSpace } from '$lib/stores';
import { HSL_WHITE, HSL_WHITE_SERIALIZED } from '$test/fixtures';

describe('Output', () => {
Expand All @@ -28,19 +26,4 @@ describe('Output', () => {
getByText(serialize(to(HSL_WHITE, 'oklch'), { inGamut: false })),
).toBeVisible();
});

it('renders warning if out of gamut', () => {
const color: PlainColorObject = {
space: ColorSpace.get('oklch'),
coords: [0.01, 0.02, 0],
alpha: 1,
};
const { getByText } = render(Output, {
type: 'fg',
color,
format: 'hsl',
});

expect(getByText('outside the HSL gamut', { exact: false })).toBeVisible();
});
});