@ericrovell/blossom
v1.10.0
Published
Blossom is a JS library tool for colour manipulations and transformations.
Downloads
47
Maintainers
Readme
Blossom
Blossom is a JS library tool for color manipulations and transformations.
Features:
- Chainable API;
- Ummutable;
- Written in Typescript;
- Types included;
- Dependency-free;
Getting started
npm i @ericrovell/blossom
import { blossom } from "@ericrovell/blossom";
blossom("#FF0000")
.grayscale
.setAlpha(0.25)
.toStringRGB
// -> rgb(128 128 128 / 0.25)
Supported color models
- Hexadecimal strings;
- RGB (objects, strings);
- HSL (objects, strings);
- HSV (objects);
- CMYK (objects);
- XYZ (objects);
- LAB (objects);
- LCH (objects, strings);
- HWB (objects, strings);
- Named colors
API
Color parsing
Parses the given input and creates a new Blossom instance.
import { blossom } from "@ericrovell/blossom";
// string input
blossom("#ABC");
blossom("#AABBCC");
blossom("#ADCDEF12");
blossom("rgb(100, 200, 255)");
blossom("rgba(100, 200, 255, 0.5)");
blossom("rgba(10% 20% 30% / 35%)");
blossom("hsl(180, 78%, 87%)");
blossom("hsla(180, 78%, 87%, 0.5)");
blossom("hsla(180deg 78% 87% / 50%)");
// object input
blossom({ r: 12, g: 34, b: 56 });
blossom({ r: 12, g: 34, b: 56, a: 1 });
blossom({ h: 180, s: 50, l: 75 });
blossom({ h: 180, s: 50, l: 75, a: 1 });
blossom({ h: 180, s: 50, v: 65 });
blossom({ h: 180, s: 50, v: 65, a: 1 });
blossom({ c: 25, m: 50, k: 75, k: 100 });
blossom({ c: 25, m: 50, k: 75, k: 100, a: 1 });
Parses a color and returns a color model name of the given input.
import { getModel } from "@ericrovell/blossom";
getModel("#ADC123"); // -> "hex"
getModel({ r: 13, g: 237, b: 162 }); // -> "rgb"
getModel("hsl(180deg 50% 50%)"); // -> "hsl"
getModel("Hi!"); // -> null
Color transformations
Returns the hexadecimal representation of a color.
Outputs the modern #RRGGBBAA
opacity syntax for transparent colors.
blossom("rgb(0, 255, 0)").hex; // -> "#00FF00"
blossom({ h: 300, s: 100, l: 50 }).hex; // -> "#FF00FF"
blossom({ r: 255, g: 255, b: 255, a: 0 }).hex; // -> "#FFFFFF00"
Returns the RGB color model object of a color.
blossom("#ff0000").rgb; // -> { r: 255, g: 0, b: 0, a: 1 }
blossom({ h: 180, s: 100, l: 50, a: 0.5 }).rgb; // -> { r: 0, g: 255, b: 255, a: 0.5 }
Returns the RGB color model string of a color. Outputs the modern whitespace syntax.
blossom("#ff0000").toStringRGB; // -> "rgb(255 0 0)"
blossom({ h: 180, s: 100, l: 50, a: 0.5 }).toStringRGB; // -> "rgb(0 255 255 / 0.5)"
Returns the HSL color space object of a color.
blossom("#ffff00").hsl; // -> { h: 60, s: 100, l: 50, a: 1 }
blossom("rgba(0, 0, 255, 0.5)").hsl; // -> { h: 240, s: 100, l: 50, a: 0.5 }
Returns the HSL color space string of a color. Outputs the modern whitespace syntax.
blossom("#ffff00").toStringHSL; // -> "hsl(60deg 100% 50%)"
blossom("rgba(0, 0, 255, 0.5)").toStringHSL; // -> "hsl(240deg 100% 50% / 0.5)"
Returns the HSV color space object of a color.
blossom("#ffff00").hsv; // -> { h: 60, s: 100, v: 100, a: 1 }
blossom("rgba(0, 255, 255, 0.5)").hsv; // -> { h: 180, s: 100, v: 100, a: 1 }
Returns the HSV color space string of a color. Outputs the modern whitespace syntax.
blossom("#FFFF00").toStringHSV; // -> "hsc(60deg 100% 100%)"
blossom("rgba(0, 0, 255, 0.5)").toStringHSV; // -> "hsc(240deg 100% 100% / 0.5)"
Returns the CMYK color space object of a color.
blossom("#FFFFFF").cmyk; // -> { c: 0, m: 0, y: 0, k: 0, a: 1 }
blossom("#555AAA").cmyk; // -> { c: 50, m: 47, y: 0, k: 33, a: 1 }
Returns the CMYK color space string of a color.
blossom("#FFFFFF").toStringCMYK; // -> device-cmyk(0% 0% 0% 0%){ c: 0, m: 0, y: 0, k: 0, a: 1 }
blossom("#555AAA80").toStringCMYK; // -> device-cmyk(50% 47% 0 33% / 0.5)
Returns the CIE XYZ color space object of a color.
blossom("#FFFFFF").xyz; // -> { x: 95.047, y: 100, z: 108.883 a: 1 }
blossom({ x: 0, y: 0, z: 0 }).hex; // -> "#000000"
Returns the CIE XYZ color space string of a color.
blossom("#FFFFFF").toStringXYZ; // -> color(xyz 96.42 100 82.52)
blossom("#555AAA80").toStringXYZ; // -> color(xyz 13.65 11.79 29.83 / 0.5)
Returns the CIE LAB color space object of a color.
blossom("#FFFFFF").lab; // -> { l: 100, a: 0, b: 0, alpha: 1 }
blossom("#123ABC").lab; // -> { l: 29.95, a: 29.48, b: -72.93, alpha: 1 }
Returns the CIE LAB color space string of a color.
blossom("#FFFFFF").toStringLAB; // -> lab(100% 0 0)
blossom("#555AAA80").toStringLAB; // -> lab(40.88% 15.43 -44.4)
Returns the CIE LCH color space object of a color.
blossom("#FFFFFF").lch; // -> { l: 100, c: 0, h: 0, a: 1 }
blossom("#123ABC").lch; // -> { l: 29.95, c: 78.66, c: 292.01, alpha: 1 }
Returns the CIE LCH color space string of a color.
blossom("#FFFFFF").toStringLCH; // -> lch(100% 0 0)
blossom("#555AAA80").toStringLCH; // -> lch(40.88% 47.01 289.16 / 0.5)
Returns the HWB color space object of a color.
blossom("#FFFFFF").hwb; // -> { h: 0, w: 100, b: 0, a: 1 }
blossom("#123ABC").hwb; // -> { h: 226, w: 7, b: 26, a: 1 }
Returns the HWB color space string of a color.
blossom("#FFFFFF").toStringHWB; // -> hwb(0 100% 0%)
blossom("#555AAA80").toStringHWB; // -> hwb(236 33% 33% / 0.5)
Returns the name of the color as exact match of browser supported list of 140 named colors. If the color has not an alias returns null
instead.
blossom("#FF0000").name; // -> "red"
blossom("#123ABC").name; // -> null
Returns the closest named color from browser supported list of 140 named colors color.
blossom("#FF0001").closestName; // -> "red"
blossom("#66339A").closestName; // -> "rebeccapurple"
Color manipulation
Changes the alpha channel value and returns a new Blossom
instance.
blossom("rgb(0, 0, 0)")
.setAlpha(0.5)
.toStringRGB; // -> "rgb(0 0 0 / 0.5)"
Creates a new Blossom
instance with an inverted color.
blossom("#aabbcc")
.inverted
.hex; // -> "#554433"
Increases the HSL saturation of a color by the given amount.
blossom("#bf4040")
.saturate(0.25)
.hex; // -> "#df2020"
blossom("hsl(0, 50%, 50%)")
.saturate(0.5)
.toStringHSL; // -> "hsl(0deg 100% 50%)"
Decreases the HSL saturation of a color by the given amount.
blossom("#df2020")
.saturate(0.25)
.hex; // -> "#bf4040"
blossom("hsl(0, 100%, 50%)")
.saturate(0.5)
.toStringHSL; // -> "hsl(0deg 50% 50%)"
Creates a gray color with the same lightness as a source color.
Same result as .desaturate(1)
.
blossom("#bf4040")
.grayscale
.hex; // -> "#808080"
blossom("hsl(0, 100%, 50%)")
.grayscale
.toStringHSL; // -> "hsl(0deg 0% 50%)"
Increases the HSL lightness of a color by the given amount.
blossom("#000000")
.lighten(0.5)
.hex; // -> "#808080"
blossom("#223344")
.lighten(0.3)
.hex; // -> "#5580aa"
blossom("hsl(0, 50%, 50%)")
.lighten(0.5)
.toStringHSL; // -> "hsl(0deg 50% 100%)"
Decreases the HSL lightness of a color by the given amount.
blossom("#ffffff")
.darken(0.5)
.hex; // -> "#808080"
blossom("#5580aa")
.darken(0.3)
.hex; // -> "#223344"
blossom("hsl(0, 50%, 100%)")
.lighten(0.5)
.toStringHSL; // -> "hsl(0, 50%, 50%)"
Changes the hue value and returns a new Blossom
instance.
blossom("hsl(90, 50%, 50%)")
.setHue(180)
.toStringHSL; // -> "hsl(180deg 50% 50%)"
blossom("hsl(90, 50%, 50%)")
.setHue(370)
.toStringHSL; // -> "hsl(10deg 50% 50%)"
Increases the HSL hue value of a color by the given amount.
blossom("hsl(90, 50%, 50%)")
.rotate(90)
.toStringHSL; // -> "hsl(180deg 50% 50%)"
blossom("hsl(90, 50%, 50%)")
.rotate(-180)
.toStringHSL; // -> "hsl(270deg 50% 50%)"
Color properties
Returns a boolean indicating whether or not an input has been parsed successfully. On unsuccess, color value defaults to black without error.
blossom("#FFF").valid; // -> true
blossom("#NaN").valid; // -> false
blossom("hello").valid; // -> false
blossom({ r: 0, g: 0, b: 0 }).valid; // -> true
blossom({ r: 0, g: 0, v: 0 }).valid; // -> false
Returns an alpha channel value of the color.
blossom("#FFFFFF").alpha; // -> 1
blossom("rgba(50 100 150 / 0.5)").alpha; // -> 0.5
Returns a boolean indicating whether or not a color is opaque.
blossom("#FFFFFF").opaque; // -> true
blossom("rgba(50 100 150 / 0.5)").opaque; // -> false
Returns a boolean indicating whether or not a color is transparent.
blossom("#FFFFFF").transparent; // -> false
blossom("rgba(50 100 150 / 0.5)").transparent; // -> true
Returns the Hue value of the number on the color wheel.
blossom("hsl(90deg 50% 50%)").hue; // -> 90
blossom("hsl(-10deg 50% 50%)").hue; // -> 350
Returns the saturation value of the number.
blossom("hsl(90deg 50% 50%)").saturation; // -> 0.5
blossom("hsl(-10deg 98% 50%)").saturation; // -> 0.98
Returns the lightness value of the number.
blossom("hsl(90deg 50% 50%)").lightness; // -> 0.5
blossom("hsl(-10deg 50% 46%)").lightness; // -> 0.46
Returns the brightness of a color in range [0; 1]. The calculation logic is modified from Web Content Accessibility Guidelines.
blossom("#000000").brightness; // -> 0
blossom("#808080").brightness; // -> 0.5
blossom("#FFFFFF").brightness; // -> 1
A Boolean indicator whether or not a color is light (brightness >= 0.5).
blossom("#000000").light; // -> false
blossom("#808080").light; // -> true
blossom("#FFFFFF").light; // -> true
A Boolean indicator whether or not a color is dark (brightness < 0.5).
blossom("#000000").dark; // -> true
blossom("#808080").dark; // -> false
blossom("#FFFFFF").dark; // -> false
Returns the relative luminance of a color, normalized to range [0, 1] as from pure black to pure white according to WCAG 2.0.
blossom("#000000").luminance; // 0
blossom("#808080").luminance; // 0.22
blossom("#ffffff").luminance; // 1
Calculates a contrast ratio for a pair of colors.
The luminance difference lies in range [1 (white on white), 21 (black on white)]. WCAG required a ratio at least 4.5 for normal text and 3:1 for large one.
blossom("#000000").contrast(); // 21 (black on white)
blossom("#ffffff").contrast("#000000"); // 21 (white on black)
blossom("#777777").contrast(); // 4.47 (gray on white)
blossom("#ff0000").contrast(); // 3.99 (red on white)
blossom("#0000ff").contrast("#ff000"); // 2.14 (blue on red)
Checks that a background and text color pair is readable according to WCAG 2.0 Contrast and Color Requirements.
blossom("#000000").isReadable(); // true (normal black text on white bg conforms to WCAG AA)
blossom("#777777").isReadable(); // false (normal gray text on white bg conforms to WCAG AA)
blossom("#ffffff").isReadable("#000000"); // true (normal white text on black bg conforms to WCAG AA)
blossom("#e60000").isReadable("#ffff47", { level: "AAA" }); // false (normal red text on yellow bg does not conform to WCAG AAA)
blossom("#e60000").isReadable("#ffff47", { level: "AAA", size: "large" }); // true (large red text on yellow bg conforms to WCAG AAA)
Produces a mixture of two colors and returns the result as new Blossom
instance. Mix produced using CIE LAB color space.
import { colord, extend } from "blossom";
import pluginMix from "@ericrovell/blossom/plugins/mix";
extend([ mixPlugin ]);
blossom("#FFFFFF").mix("#000000").hex; // -> "#777777"
blossom("#800080").mix("#DDA0DD").hex; // -> "#AF5CAE"
blossom("#CD853F").mix("#EEE8AA", 0.6).hex; // -> "#E3C07E"
blossom("#008080").mix("#808000", 0.35).hex; // -> "#50805D"
Calculates the perceived color difference between two colors. The difference calculated according to Delta E2000.
Returns the normalized value in range from [0, 1], where 0 means the same colors and 1 are completely different ones.
colord("#3296fa").delta("#197dc8") // 0.099
colord("#faf0c8").delta("#fff") // 0.148
colord("#afafaf").delta("#b4b4b4") // 0.014
colord("#000").delta("#fff") // 1.0
Color Utilities
Creates new instance with a random color.
import { random } from "@ericrovell/blossom";
random().hex; // -> "#01C8EC"
random().setAlpha(0.5).rgb; // -> { r: 13, g: 237, b: 162, a: 0.5 }
Plugins
Usage
To extend the functionality using plugins, the extend
function should be used:
import { blossom, extend } from "@ericrovell/blossom";
import { plugin1, plugin2 } from "plugin-path;
extend([
plugin1,
plugin2
]);
Included plugins
Provides functionatity to generate harmony colors.
Available harmony pallets:
- analogous;
- complimentary;
- double-split-comlimentary;
- rectangle;
- tetradic;
- triadic;
- split-complimentary;
import { blossom, extends } from "@ericrovell/blossom";
import { pluginHarmonies } from "blossom/plugins/harmonies";
extend([ pluginHarmonies ]);
const color = blossom("FF0000");
color.harmonies("analogous")
.map(color => color.hex); // -> [ "#FF0080", "#FF0000", "#FF8000"]
color.harmonies("complimentary")
.map(color => color.hex); // -> [ "#FF0000", "#00FFFF" ]
color.harmonies("double-split-complimentary")
.map(color => color.hex); // -> [ "#FF0080", "#FF0000", "#FF8000", "#00FF80", "#0080FF" ]
color.harmonies("rectangle")
.map(color => color.hex); // -> [ "#FF0000", "#FFFF00", "#00FFFF", "#0000FF" ]
color.harmonies("tetradic")
.map(color => color.hex); // -> [ "#FF0000", "#80FF00", "#00FFFF", "#8000FF" ]
color.harmonies("triadic" )
.map(color => color.hex); // -> [ "#FF0000", "#00FF00", "#0000FF" ]
color.harmonies("split-complimentary")
.map(color => color.hex); // -> [ "#FF0000", "#00FF80", "#0080FF" ]
Harmony color schemes type is available for import:
import type { Harmony } from "@ericrovell/blossom/plugins/harmonies";
const harmony: Harmony = "analogous";
const notHarmony: Harmony = "round"; // TypeError
Provides functionatity to generate monochromatic colors as:
- Tints;
- Shades;
- Tones.
import { blossom, extends } from "@ericrovell/blossom";
import { pluginMonochromatic } from "blossom/plugins/monochromatic";
extend([ pluginMonochromatic ]);
const color = blossom("FF0000");
color.tints(4).map(tint => tint.hex); // -> [ "#FF0000", "#FF4242", "#FF8585", "#FFC7C7", "#FFFFFF" ]
color.shades(4).map(shade => shade.hex); // -> [ "#FF0000", "#BD0000", "#7A0000", "#380000", "#000000" ]
color.tones(4).map(tone => tone.hex); // -> [ "#FF0000", "#DF2020", "#BF4040", "#9F6060", "#808080" ]
The original color is always included as first palette item.
If there is not enough space between colors to generate required number of colors, less number of colors will be generated. For example, generating 10 shades for #050505
is not practical as #000000
is too close and all shades will be indistinguishable:
import { blossom, extends } from "@ericrovell/blossom";
import { pluginMonochromatic } from "blossom/plugins/monochromatic";
extend([ pluginMonochromatic ]);
blossom("#FAFAFA").tints(10).map(tint => tint.hex); // -> [ "#FAFAFA", "#FDFDFD", "#FFFFFF" ]
blossom("#050505").shades(10).map(shade => shade.hex); // -> [ "#050505", "#020202", "#000000" ]
blossom("#827D7D").tones(10).map(tone => tone.hex); // -> [ "#827D7D", "#817E7E", "#808080" ]
Adds accessibility and color contrast utilities working according to Web Content Accessibility Guidelines 2.0.
import { blossom, extend } from "@ericrovell/blossom";
import { pluginA11Y } from "@ericrovell/blossom/plugins/a11y";
extend([ pluginA11Y ]);
blossom("#000000").luminance; // 0
blossom("#CCDDEE").luminance; // 0.71
blossom("#FFFFFF").luminance; // 1
blossom("#000000").contrast(); // 21 (black on white)
blossom("#FFFFFF").contrast("#000000"); // 21 (white on black)
blossom("#0000ff").contrast("#FF000"); // 2.14 (blue on red)
blossom("#000000").readable(); // true (black on white)
blossom("#FFFFFF").readable("#000000"); // true (white on black)
blossom("#777777").readable(); // false (gray on white)
blossom("#E60000").readable("#FFFF47"); // true (normal red text on yellow bg conforms to WCAG AA)
blossom("#E60000").readable("#FFFF47", { level: "AAA" }); // false (normal red text on yellow bg does not conform to WCAG AAA)
blossom("#E60000").readable("#FFFF47", { level: "AAA", size: "large" }); // true (large red text on yellow bg conforms to WCAG AAA)
Adds support of CIE XYZ color model.
import { blossom, extend } from "@ericrovell/blossom";
import { pluginXYZ } from "@ericrovell/blossom/plugins/xyz";
extend([ pluginXYZ ]);
blossom("#FFFFFF").xyz; // -> { x: 95.047, y: 100, z: 108.883, a: 1 }
blossom({ x: 0, y: 0, z: 0 }).hex; // -> "#000000"
Adds support of CIE LAB color model.
Plugin provides .delta
method for perceived color difference calculations: 0 for same colors, 1 for completely different ones.
import { blossom, extend } from "@ericrovell/blossom";
import { pluginLAB } from "@ericrovell/blossom/plugins/lab";
extend([ pluginLAB ]);
blossom({ l: 29.95, a: 29.48, b: -72.93 }).hex; // "#123ABC"
blossom("#FFFFFF").lab; // { l: 100, a: 0, b: 0, alpha: 1 }
blossom("#afafaf").delta("#b4b4b4") // 0.014
blossom("#000").delta("#fff") // 1.0
Adds support of CIE LCH color model.
import { blossom, extend } from "@ericrovell/blossom";
import { pluginLCH } from "@ericrovell/blossom/plugins/lch";
extend([ pluginLCH ]);
blossom({ l: 29.95, a: 29.48, b: 40.21 }).hex; // "#6B372A"
blossom("#FFFFFF").lab; // { l: 100, c: 0, h: 0, a: 1 }
Adds support of HWB color model.
import { blossom, extend } from "@ericrovell/blossom";
import { pluginHWB } from "@ericrovell/blossom/plugins/hwb";
extend([ pluginHWB ]);
blossom({h: 236, w: 33, b: 33 }).hex; // "#555AAA"
blossom("#FFFFFF").hwb; // { h: 0, w: 100, b: 0 }
Adds support for mixing colors. Mixture is produced using CIE LAB color space.
import { colord, extend } from "blossom";
import pluginMix from "@ericrovell/blossom/plugins/mix";
extend([ mixPlugin ]);
blossom("#FFFFFF").mix("#000000").hex; // -> "#777777"
blossom("#800080").mix("#DDA0DD").hex; // -> "#AF5CAE"
blossom("#CD853F").mix("#EEE8AA", 0.6).hex; // -> "#E3C07E"
blossom("#008080").mix("#808000", 0.35).hex; // -> "#50805D"
Adds support for a list of 140 named colors supported by all modern browsers.
import { colord, extend } from "blossom";
import pluginNames from "@ericrovell/blossom/plugins/names";
extend([ pluginNames ]);
blossom("white").hex // -> "#FFFFFF"
blossom("red").hex // -> "#FF0000"
blossom("#FF0000").name // -> "red"
blossom("#ABC123").name // -> null
blossom("#FF0101").closestName // -> "red"
blossom("#66339A").closestName // -> "rebeccapurple"
Types
Blossom is written in strict TypeScript and ships with types in the library itself.
While not only typing its own functions and variables, you can also type yours. Depending on the color space you are using, the types can be also imported and used to type the code.
import type { ColorRGB, ColorHSL } from "@ericrovell/blossom";
const foo: ColorHSL = { h: 0, s: 0, l: 0 };
const bar: ColorRGB = { r: 0, g: 0, v: 0 }; // type error!
Extending the functionality
To extend functionality for your needs, just extend the Blossom
class:
import { Blossom } from "@ericrovell/blossom";
class BlossomExtended extends Blossom {
constructor(input?) {
super(input);
}
get red() {
return this.color.r;
}
}
const extended = new BlossomExtended("#FF0000");
extended.red // -> 255;
Inspiration
It was a long time I was thinking about this project. There were two unsuccessfull attemps, it was not thoughfull enough.
This project is inspired by fantastic colord project, that gave me the idea about architecture and implementation.