diff --git a/src/colorModels/hex.ts b/src/colorModels/hex.ts index 779499e..6d925f7 100644 --- a/src/colorModels/hex.ts +++ b/src/colorModels/hex.ts @@ -1,5 +1,6 @@ import { RgbaColor } from "../types"; import { round } from "../helpers"; +import { ALPHA_PRECISION } from "../constants"; import { roundRgba } from "./rgb"; const hexMatcher = /^#([0-9a-f]{3,8})$/i; @@ -17,7 +18,7 @@ export const parseHex = (hex: string): RgbaColor | null => { r: parseInt(hex[0] + hex[0], 16), g: parseInt(hex[1] + hex[1], 16), b: parseInt(hex[2] + hex[2], 16), - a: hex.length === 4 ? round(parseInt(hex[3] + hex[3], 16) / 255, 2) : 1, + a: hex.length === 4 ? round(parseInt(hex[3] + hex[3], 16) / 255, ALPHA_PRECISION) : 1, }; } @@ -26,7 +27,7 @@ export const parseHex = (hex: string): RgbaColor | null => { r: parseInt(hex.substr(0, 2), 16), g: parseInt(hex.substr(2, 2), 16), b: parseInt(hex.substr(4, 2), 16), - a: hex.length === 8 ? round(parseInt(hex.substr(6, 2), 16) / 255, 2) : 1, + a: hex.length === 8 ? round(parseInt(hex.substr(6, 2), 16) / 255, ALPHA_PRECISION) : 1, }; } diff --git a/tests/colord.test.ts b/tests/colord.test.ts index 2df4310..026c2c7 100644 --- a/tests/colord.test.ts +++ b/tests/colord.test.ts @@ -56,7 +56,7 @@ it("Parses modern HSL functional notations", () => { it("Supports HEX4 and HEX8 color models", () => { expect(colord("#ffffffff").toRgb()).toMatchObject({ r: 255, g: 255, b: 255, a: 1 }); - expect(colord("#80808080").toRgb()).toMatchObject({ r: 128, g: 128, b: 128, a: 0.5 }); + expect(colord("#80808080").toRgb()).toMatchObject({ r: 128, g: 128, b: 128, a: 0.502 }); expect(colord("#AAAF").toRgb()).toMatchObject({ r: 170, g: 170, b: 170, a: 1 }); expect(colord("#5550").toRgb()).toMatchObject({ r: 85, g: 85, b: 85, a: 0 }); expect(colord({ r: 255, g: 255, b: 255, a: 1 }).toHex()).toBe("#ffffff"); @@ -64,6 +64,14 @@ it("Supports HEX4 and HEX8 color models", () => { expect(colord({ r: 128, g: 128, b: 128, a: 0 }).toHex()).toBe("#80808000"); }); +it("Round-trips a HEX8 alpha channel without drifting", () => { + // The alpha byte of a HEX8 string is 8-bit; parsing must keep enough + // precision (ALPHA_PRECISION) to re-encode the very same byte. + ["#476d5e55", "#80808080", "#0a141e7f", "#ffffff01", "#000000fe"].forEach((hex) => { + expect(colord(hex).toHex()).toBe(hex); + }); +}); + it("Ignores a case and extra whitespace", () => { expect(colord(" #0a0a0a ").toRgb()).toMatchObject({ r: 10, g: 10, b: 10, a: 1 }); expect(colord("RGB( 10, 10, 10 )").toRgb()).toMatchObject({ r: 10, g: 10, b: 10, a: 1 });