Skip to content

Commit

Permalink
udpated readme
Browse files Browse the repository at this point in the history
  • Loading branch information
landonwjohnson committed Jul 19, 2024
1 parent a59486c commit 6dff8bf
Show file tree
Hide file tree
Showing 47 changed files with 1,170 additions and 727 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@devlander/colors",
"description": "Color utility package used between packages",
"version": "0.0.3",
"version": "0.0.4",
"browser": "dist/umd/index.js",
"main": "dist/cjs/index.js",
"types": "typings/index.d.ts",
Expand Down
19 changes: 9 additions & 10 deletions src/__tests__/adjustColor.test.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,44 @@
import { adjustColor } from "../adjustColor";
import { AlphaValue } from "../types/alpha-value.type";

describe("adjustColor", () => {
it("should return the input color if it is a valid CSS color name", () => {
const result = adjustColor("transparent", 0.5 as AlphaValue, "light");
const result = adjustColor("transparent", 0.5, "light");
expect(result).toBe("transparent");
});

it("should return default color if alphaValue is out of range", () => {
const result = adjustColor("#FFFFFF", -1 as AlphaValue, "light");
it("should return default color is out of range", () => {
const result = adjustColor("#FFFFFF", -1, "light");
expect(result).toBe("#FF0000");
});

it("should lighten the color in light mode", () => {
const result = adjustColor("#000000", 0.5 as AlphaValue, "light");
const result = adjustColor("#000000", 0.5, "light");
expect(result).toMatch(/^#[0-9A-F]{6}$/i); // Regex to match hex color
});

it("should darken the color in dark mode", () => {
const result = adjustColor("#FFFFFF", 0.5 as AlphaValue, "dark");
const result = adjustColor("#FFFFFF", 0.5, "dark");
expect(result).toMatch(/^#[0-9A-F]{6}$/i); // Regex to match hex color
});

it("should return default color for invalid color format", () => {
const result = adjustColor("invalidColor", 0.5 as AlphaValue, "light");
const result = adjustColor("invalidColor", 0.5, "light");
expect(result).toBe("#FF0000");
});

it("should apply alpha to RGB color", () => {
const result = adjustColor("rgb(0, 0, 0)", 0.5 as AlphaValue, "light");
const result = adjustColor("rgb(0, 0, 0)", 0.5, "light");
expect(result).toMatch(/^rgba\(\d{1,3}, \d{1,3}, \d{1,3}, 0(\.\d+)?\)$/i); // Regex to match RGBA color
});

it("should apply alpha to RGBA color", () => {
const result = adjustColor("rgba(0, 0, 0, 1)", 0.5 as AlphaValue, "light");
const result = adjustColor("rgba(0, 0, 0, 1)", 0.5, "light");
expect(result).toMatch(/^rgba\(\d{1,3}, \d{1,3}, \d{1,3}, 0(\.\d+)?\)$/i); // Regex to match RGBA color
});

it("should handle exceptions and return default color", () => {
jest.spyOn(console, "log").mockImplementation(() => {}); // Mock console.log
const result = adjustColor("#12345G", 0.5 as AlphaValue, "light");
const result = adjustColor("#12345G", 0.5, "light");
expect(result).toBe("#FF0000");
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining("Error adjusting color with value"),
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/color.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ describe("Color class", () => {
test("should blend the color with another color", () => {
const color = new Color("#ff6464");
const secondaryColor: HexDecimalObject = { r: 0, g: 0, b: 255 };
color.blend(0.5, secondaryColor);
color.blend(50, secondaryColor);
expect(color.getColor()).toEqual({ r: 128, g: 50, b: 178 });
});

Expand Down
99 changes: 50 additions & 49 deletions src/adjustColor.ts
Original file line number Diff line number Diff line change
@@ -1,106 +1,107 @@
import { applyAlphaToColor } from './applyAlphaToColor'
import { canBeConvertedIntoColor } from './canBeConvertedToColor'
import { applyAlphaToColor } from "./applyAlphaToColor";
import { canBeConvertedIntoColor } from "./canBeConvertedToColor";

import { lightenColor } from './lightenColor'
import { darkenColor } from './darkenColor'
import { toHexColor } from './toHexColor'
import { toRgbString } from './toRgbString'
import { blendColors } from './blendColors'
import { parseRgbString } from './parseRgbString'
import { isValidHex } from './isValidHex'
import { isValidRgb } from './isValidRgb'
import { isValidRgba } from './isValidRgba'
import { AlphaValue } from './types/alpha-value.type'
import { ThemeType } from './types/theme.type'
import { HexDecimalObject } from './types/hex-decimal-object.interface'
import { hexesToDecimals, RgbWithAHexObject } from './hexToDecimals'
import { parseHex } from './parseHex'
import { NumberRange1To100 } from './types/number-range-hundred.type'
import { lightenColor } from "./lightenColor";
import { darkenColor } from "./darkenColor";
import { toHexColor } from "./toHexColor";
import { toRgbString } from "./toRgbString";
import { blendColors } from "./blendColors";
import { parseRgbString } from "./parseRgbString";
import { isValidHex } from "./isValidHex";
import { isValidRgb } from "./isValidRgb";
import { isValidRgba } from "./isValidRgba";
import { ThemeType } from "./types/theme.type";
import { HexDecimalObject } from "./types/hex-decimal-object.interface";
import { hexesToDecimals, RgbWithAHexObject } from "./hexToDecimals";
import { parseHex } from "./parseHex";
import { AlphaScale } from "./types/alpha-scale.type";

export interface AdjustColorFunc {
(
colorValue: string,
alphaValue: NumberRange1To100,
alphaValue: AlphaScale,
mode: ThemeType,
cssColorNames?: string[],
): string
): string;
}

const defaultCssColorNames = ['transparent']
const defaultCssColorNames = ["transparent"];

export const log = (message: string): void => {
if (typeof console !== 'undefined' && typeof console.log === 'function') {
console.log(message)
if (typeof console !== "undefined" && typeof console.log === "function") {
console.log(message);
}
}
};

export const adjustColor: AdjustColorFunc = (
colorValue: string,
alphaValue: NumberRange1To100,
alphaValue: AlphaScale,
mode: ThemeType,
cssColorNames = defaultCssColorNames,
): string => {
try {
if (cssColorNames.includes(colorValue)) return colorValue
if (cssColorNames.includes(colorValue)) return colorValue;

if (alphaValue < 0 || alphaValue > 1) {
log('Alpha value should be between 0.0 and 1.0. Returning default color.')
return '#FF0000' // Default color (Red in this case)
if (alphaValue < 0 || alphaValue > 100) {
log(
"Alpha value should be between 0.0 and 1.0. Returning default color.",
);
return "#FF0000"; // Default color (Red in this case)
}

if (canBeConvertedIntoColor(colorValue)) {
let color: HexDecimalObject | null = null
let color: HexDecimalObject | null = null;

if (isValidHex(colorValue)) {
const hexObject = parseHex(colorValue)
color = hexesToDecimals(hexObject as RgbWithAHexObject)
const hexObject = parseHex(colorValue);
color = hexesToDecimals(hexObject as RgbWithAHexObject);
} else if (isValidRgb(colorValue)) {
color = parseRgbString(colorValue)
color = parseRgbString(colorValue);
} else if (isValidRgba(colorValue)) {
color = parseRgbString(colorValue)
color = parseRgbString(colorValue);
} else {
throw new Error('Invalid color format')
throw new Error("Invalid color format");
}

if (!color) {
throw new Error('Failed to parse color')
throw new Error("Failed to parse color");
}

const brightnessFactor = mode === 'light' ? 0.2 : -0.2
const brightnessFactor = mode === "light" ? 0.2 : -0.2;
color =
mode === 'light'
mode === "light"
? lightenColor(color, brightnessFactor)
: darkenColor(color, brightnessFactor)
: darkenColor(color, brightnessFactor);

const alphaScale = alphaValue
const alphaScale = alphaValue;

if (isValidHex(colorValue)) {
const mixedColor = blendColors(
color,
{ r: 255, g: 255, b: 255 },
alphaScale,
)
return toHexColor(mixedColor)
);
return toHexColor(mixedColor);
} else {
const colorWithAlpha = applyAlphaToColor(color, alphaScale)
return toRgbString(colorWithAlpha)
const colorWithAlpha = applyAlphaToColor(color, alphaScale);
return toRgbString(colorWithAlpha);
}
} else {
log(
`Failed to convert ${colorValue} into a color. Returning default color.`,
)
return '#FF0000' // Default color (Red in this case)
);
return "#FF0000"; // Default color (Red in this case)
}
} catch (error) {
if (error instanceof Error) {
log(
`Error adjusting color with value: ${colorValue}. Returning default color. Error: ${error.message}`,
)
);
} else {
log(
`Error adjusting color with value: ${colorValue}. Returning default color. Unknown error.`,
)
);
}
return '#FF0000' // Default color (Red in this case)
return "#FF0000"; // Default color (Red in this case)
}
}
};
35 changes: 32 additions & 3 deletions src/applyAlphaToColor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
import { AlphaScale } from "./types/alpha-scale.type";

/**
* Applies a new alpha value to an RGBA color object.
* The alpha value can be provided in the range 0-1 or 0-100.
*
* @param {object} color - The original color object with properties r, g, b, and optionally a.
* @param {AlphaScale} alphaValue - The new alpha value. It can be in the range 0-1 or 0-100.
* @returns {object} - The new color object with the updated alpha value.
*
* @example
* const color = { r: 52, g: 152, b: 219 };
* const newColor = applyAlphaToColor(color, 50);
* // newColor will be { r: 52, g: 152, b: 219, a: 0.5 }
*/
export const applyAlphaToColor = (
color: { r: number; g: number; b: number; a?: number },
alphaValue: number,
alphaValue: AlphaScale,
): { r: number; g: number; b: number; a: number } => {
return { ...color, a: alphaValue }
}
let alpha;

// Check if alphaValue is in the 0-1 range or 0-100 range
if (alphaValue > 1) {
// Assume alphaValue is in the 0-100 range
alpha = alphaValue / 100;
} else {
// Assume alphaValue is in the 0-1 range
alpha = alphaValue;
}

// Ensure the new alpha value is within the valid range (0 to 1)
const clampedAlpha = Math.min(Math.max(alpha, 0), 1);

return { ...color, a: clampedAlpha };
};
54 changes: 46 additions & 8 deletions src/blendColors.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,52 @@
import { HexDecimalObject } from './types/hex-decimal-object.interface'
import { NumberRange1To100 } from './types/number-range-hundred.type'
import { AlphaScale } from "./types/alpha-scale.type";
import { HexDecimalObject } from "./types/hex-decimal-object.interface";

/**
* Blends two colors based on the given alpha scale.
* The alpha scale can be provided in the range -1 to 1, -1.00 to 1.00, or -100 to 100.
*
* @param {HexDecimalObject} color1 - The first color object with properties r, g, b.
* @param {HexDecimalObject} color2 - The second color object with properties r, g, b.
* @param {AlphaScale} alphaScale - The alpha scale value. It can be in the range -1 to 1, -1.00 to 1.00, or -100 to 100.
* @returns {HexDecimalObject} - The blended color object.
*
* @example
* const color1 = { r: 52, g: 152, b: 219 };
* const color2 = { r: 255, g: 0, b: 0 };
* const blendedColor = blendColors(color1, color2, 50);
* // blendedColor will be a color blended 50% between color1 and color2
*/
export const blendColors = (
color1: HexDecimalObject,
color2: { r: number; g: number; b: number },
alphaScale: NumberRange1To100,
alphaScale: AlphaScale,
): HexDecimalObject => {
return {
r: Math.round(color1.r * alphaScale + color2.r * (1 - alphaScale)),
g: Math.round(color1.g * alphaScale + color2.g * (1 - alphaScale)),
b: Math.round(color1.b * alphaScale + color2.b * (1 - alphaScale)),
let alpha;

// Check if alphaScale is in the 0-1, 0.00-1.00, or 1-100 range
if (Math.abs(alphaScale) > 1) {
// Assume alphaScale is in the 1-100 range
alpha = alphaScale / 100;
} else {
// Assume alphaScale is in the 0-1 or 0.00-1.00 range
alpha = alphaScale;
}
}

// Ensure the new alpha value is within the valid range (0 to 1)
const clampedAlpha = Math.min(Math.max(alpha, -1), 1);

return {
r: Math.round(
color1.r * Math.abs(clampedAlpha) +
color2.r * (1 - Math.abs(clampedAlpha)),
),
g: Math.round(
color1.g * Math.abs(clampedAlpha) +
color2.g * (1 - Math.abs(clampedAlpha)),
),
b: Math.round(
color1.b * Math.abs(clampedAlpha) +
color2.b * (1 - Math.abs(clampedAlpha)),
),
};
};
14 changes: 7 additions & 7 deletions src/canBeConvertedToColor.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { isValidHex } from './isValidHex'
import { isValidRgb } from './isValidRgb'
import { isValidRgba } from './isValidRgba'
import { isValidHex } from "./isValidHex";
import { isValidRgb } from "./isValidRgb";
import { isValidRgba } from "./isValidRgba";

export const canBeConvertedIntoColor = (
colorValue: string,
cssColorNames = ['transparent'],
cssColorNames = ["transparent"],
): boolean => {
if (cssColorNames.includes(colorValue)) return true
if (cssColorNames.includes(colorValue)) return true;
return (
isValidHex(colorValue) || isValidRgb(colorValue) || isValidRgba(colorValue)
)
}
);
};
Loading

0 comments on commit 6dff8bf

Please sign in to comment.