Some components should be highly customizable (such as Tag), and the library provides a way to use colors in a consistent way.
To achieve that, we forked @ctrl/tinycolor (version 4.1.0, changes after this version are not supported) and added some features to it (like tailwind colors support).
API
import { LuiColor } from '@lqvrent-workspace/lqvrent-ui/core/colors';
new LuiColor('indigo').toHexString(); // '#6366f1'
Accepted String Inputs
The string parsing is very permissive. It is meant to make typing a color as input as easy as possible. All commas, percentages, parenthesis are optional, and most input allow either 0-1, 0%-100%, or 0-n (where n is either 100, 255, or 360 depending on the value).
HSL and HSV both require either 0%-100% or 0-1 for the S/L/V properties. The H (hue) can have values between 0%-100% or 0-360.
RGB input requires either 0-255 or 0%-100%.
If you call fromRatio
, RGB and Hue input can also accept 0-1.
Here are some examples of string input:
Tailwind Named Colors
new LuiColor('indigo');
new LuiColor('emerald');
new LuiColor('sky');
When using tailwind colors, the library will use the 500
shade by default (in most cases, it works great for both light and dark themes).
If you want to use another shade, you can use any tailwind color like in the following example:
import colors from 'tailwindcss/colors';
new LuiColor(colors.emerald[800]);
CSS Named Colors
new LuiColor('SEASHELL');
new LuiColor('blanchedalmond');
new LuiColor('darkblue');
Hex, 8-digit (RGBA) Hex
new LuiColor('#000');
new LuiColor('000');
new LuiColor('#369C');
new LuiColor('369C');
new LuiColor('#f0f0f6');
new LuiColor('f0f0f6');
new LuiColor('#f0f0f688');
new LuiColor('f0f0f688');
RGB, RGBA
new LuiColor('rgb (255, 0, 0)');
new LuiColor('rgb 255 0 0');
new LuiColor('rgba (255, 0, 0, .5)');
new LuiColor({ r: 255, g: 0, b: 0 });
import { fromRatio } from '@lqvrent-workspace/lqvrent-ui/core/colors';
fromRatio({ r: 1, g: 0, b: 0 });
fromRatio({ r: 0.5, g: 0.5, b: 0.5 });
HSL, HSLA
new LuiColor('hsl(0, 100%, 50%)');
new LuiColor('hsla(0, 100%, 50%, .5)');
new LuiColor('hsl(0, 100%, 50%)');
new LuiColor('hsl 0 1.0 0.5');
new LuiColor({ h: 0, s: 1, l: 0.5 });
HSV, HSVA
new LuiColor('hsv(0, 100%, 100%)');
new LuiColor('hsva(0, 100%, 100%, .5)');
new LuiColor('hsv (0 100% 100%)');
new LuiColor('hsv 0 1 1');
new LuiColor({ h: 0, s: 100, v: 100 });
CMYK
new LuiColor('cmyk(0, 25, 20, 0)');
new LuiColor('cmyk(0, 100, 100, 0)');
new LuiColor('cmyk 100 0 100 0)');
new LuiColor({c: 0, m: 25, y: 25, k: 0});
Number
new LuiColor(0x0);
new LuiColor(0xaabbcc);
Accepted Object Input
If you are calling this from code, you may want to use object input. Here are some examples of the different types of accepted object inputs:
{ r: 255, g: 0, b: 0 }
{ r: 255, g: 0, b: 0, a: .5 }
{ h: 0, s: 100, l: 50 }
{ h: 0, s: 100, v: 100 }
Properties
originalInput
The original input passed into the constructer used to create the LuiColor
instance
const color = new LuiColor('gold');
color.originalInput; // "gold"
color = new LuiColor({ r: 255, g: 215, b: 0 });
color.originalInput; // "{r: 255, g: 215, b: 0}"
format
Returns the format used to create the LuiColor
instance
const color = new LuiColor('gold');
color.format; // "name"
color = new LuiColor({ r: 255, g: 215, b: 0 });
color.format; // "rgb"
isValid
A boolean indicating whether the color was successfully parsed.
If the color is not valid then it will act like black
when being used with other methods.
const color1 = new LuiColor('gold');
color1.isValid; // true
color1.toHexString(); // "#ffd700"
const color2 = new LuiColor('not a color');
color2.isValid; // false
color2.toString(); // "#000000"
Methods
getBrightness
Returns the perceived brightness of a color, from 0-255
, as defined by Web Content Accessibility Guidelines (Version 1.0).
const color1 = new LuiColor('#fff');
color1.getBrightness(); // 255
const color2 = new LuiColor('#000');
color2.getBrightness(); // 0
isLight
Return a boolean indicating whether the color's perceived brightness is light.
const color1 = new LuiColor('#fff');
color1.isLight(); // true
const color2 = new LuiColor('#000');
color2.isLight(); // false
isDark
Return a boolean indicating whether the color's perceived brightness is dark.
const color1 = new LuiColor('#fff');
color1.isDark(); // false
const color2 = new LuiColor('#000');
color2.isDark(); // true
getLuminance
Returns the perceived luminance of a color, from 0-1
as defined by Web Content Accessibility Guidelines (Version 2.0).
const color1 = new LuiColor('#fff');
color1.getLuminance(); // 1
const color2 = new LuiColor('#000');
color2.getLuminance(); // 0
getAlpha
Returns the alpha value of a color, from 0-1
.
const color1 = new LuiColor('rgba(255, 0, 0, .5)');
color1.getAlpha(); // 0.5
const color2 = new LuiColor('rgb(255, 0, 0)');
color2.getAlpha(); // 1
const color3 = new LuiColor('transparent');
color3.getAlpha(); // 0
setAlpha
Sets the alpha value on a current color. Accepted range is in between 0-1
.
const color = new LuiColor('gold');
color.getAlpha(); // 1
color.setAlpha(0.5);
color.getAlpha(); // .5
color.toRgbString(); // "rgba(255, 215, 0, .5)"
onBackground
Compute how the color would appear on a background. When the color is fully transparent (i.e. getAlpha() == 0
), the result will be the background color. When the color is not transparent at all (i.e. getAlpha() == 1
), the result will be the color itself. Otherwise you will get a computed result.
const color = new LuiColor('rgba(255, 0, 0, .5)');
const computedColor = color.onBackground('rgb(0, 0, 255)');
computedColor.toRgbString(); // "rgb(128, 0, 128)"
String Representations
The following methods will return a property for the alpha
value, which can be ignored: toHsv
, toHsl
, toRgb
toHsv
const color = new LuiColor('gold');
color.toHsv(); // ~ { h: 50.6, s: 1, v: 1, a: 1 }
toHsvString
const color = new LuiColor('gold');
color.toHsvString(); // ~ "hsv(50.6, 100%, 100%)"
color.setAlpha(0.5);
color.toHsvString(); // ~ "hsva(50.6, 100%, 100%, 0.5)"
toHsl
const color = new LuiColor('gold');
color.toHsl(); // ~ { h: 50.6, s: 1, l: 0.5, a: 1 }
toHslString
const color = new LuiColor('gold');
color.toHslString(); // ~ "hsl(50.6, 100%, 50%)"
color.setAlpha(0.5);
color.toHslString(); // ~ "hsla(50.6, 100%, 50%, 0.5)"
toCmykString
const color = new LuiColor('gold');
color.toCmykString(); // "cmyk(0, 25, 100, 0)"
toNumber
new LuiColor('#aabbcc').toNumber() === 0xaabbcc // true
new LuiColor('rgb(1, 1, 1)').toNumber() === (1 << 16) + (1 << 8) + 1 // true
toHex
const color = new LuiColor('gold');
color.toHex(); // "ffd700"
toHexString
const color = new LuiColor('gold');
color.toHexString(); // "#ffd700"
toHex8
const color = new LuiColor('gold');
color.toHex8(); // "ffd700ff"
toHex8String
const color = new LuiColor('gold');
color.toHex8String(); // "#ffd700ff"
toHexShortString
const color1 = new LuiColor('#ffd700ff');
color1.toHexShortString(); // "#ffd700"
color1.toHexShortString(true); // "#fd0"
const color2 = new LuiColor('#ffd700');
color2.toHexShortString(); // "#ffd700"
color2.toHexShortString(true); // "#fd0"
toRgb
const color = new LuiColor('gold');
color.toRgb(); // { r: 255, g: 215, b: 0, a: 1 }
toRgbString
const color = new LuiColor('gold');
color.toRgbString(); // "rgb(255, 215, 0)"
color.setAlpha(0.5);
color.toRgbString(); // "rgba(255, 215, 0, 0.5)"
toPercentageRgb
const color = new LuiColor('gold');
color.toPercentageRgb(); // { r: "100%", g: "84.3%", b: "0%", a: 1 }
toPercentageRgbString
const color = new LuiColor('gold');
color.toPercentageRgbString(); // "rgb(100%, 84.3%, 0%)"
color.setAlpha(0.5);
color.toPercentageRgbString(); // "rgba(100%, 84.3%, 0%, 0.5)"
toName
const color = new LuiColor('gold');
color.toName(); // "gold"
toFilter
import { toMsFilter } from '@lqvrent-workspace/lqvrent-ui/core/colors';
toMsFilter('gold', 'blue'); // 'progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffd70000,endColorstr=#ff0000ff)'
toString
Print to a string, depending on the input format. You can also override this by passing one of "rgb", "prgb", "hex6", "hex3", "hex8", "name", "hsl", "hsv"
into the function.
const color1 = new LuiColor('gold');
color1.toString(); // "rold"
color1.toString('hsv'); // "hsv(50.6, 100%, 100%)"
const color2 = new LuiColor('rgb(255, 215, 0)');
color2.toString(); // "rgb(255, 215, 0)"
color2.setAlpha(0.5);
color2.toString(); // "rgba(255, 215, 0, 0.5)"
Color Modification
These methods manipulate the current color, and return it for chaining. For instance:
new LuiColor('gold')
.lighten()
.desaturate()
.toHexString(); // '#f2f2f2'
lighten
Lighten the color a given amount, from 0 to 100. Providing 100 will always return white.
lighten: function(amount = 10) -> LuiColor
new LuiColor('#f00').lighten().toString(); // '#ff3333'
new LuiColor('#f00').lighten(100).toString(); // '#ffffff'
brighten
Brighten the color a given amount, from 0 to 100.
brighten: function(amount = 10) -> LuiColor
new LuiColor('#f00').brighten().toString(); // '#ff1919'
darken
Darken the color a given amount, from 0 to 100. Providing 100 will always return black.
darken: function(amount = 10) -> LuiColor
new LuiColor('#f00').darken().toString(); // '#cc0000'
new LuiColor('#f00').darken(100).toString(); // '#000000'
tint
Mix the color with pure white, from 0 to 100. Providing 0 will do nothing, providing 100 will always return white.
new LuiColor('#f00').tint().toString(); // "#ff1a1a"
new LuiColor('#f00').tint(100).toString(); // "#ffffff"
shade
Mix the color with pure black, from 0 to 100. Providing 0 will do nothing, providing 100 will always return black.
new LuiColor('#f00').shade().toString(); // "#e60000"
new LuiColor('#f00').shade(100).toString(); // "#000000"
desaturate
Desaturate the color a given amount, from 0 to 100. Providing 100 will is the same as calling greyscale
.
desaturate: function(amount = 10) -> LuiColor
new LuiColor('#f00').desaturate().toString(); // "#f20d0d"
new LuiColor('#f00').desaturate(100).toString(); // "#808080"
saturate
Saturate the color a given amount, from 0 to 100.
saturate: function(amount = 10) -> LuiColor
new LuiColor('hsl(0, 10%, 50%)').saturate().toString(); // "hsl(0, 20%, 50%)"
greyscale
Completely desaturates a color into greyscale. Same as calling desaturate(100)
.
greyscale: function() -> LuiColor
new LuiColor('#f00').greyscale().toString(); // "#808080"
spin
spin: function(amount = 0) -> LuiColor
. Spin the hue a given amount, from -360 to 360. Calling with 0, 360, or -360 will do nothing (since it sets the hue back to what it was before).
new LuiColor('#f00').spin(180).toString(); // "#00ffff"
new LuiColor('#f00').spin(-90).toString(); // "#7f00ff"
new LuiColor('#f00').spin(90).toString(); // "#80ff00"
// spin(0) and spin(360) do nothing
new LuiColor('#f00').spin(0).toString(); // "#ff0000"
new LuiColor('#f00').spin(360).toString(); // "#ff0000"
mix
mix: function(amount = 50) -> LuiColor
. Mix the current color a given amount with another color, from 0 to 100. 0 means no mixing (return current color).
let color1 = new LuiColor('#f0f');
let color2 = new LuiColor('#0f0');
color1.mix(color2).toHexString(); // #808080
Color Combinations
Combination functions return an array of LuiColor objects unless otherwise noted.
analogous
analogous: function(results = 6, slices = 30) -> array<LuiColor>
.
const colors = new LuiColor('#f00').analogous();
colors.map(t => t.toHexString()); // [ "#ff0000", "#ff0066", "#ff0033", "#ff0000", "#ff3300", "#ff6600" ]
monochromatic
monochromatic: function(, results = 6) -> array<LuiColor>
.
const colors = new LuiColor('#f00').monochromatic();
colors.map(t => t.toHexString()); // [ "#ff0000", "#2a0000", "#550000", "#800000", "#aa0000", "#d40000" ]
splitcomplement
splitcomplement: function() -> array<LuiColor>
.
const colors = new LuiColor('#f00').splitcomplement();
colors.map(t => t.toHexString()); // [ "#ff0000", "#ccff00", "#0066ff" ]
triad
triad: function() -> array<LuiColor>
. Alias for polyad(3)
.
const colors = new LuiColor('#f00').triad();
colors.map(t => t.toHexString()); // [ "#ff0000", "#00ff00", "#0000ff" ]
tetrad
tetrad: function() -> array<LuiColor>
. Alias for polyad(4)
.
const colors = new LuiColor('#f00').tetrad();
colors.map(t => t.toHexString()); // [ "#ff0000", "#80ff00", "#00ffff", "#7f00ff" ]
polyad
polyad: function(number) -> array<LuiColor>
.
const colors = new LuiColor('#f00').polyad(4);
colors.map(t => t.toHexString()); // [ "#ff0000", "#80ff00", "#00ffff", "#7f00ff" ]
complement
complement: function() -> LuiColor
.
new LuiColor('#f00').complement().toHexString(); // "#00ffff"
Color Utilities
equals
let color1 = new LuiColor('gold');
let color2 = new LuiColor('#ffd700');
color1.equals(color2); // true
random
Returns a random LuiColor
object. This is an implementation of randomColor by David Merfield.
The difference input parsing and output formatting are handled by LuiColor.
You can pass an options object to influence the type of color it produces. The options object accepts the following properties:
hue
– Controls the hue of the generated color. You can pass a string representing a color name:red
,orange
,yellow
,green
,blue
,purple
,pink
andmonochrome
are currently supported. If you pass a hexidecimal color string such as #00FFFF, its hue value will be extracted and used to generate colors.luminosity
– Controls the luminosity of the generated color. You can specify a string containing bright, light or dark.count
– An integer which specifies the number of colors to generate.seed
– An integer which when passed will cause randomColor to return the same color each time.alpha
– A decimal between 0 and 1. Only relevant when using a format with an alpha channel (rgba and hsla). Defaults to a random value.
import { random } from '@lqvrent-workspace/lqvrent-ui/core/colors';
// Returns a LuiColor for an attractive color
random();
// Returns an array of ten green colors
random({
count: 10,
hue: 'green',
});
// Returns a LuiColor object in a light blue
random({
luminosity: 'light',
hue: 'blue',
});
// Returns a LuiColor object in a 'truly random' color
random({
luminosity: 'random',
hue: 'random',
});
// Returns a dark RGB color with specified alpha
random({
luminosity: 'dark',
alpha: 0.5,
});
Readability
LuiColor assesses readability based on the Web Content Accessibility Guidelines (Version 2.0).
readability
readability: function(LuiColor, LuiColor) -> number
.
Returns the contrast ratio between two colors.
import { readability } from '@lqvrent-workspace/lqvrent-ui/core/colors';
readability('#000', '#000'); // 1
readability('#000', '#111'); // 1.1121078324840545
readability('#000', '#fff'); // 21
Use the values in your own calculations, or use one of the convenience functions below.
isReadable
isReadable: function(LuiColor, LuiColor, Object) -> Boolean
. Ensure that foreground and background color combinations meet WCAG guidelines. Object
is optional, defaulting to {level: "AA",size: "small"}
. level
can be "AA"
or "AAA" and size
can be "small"
or "large"
.
Here are links to read more about the AA and AAA requirements.
import { isReadable } from '@lqvrent-workspace/lqvrent-ui/core/colors';
isReadable("#000", "#111"); // false
isReadable("#ff0088", "#5c1a72", { level: "AA", size: "small" }); // false
isReadable("#ff0088", "#5c1a72", { level: "AA", size: "large" }), // true
mostReadable
mostReadable: function(LuiColor, [LuiColor, LuiColor ...], Object) -> Boolean
.
Given a base color and a list of possible foreground or background colors for that base, returns the most readable color.
If none of the colors in the list is readable, mostReadable
will return the better of black or white if includeFallbackColors:true
.
import { mostReadable } from '@lqvrent-workspace/lqvrent-ui/core/colors';
mostReadable('#000', ['#f00', '#0f0', '#00f']).toHexString(); // "#00ff00"
mostReadable('#123', ['#124', '#125'], { includeFallbackColors: false }).toHexString(); // "#112255"
mostReadable('#123', ['#124', '#125'], { includeFallbackColors: true }).toHexString(); // "#ffffff"
mostReadable('#ff0088', ['#2e0c3a'], {
includeFallbackColors: true,
level: 'AAA',
size: 'large',
}).toHexString(); // "#2e0c3a",
mostReadable('#ff0088', ['#2e0c3a'], {
includeFallbackColors: true,
level: 'AAA',
size: 'small',
}).toHexString(); // "#000000",
See index.html in the project for a demo.
Common operations
clone
clone: function() -> LuiColor
.
Instantiate a new LuiColor
object with the same color. Any changes to the new one won't affect the old one.
const color1 = new LuiColor('#F00');
const color2 = color1.clone();
color2.setAlpha(0.5);
color1.toString(); // "#ff0000"
color2.toString(); // "rgba(255, 0, 0, 0.5)"