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

Bug: make string conversion more robust #73

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 0 additions & 3 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,4 @@
.main-content {
min-width: 0;
}
.top-bar {
min-height: 50px !important;
}
</style>
45 changes: 21 additions & 24 deletions src/controls/GetColorsFromString.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,30 @@
import { Color } from "../lib/Color";
import type { ColorWrap } from "../types";
import configStore from "../stores/config-store";
import { wrapInBlankSemantics } from "../lib/utils";
import { wrapInBlankSemantics, processBodyTextToColors } from "../lib/utils";

let state: "idle" | "error" = "idle";
export let onChange: (colors: ColorWrap<Color>[]) => void;
export let colors: ColorWrap<Color>[];
export let colorSpace: string;
let errorMsg = "";

function processBodyInput(body: string) {
try {
const newColors = body
.split(",")
.map((x) => x.replace(/"/g, "").trim())
// remove all parens and brackets
.map((x) => x.replace(/[\(\)\[\]]/g, ""))
.filter((x) => x.length > 0)
.map((x) => Color.colorFromString(x, colorSpace as any))
.map((x, idx) => {
const newColors = processBodyTextToColors(body, colorSpace).map(
(x, idx) => {
if (colors[idx]) {
return { ...colors[idx], color: x };
} else {
return wrapInBlankSemantics(x);
}
});
}
);
onChange(newColors);
state = "idle";
} catch (e) {
console.error(e);
errorMsg = (e as any)?.message;
state = "error";
return;
}
Expand All @@ -38,8 +35,21 @@

<div class="w-full border-t-2 border-black my-2"></div>
<div class="mt-2">
<div class="flex justify-between w-full text-sm">
<label for="current-colors">Current Colors</label>
<div class="flex items-center">
<label for="include-quotes" class="mr-2">Include quotes</label>
<input
type="checkbox"
id="include-quotes"
class="mr-2"
checked={includeQuotes}
on:change={() => configStore.setIncludeQuotes(!includeQuotes)}
/>
</div>
</div>
{#if state === "error"}
<div class="text-red-500">Error parsing colors</div>
<div class="text-red-500">Error parsing colors. {errorMsg}</div>
{/if}
<textarea
id="current-colors"
Expand All @@ -57,19 +67,6 @@
}}
on:change={(e) => processBodyInput(e.currentTarget.value)}
/>
<div class="flex justify-between w-full text-sm">
<label for="current-colors">Current Colors</label>
<div class="flex items-center">
<label for="include-quotes" class="mr-2">Include quotes</label>
<input
type="checkbox"
id="include-quotes"
class="mr-2"
checked={includeQuotes}
on:change={() => configStore.setIncludeQuotes(!includeQuotes)}
/>
</div>
</div>
</div>

<style>
Expand Down
18 changes: 10 additions & 8 deletions src/controls/NewPal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import type { StringPalette, Palette } from "../types";

import { processBodyTextToColors } from "../lib/utils";
import { buttonStyle, denseButtonStyle } from "../lib/styles";
import Tooltip from "../components/Tooltip.svelte";
import {
Expand All @@ -21,23 +22,24 @@
const color = Color.colorFromString(x.color, colorSpace);
return wrapInBlankSemantics(color);
});
const background = Color.colorFromString(newPal.background, colorSpace);
console.log(background.toHex(), newPal.background);
const pal = {
...newPal,
colors,
background: Color.colorFromString(newPal.background, colorSpace),
background,
colorSpace,
} as Palette;
colorStore.createNewPal(pal);
}

