Skip to content

Commit

Permalink
Merge pull request #137 from oddbird/group-formats
Browse files Browse the repository at this point in the history
Group formats
  • Loading branch information
jgerigmeyer authored Dec 19, 2023
2 parents 486e84c + 8b130b1 commit 9aeef3d
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 58 deletions.
57 changes: 57 additions & 0 deletions src/lib/components/colors/FormatGroup.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<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">
<div class="format-group-heading">
<h2 class="label section-heading">{formatGroup.name}</h2>
{#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}
</div>
{#each formatGroup.formats as format (format)}
<Output {type} {color} {format} />
{/each}
</div>

<style lang="scss">
[data-content~='format-group'] {
--heading-transform: none;
margin-block-end: var(--double-gutter);
}
.format-group-heading {
align-items: baseline;
display: flex;
flex-wrap: wrap;
gap: var(--shim);
margin-block-end: var(--gutter);
}
</style>
36 changes: 26 additions & 10 deletions src/lib/components/colors/Formats.svelte
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
<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} />
<h2 class="small-only label">{displayType} Color</h2>
{#each otherFormats as formatGroup}
<FormatGroup {type} {color} {formatGroup} />
{/each}
</div>

<style lang="scss">
[data-content~='formats'] {
margin-bottom: var(--double-gutter);
margin-block-end: var(--double-gutter);
}
.label {
--label-margin-bottom: var(--gutter);
.small-only {
--label-margin-block-end: var(--gutter);
}
</style>
2 changes: 1 addition & 1 deletion src/lib/components/colors/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
}
[data-label] {
--label-margin-bottom: var(--half-shim);
--label-margin-block-end: var(--half-shim);
grid-area: label;
}
Expand Down
26 changes: 7 additions & 19 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,40 +13,28 @@
$: 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>

<style lang="scss">
[data-group~='output'] {
grid-column: 1 / -1;
}
li {
column-gap: 1ch;
display: grid;
grid-template:
'copy color' auto
'copy message' 3ex / auto 1fr;
}
[data-color-info='value'] {
grid-area: color;
}
[data-color-info='warning'] {
grid-area: message;
grid-template-columns: auto 1fr;
}
</style>
2 changes: 1 addition & 1 deletion src/lib/components/colors/Sliders.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
}
[data-group~='sliders'] {
--label-margin-bottom: var(--half-shim);
--label-margin-block-end: var(--half-shim);
margin-bottom: var(--triple-gutter);
}
Expand Down
1 change: 0 additions & 1 deletion src/lib/components/colors/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
<Sliders type="fg" color={fg} format={$format} />
</form>

<h3 class="label section-heading">Additional Formats</h3>
<div data-layout="split">
<Formats type="bg" color={$bg} format={$format} />
<Formats type="fg" color={$fg} format={$format} />
Expand Down
11 changes: 7 additions & 4 deletions src/lib/components/ratio/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</div>

<div class="contrast-defined">
<h4 class="label">AA Contrast Ratio</h4>
<h3 class="label">AA Contrast Ratio</h3>

<dl>
<dt><strong>{RATIOS.AA.Normal}</strong> : 1</dt>
Expand All @@ -47,7 +47,7 @@
<dd>Large Text</dd>
</dl>

<h4 class="label">AAA Contrast Ratio</h4>
<h3 class="label">AAA Contrast Ratio</h3>
<dl>
<dt><strong>{RATIOS.AAA.Normal}</strong> : 1</dt>
<dd>Normal Text</dd>
Expand All @@ -56,7 +56,7 @@
<dd>Large Text</dd>
</dl>

<h4 class="label">Large Text Size</h4>
<h3 class="label">Large Text Size</h3>
<dl>
<dt><strong>≥ 24px</strong></dt>
<dd>Regular Weight</dd>
Expand Down Expand Up @@ -135,8 +135,11 @@
align-items: start;
display: inline-flex;
grid-area: number;
justify-content: flex-end;
line-height: 0.7; // weird number alignment
@include config.between('sm-column-break', 'lg-page-break') {
justify-content: flex-end;
}
}
.result-ratio-number {
Expand Down
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',
},
];

export const RATIOS = {
AA: {
Normal: 4.5,
Expand Down
7 changes: 2 additions & 5 deletions src/sass/initial/_type.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@

h1,
h2,
h3,
h4 {
h3 {
font-weight: normal;
margin: 0;
}
Expand All @@ -42,15 +41,13 @@ h4 {
display: block;
font-size: var(--heading-size, var(--label-size));
letter-spacing: var(--heading-letterspacing, 0.05rem);
margin-bottom: var(--label-margin-bottom, 0);
margin-block-end: var(--label-margin-block-end, 0);
text-transform: var(--heading-transform, uppercase);
}

.section-heading {
@include heading;

--label-margin-bottom: var(--gutter-plus);

@include config.below('sm-page-break') {
--heading-size: var(--medium);
}
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();
});
});

0 comments on commit 9aeef3d

Please sign in to comment.