Skip to content

Commit

Permalink
made changes, just trying to pass tests
Browse files Browse the repository at this point in the history
  • Loading branch information
landonwjohnson committed Jul 18, 2024
1 parent 1ff43b9 commit 1ad0723
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 80 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@
</a>
<br/>

<a href="https://bit.ly/landonwjohnson-on-twitter">
<img src="https://wakatime.com/badge/user/bd50b6c5-e0ca-4937-83b3-ab2d13adbc73/project/018d49ad-1c41-4ee7-9a6b-5387db501fcb.svg" alt="Wakatime stats for utils">
</a>

[![wakatime](https://wakatime.com/badge/user/bd50b6c5-e0ca-4937-83b3-ab2d13adbc73/project/02037e5a-4e97-4cd5-872c-df41ad2d6b67.svg)](https://wakatime.com/badge/user/bd50b6c5-e0ca-4937-83b3-ab2d13adbc73/project/02037e5a-4e97-4cd5-872c-df41ad2d6b67)
<br/>


Expand Down
33 changes: 31 additions & 2 deletions src/__tests__/hexToDecimals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ describe('hexesToDecimals', () => {

test('converts hex values to decimal values without alpha', () => {
const hexObj: RgbWithAHexObject = { r: 'ff', g: '00', b: '00' };
const expected: HexDecimalObject = { r: 255, g: 0, b: 0 };
const expected: HexDecimalObject = { r: 255, g: 0, b: 0, a: 1 };
expect(hexesToDecimals(hexObj)).toEqual(expected);
});

test('handles case when alpha value is not provided', () => {
const hexObj: RgbWithAHexObject = { r: 'ff', g: 'ff', b: 'ff' };
const expected: HexDecimalObject = { r: 255, g: 255, b: 255 };
const expected: HexDecimalObject = { r: 255, g: 255, b: 255, a: 1 };
expect(hexesToDecimals(hexObj)).toEqual(expected);
});

Expand All @@ -36,4 +36,33 @@ describe('hexesToDecimals', () => {
const expected: HexDecimalObject = { r: 255, g: 255, b: 255, a: 1.0 };
expect(hexesToDecimals(hexObj)).toEqual(expected);
});

test('parses and converts hex string to decimal values', () => {
const hexString = '#ff000080';
const expected: HexDecimalObject = { r: 255, g: 0, b: 0, a: 0.5 };
expect(hexesToDecimals(hexString)).toEqual(expected);
});

test('parses and converts hex string without alpha to decimal values', () => {
const hexString = '#ff0000';
const expected: HexDecimalObject = { r: 255, g: 0, b: 0, a: 1 };
expect(hexesToDecimals(hexString)).toEqual(expected);
});

test('handles invalid hex string gracefully', () => {
const hexString = '#gggggg';
expect(() => hexesToDecimals(hexString)).toThrow('Invalid hex color');
});

test('handles short hex string format', () => {
const hexString = '#f00';
const expected: HexDecimalObject = { r: 255, g: 0, b: 0, a: 1 };
expect(hexesToDecimals(hexString)).toEqual(expected);
});

test('handles short hex string with alpha format', () => {
const hexString = '#f008';
const expected: HexDecimalObject = { r: 255, g: 0, b: 0, a: 0.53 };
expect(hexesToDecimals(hexString)).toEqual(expected);
});
});
67 changes: 53 additions & 14 deletions src/hexToDecimals.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HexObject } from './parseHex';
import { isObject, isString } from '@devlander/utils';
import { HexObject, parseHex } from './parseHex';
import { HexDecimalObject } from './types/hex-decimal-object.interface';

/**
Expand All @@ -16,37 +17,75 @@ export const hexToDecimal = (hex: string): number => {
return parseInt(hex, 16);
};

export interface RgbWithAHexObject extends Partial<HexObject >{
r: string
g: string,
b: string,
a?: string
export interface RgbWithAHexObject extends Partial<HexObject> {
r: string;
g: string;
b: string;
a?: string;
}

type ParamsForHexesToDecimals = string | RgbWithAHexObject;

/**
* Converts a HexObject to a HexDecimalObject by converting each hex value to its decimal equivalent.
* If the alpha (a) value is not provided, it returns an object without the alpha value.
* Converts a HexObject or hex string to a HexDecimalObject by converting each hex value to its decimal equivalent.
* If the alpha (a) value is not provided, it defaults to 1.
*
* @param hexObj - The object containing hex values for r, g, b, and optionally a.
* @param params - The object containing hex values for r, g, b, and optionally a, or a hex string.
* @returns An object containing decimal values for r, g, b, and optionally a.
*
* @example
* ```typescript
* const hexObj = { r: 'ff', g: '00', b: '00', a: '80' };
* console.log(hexesToDecimals(hexObj)); // { r: 255, g: 0, b: 0, a: 0.5 }
*
* const hexObjWithoutA = { r: 'ff', g: '00', b: '00' };
* console.log(hexesToDecimals(hexObjWithoutA)); // { r: 255, g: 0, b: 0 }
* const hexString = '#ff000080';
* console.log(hexesToDecimals(hexString)); // { r: 255, g: 0, b: 0, a: 0.5 }
*
* const shortHexString = '#f008';
* console.log(hexesToDecimals(shortHexString)); // { r: 255, g: 0, b: 0, a: 0.53 }
* ```
*/
export const hexesToDecimals = ({ r, g, b, a }: RgbWithAHexObject): HexDecimalObject => {
export const hexesToDecimals = (params: ParamsForHexesToDecimals): HexDecimalObject => {
let hexObject: RgbWithAHexObject;

if (isObject(params) && !isString(params)) {
hexObject = {
r: params.r,
g: params.g,
b: params.b,
a: "a" in params ? params.a : 'ff'
};
} else {
hexObject = parseHex(params as string);
}

const { r, g, b, a } = hexObject;
const result: HexDecimalObject = {
r: hexToDecimal(r),
g: hexToDecimal(g),
b: hexToDecimal(b),
};
if (a !== undefined) {

if (a !== undefined && a !== 'ff') {
result.a = +(hexToDecimal(a) / 255).toFixed(2);
} else {
result.a = 1;
}
return result;

return validateHexDecimalObject(result);
};

/**
* Validates a HexDecimalObject by checking for NaN values and changing them to 1.
* @param obj - The HexDecimalObject to validate.
* @returns The validated HexDecimalObject.
*/
const validateHexDecimalObject = (obj: HexDecimalObject): HexDecimalObject => {
const keys: (keyof HexDecimalObject)[] = ['r', 'g', 'b', 'a'];
keys.forEach((key) => {
if (obj[key] !== undefined && isNaN(obj[key] as number)) {
obj[key] = 1;
}
});
return obj;
};
73 changes: 33 additions & 40 deletions src/hexToRgba.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,43 @@ import { toRgbString } from './toRgbString';
* @returns An RGB or RGBA color value. ('rgb(11, 22, 33)', 'rgba(11, 22, 33, 0.5)')
*/
export function hexToRgba(hex: string, alpha: string | number = 1): string {
try {
if (!isValidHex(hex)) {
throw new Error('Invalid hex color');
}
if (!isValidHex(hex)) {
throw new Error('Invalid hex color');
}

const hashlessHex = hex.replace(/^#/, '');
const { r, g, b } = parseHex(hashlessHex);
const hashlessHex = hex.replace(/^#/, '');
const { r, g, b } = parseHex(hashlessHex);

// Check if r, g, b are valid numbers
if (!isNumeric(r) || !isNumeric(g) || !isNumeric(b)) {
throw new TypeError('Invalid color components');
}
// Validate the parsed hex values
if (!r || !g || !b || r.length !== 2 || g.length !== 2 || b.length !== 2) {
throw new TypeError('Invalid color components');
}

let alphaValue: number;
const red = hexToDecimal(r);
const green = hexToDecimal(g);
const blue = hexToDecimal(b);

// Check alpha value
if (typeof alpha === 'number') {
if (alpha < 0 || alpha > 1) {
throw new Error('Invalid alpha value');
}
alphaValue = alpha;
} else if (isNumeric(alpha)) {
alphaValue = parseFloat(alpha);
if (alphaValue < 0 || alphaValue > 1) {
throw new Error('Invalid alpha value');
}
} else {
alphaValue = 1;
}
let alphaValue: number;

return toRgbString({
r: hexToDecimal(r),
g: hexToDecimal(g),
b: hexToDecimal(b),
a: alphaValue
});

} catch (error: any) {
console.log(`Error converting hex to RGBA: ${error.toString()}`);
return toRgbString({
r: hexToDecimal('FF'),
g: hexToDecimal('00'),
b: hexToDecimal('00'),
a: 1
});
// Check alpha value
if (typeof alpha === 'number') {
if (alpha < 0 || alpha > 1) {
throw new Error('Invalid alpha value');
}
alphaValue = alpha;
} else if (isNumeric(alpha)) {
alphaValue = parseFloat(alpha);
if (alphaValue < 0 || alphaValue > 1) {
throw new Error('Invalid alpha value');
}
} else {
alphaValue = 1;
}

return toRgbString({
r: red,
g: green,
b: blue,
a: alphaValue
});
}
28 changes: 7 additions & 21 deletions src/parseColor.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
/**
* Imports for color conversion and validation utilities.
*/
import { canBeConvertedIntoColor } from "./canBeConvertedToColor";
import { hexesToDecimals } from "./hexToDecimals";
import { hexToRgb } from "./hexToRgb";
import { hexToRgba } from "./hexToRgba";
import { hexesToDecimals, RgbWithAHexObject } from "./hexToDecimals";
import { isValidHex } from "./isValidHex";
import { isValidRgb } from "./isValidRgb";
import { isValidRgba } from "./isValidRgba";
import { parseRgbString } from "./parseRgbString";
import { toRgbString } from "./toRgbString";
import { parseHex } from "./parseHex";
import { HexDecimalObject } from "./types/hex-decimal-object.interface";

/**
Expand All @@ -24,25 +19,16 @@ export const parseColor = (colorValue: string): HexDecimalObject => {
}

try {
let rgbString: string | null = null;
let rgbaString: string | null = null;
let result: HexDecimalObject | null = null;

if (isValidHex(colorValue)) {
rgbString = hexToRgb(colorValue);
rgbaString = hexToRgba(colorValue);
const hexObject = parseHex(colorValue);
result = hexesToDecimals(hexObject as RgbWithAHexObject);
} else if (isValidRgb(colorValue)) {
rgbString = colorValue;
result = hexesToDecimals(colorValue);
} else if (isValidRgba(colorValue)) {
rgbaString = colorValue;
}

if (rgbString) {
result = parseRgbString(rgbString);
}

if (!result && rgbaString) {
result = parseRgbString(rgbaString);
const hexObject = parseRgbString(colorValue);
result = hexesToDecimals(hexObject as any);
}

if (result) {
Expand Down

0 comments on commit 1ad0723

Please sign in to comment.