feat: release Colour Tools 0.1.0

This commit is contained in:
2026-08-31 21:21:35 +02:00
commit 0c1fc94b58
100 changed files with 17406 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
import { fireEvent, render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { CompositeLab } from "../../src/components/CompositeLab";
import { ConverterLab } from "../../src/components/ConverterLab";
import { PickerLab } from "../../src/components/PickerLab";
import { Workbench } from "../../src/components/Workbench";
describe("colour workbench", () => {
beforeEach(() => {
localStorage.clear();
history.replaceState(null, "", "/");
});
it("exposes all seven workspaces as accessible tabs", () => {
render(<Workbench />);
const tabs = screen.getAllByRole("tab");
expect(tabs).toHaveLength(7);
expect(tabs[0]).toHaveAttribute("aria-selected", "true");
expect(
screen.getByRole("heading", { name: "Convert colours" }),
).toBeVisible();
});
it("supports keyboard navigation between workspaces", async () => {
render(<Workbench />);
const convert = screen.getByRole("tab", { name: /Convert/ });
convert.focus();
await userEvent.keyboard("{ArrowRight}");
expect(screen.getByRole("tab", { name: /Composite/ })).toHaveAttribute(
"aria-selected",
"true",
);
expect(
screen.getByRole("heading", { name: "Composite translucent colours" }),
).toBeVisible();
});
});
describe("interactive colour labs", () => {
it("keeps the last valid conversion visible while an input is incomplete", async () => {
render(<ConverterLab onAddColour={vi.fn()} />);
const source = screen.getByLabelText("Colour");
await userEvent.clear(source);
await userEvent.type(source, "oklch(");
expect(source).toHaveAttribute("aria-invalid", "true");
expect(screen.getByText(/Keeping the last valid conversion/)).toBeVisible();
expect(screen.getByText("HEX + alpha")).toBeVisible();
});
it("produces an opaque composite over the enabled matte", () => {
render(<CompositeLab onAddColour={vi.fn()} />);
const result = screen.getByText("Result").closest("aside");
expect(result).not.toBeNull();
expect(within(result!).getByText(/^#[0-9a-f]{6}$/i)).toBeVisible();
expect(screen.getByText(/Produces an opaque RGB result/)).toBeVisible();
});
it("keeps the exact picker field in sync with visual controls", () => {
render(<PickerLab onAddColour={vi.fn()} />);
const hue = screen.getByLabelText(/Hue ·/);
fireEvent.change(hue, { target: { value: "0" } });
expect(screen.getByLabelText("Exact CSS colour")).toHaveValue("#d14f4f");
expect(screen.getByText("#d14f4f")).toBeVisible();
});
});