let inputString = "";
function processBodyInput(body: string) {
if (body.length === 0) {
return;
}
try {
const newColors = body
.split(",")
.map((x) => x.replace(/"/g, "").trim())
.filter((x) => x.length > 0)
.map((x) => Color.colorFromString(x, colorSpace as any));
const newColors = processBodyTextToColors(body, colorSpace as any);
newPal(createPalFromHexes(newColors.map((x) => x.toHex())));
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -103,12 +105,12 @@
on:keydown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
processBodyInput(e.currentTarget.value);
e.currentTarget.blur();
}
}}
on:change={(e) => {
on:blur={(e) => {
processBodyInput(e.currentTarget.value);
inputString = "";
}}
/>
<div class="mt-5 border-t-2 border-black"></div>
Expand Down
1 change: 0 additions & 1 deletion src/example/ExampleAlaCarte.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
{paletteIdx}
hideHeader={true}
allowInteraction={allowModification}
bg={bgColor}
/>
{:else}
{#if example.svg}
Expand Down
5 changes: 1 addition & 4 deletions src/example/Examples.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,7 @@
style={`height: calc(100% - 100px)`}
>
{#if $configStore.exampleRoute === "swatches"}
<Swatches
paletteIdx={$colorStore.currentPal}
bg={currentPal.background.toString()}
/>
<Swatches paletteIdx={$colorStore.currentPal} />
{/if}
{#each examples as example, idx}
{#if exampleShowMap[idx]}
Expand Down
1 change: 0 additions & 1 deletion src/example/Swatches.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
export let paletteIdx: number;
export let allowInteraction: boolean = true;
export let hideHeader: boolean = false;
export let bg: string;

$: currentPal = $colorStore.palettes[paletteIdx];
$: colors = currentPal?.colors || [];
Expand Down
37 changes: 15 additions & 22 deletions src/lib/Color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class Color {
if (hexCache.has(str)) {
return hexCache.get(str) as string;
}

const newHex = this.toColorIO().to("srgb").toString({ format: "hex" });
hexCache.set(str, newHex);
return newHex;
Expand Down Expand Up @@ -73,21 +74,6 @@ export class Color {
const result = this.toColorIO().inGamut("srgb");
this.cachedInGamut = result;
return result;

// // return new ColorIO(this.spaceName, this.toChannels()).inGamut();
// let clr = this.toColorIO().to("srgb", { inGamut: false });
// let cssColor = clr.display();
// // cssColor.color.inGamut();
// return cssColor.color.inGamut();

// const x = this.toHex();
// const y = this.toColorIO().to("srgb").toString({ format: "hex" });
// if (x !== y) {
// console.log("x", x, "y", y);
// }
// const result = x === y;
// this.cachedInGamut = result;
// return result;
}
toColorIO(): ColorIO {
if (this.cachedColorIO) {
Expand All @@ -103,9 +89,10 @@ export class Color {
}
}

fromString(colorString: string): Color {
if (stringChannelsCache.has(colorString)) {
return this.fromChannels(stringChannelsCache.get(colorString)!);
fromString(colorString: string, allowError?: boolean): Color {
let key = `${colorString}-${this.spaceName}`;
if (stringChannelsCache.has(key)) {
return this.fromChannels(stringChannelsCache.get(key)!);
}
// const isTargetSpace = colorString.startsWith(`${this.spaceName}(`);
// const isHex = colorString.startsWith("#");
Expand All @@ -120,11 +107,13 @@ export class Color {
try {
channels = new ColorIO(`#${colorString}`).to(this.spaceName).coords;
} catch (e) {
console.log("error", e, colorString);
if (allowError) {
throw new Error("Invalid color string: " + colorString);
}
channels = [0, 0, 0];
}
}
stringChannelsCache.set(colorString, channels);
stringChannelsCache.set(key, channels.map((x) => Number(x)) as Channels);
return this.fromChannels(channels);
}
fromChannels(channels: Channels): Color {
Expand Down Expand Up @@ -445,9 +434,13 @@ class CAM16 extends Color {

function colorFromString(
colorString: string,
colorSpace: keyof typeof colorDirectory = "lab"
colorSpace: keyof typeof colorDirectory = "lab",
allowError?: boolean
): Color {
const result = new colorDirectory[colorSpace]().fromString(colorString);
const result = new colorDirectory[colorSpace]().fromString(
colorString,
allowError
);
return result;
}

Expand Down
95 changes: 95 additions & 0 deletions src/lib/Utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { expect, test } from "vitest";
import { processBodyTextToColors } from "./utils";

const reactVisColors = `
'#19CDD7',
'#DDB27C',
'#88572C',
'#FF991F',
'#F15C17',
'#223F9A',
'#DA70BF',
'#125C77',
'#4DC19C',
'#776E57',
'#12939A',
'#17B8BE',
'#F6D18A',
'#B7885E',
'#FFCB99',
'#F89570',
'#829AE3',
'#E79FD5',
'#1E96BE',
'#89DAC1',
'#B3AD9E'
`;
const resultColors = [
"#19CDD7",
"#DDB27C",
"#88572C",
"#FF991F",
"#F15C17",
"#223F9A",
"#DA70BF",
"#125C77",
"#4DC19C",
"#776E57",
"#12939A",
"#17B8BE",
"#F6D18A",
"#B7885E",
"#FFCB99",
"#F89570",
"#829AE3",
"#E79FD5",
"#1E96BE",
"#89DAC1",
"#B3AD9E",
];
const rvColorsShort = `
[
'#12939A',
'#79C7E3',
'#1A3177',
'#FF9833',
'#EF5D28'
]
`;
// color spaces
const spaces = [
"lab",
"hsl",
//
"lch",
"hsv",
];
test("processBodyTextToColors", async () => {
spaces.forEach((space) => {
console.log(space);
const result1 = processBodyTextToColors(reactVisColors, space);
expect(
result1.map((x) => x.toHex().toUpperCase()),
`Large rv colors in ${space} space should match`
).toEqual(resultColors);

const result2 = processBodyTextToColors(rvColorsShort, space);
expect(
result2.map((x) => x.toHex().toUpperCase()),
`Short rv colors in ${space} space should match`
).toEqual(["#12939A", "#79C7E3", "#1A3177", "#FF9833", "#EF5D28"]);
});
});

test("processBodyTextToColors: zoom in", async () => {
spaces.forEach((space) => {
resultColors.forEach((color) => {
expect(
processBodyTextToColors(` '${color}'`, space).map((x) =>
x.toHex().toUpperCase()
),
`Single color (${color}) in ${space} space should match`
).toEqual([color]);
});
});
});
16 changes: 16 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,3 +759,19 @@ export function splitMessageIntoTextAndColors(message: string): ParseBlock[] {

return output;
}

export function processBodyTextToColors(body: string, colorSpace: string) {
return body
.split(",")
.map((x) =>
x
// remove all quotes
.replace(/"/g, "")
.replace(/'/g, "")
// remove all parens and brackets
.replace(/[\(\)\[\]]/g, "")
.trim()
)
.filter((x) => x.length > 0)
.map((x) => Color.colorFromString(x, colorSpace as any, true));
}
Loading