react-native-ui-lib
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a
268 lines (214 loc) • 6.14 kB
JavaScript
import _ from 'lodash'; //@ts-ignore
import Color from 'color';
import tinycolor from 'tinycolor2';
import { colorsPalette, themeColors } from "./colorsPalette";
import { designTokens } from "./designTokens"; //@ts-ignore
import ColorName from "./colorName";
import Scheme from "./scheme";
export class Colors {
constructor() {
const colors = Object.assign(colorsPalette, designTokens, themeColors);
Object.assign(this, colors);
Scheme.addChangeListener(() => {
Object.assign(this, Scheme.getScheme());
});
}
/**
* Load custom set of colors
* arguments:
* colors - map of keys and colors values e.g {grey10: '#20303C', grey20: '#43515C'}
*/
loadColors(colors) {
_.forEach(colors, (value, key) => {
this[key] = value;
});
}
/**
* Load set of schemes for light/dark mode
* arguments:
* schemes - two sets of map of colors e.g {light: {screen: 'white'}, dark: {screen: 'black'}}
*/
loadSchemes(schemes) {
Scheme.loadSchemes(schemes);
Object.assign(this, Scheme.getScheme());
}
/**
* Get app's current color scheme
*/
getScheme() {
return Scheme.getSchemeType();
}
/**
* Set color scheme for app
* arguments:
* scheme - color scheme e.g light/dark/default
*/
setScheme(scheme) {
Scheme.setScheme(scheme);
}
/**
* Add alpha to hex or rgb color
* arguments:
* p1 - hex color / R part of RGB
* p2 - opacity / G part of RGB
* p3 - B part of RGB
* p4 - opacity
*/
rgba(p1, p2, p3, p4) {
let hex;
let opacity;
let red;
let green;
let blue;
if (arguments.length === 2 && typeof p1 === 'string') {
hex = p1;
opacity = p2;
hex = validateHex(hex);
red = parseInt(hex.substring(0, 2), 16);
green = parseInt(hex.substring(2, 4), 16);
blue = parseInt(hex.substring(4, 6), 16);
} else if (arguments.length === 4 && typeof p1 === 'number') {
red = validateRGB(p1);
green = validateRGB(p2);
blue = validateRGB(p3);
opacity = p4;
} else {
throw new Error('rgba can work with either 2 or 4 arguments');
}
return `rgba(${red}, ${green}, ${blue}, ${opacity})`;
}
getBackgroundKeysPattern() {
return /^(bg-|background-)/;
}
isEmpty(color) {
if (_.isNil(color) || color === 'transparent') {
return true;
}
try {
Color(color);
return false;
} catch (error) {
console.warn('Colors.isEmpty failed:', error);
return true;
}
}
getColorTint(color, tintKey) {
if (_.isUndefined(tintKey) || isNaN(tintKey) || _.isUndefined(color)) {
// console.error('"Colors.getColorTint" must accept a color and tintKey params');
return color;
}
if (color === 'transparent') {
return color;
}
const colorKey = _.findKey(this, (_value, key) => this[key] === color);
if (colorKey) {
const requiredColorKey = `${colorKey.slice(0, -2)}${tintKey}`;
const requiredColor = this[requiredColorKey];
if (_.isUndefined(requiredColor)) {
return this.getTintedColorForDynamicHex(color, tintKey);
}
return requiredColor;
}
return this.getTintedColorForDynamicHex(color, tintKey);
}
getColorName(color) {
return ColorName.name(color)[1];
}
getTintedColorForDynamicHex(color, tintKey) {
// Handles dynamic colors (non uilib colors)
let tintLevel = Math.floor(Number(tintKey) / 10);
tintLevel = Math.max(1, tintLevel);
tintLevel = Math.min(8, tintLevel);
const colorsPalette = this.generateColorPalette(color);
return colorsPalette[tintLevel - 1];
}
generateColorPalette = _.memoize(color => {
const hsl = Color(color).hsl();
const lightness = Math.round(hsl.color[2]);
const ls = [hsl.color[2]];
let l = lightness - 10;
while (l >= 20) {
ls.unshift(l);
l -= 10;
}
l = lightness + 10;
while (l < 100) {
ls.push(l);
l += 10;
}
const tints = [];
_.forEach(ls, e => {
const tint = generateColorTint(color, e);
tints.push(tint);
});
const sliced = tints.slice(0, 8);
const adjusted = adjustSaturation(sliced, color);
return adjusted || sliced;
});
isDark(color) {
const lum = tinycolor(color).getLuminance();
return lum < 0.55;
}
isValidHex(string) {
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);
}
getHexString(color) {
return tinycolor(color).toHexString();
}
getHSL(color) {
return tinycolor(color).toHsl();
}
isTransparent(color) {
return color && _.toUpper(color) === _.toUpper('transparent');
}
areEqual(colorA, colorB) {
return _.toLower(colorA) === _.toLower(colorB);
}
}
function adjustSaturation(colors, color) {
let array;
const lightnessLevel = 80;
const saturationLevel = 60;
const hsl = Color(color).hsl();
const lightness = Math.round(hsl.color[2]);
if (lightness > lightnessLevel) {
const saturation = Math.round(hsl.color[1]);
if (saturation > saturationLevel) {
array = _.map(colors, e => e !== color ? addSaturation(e, saturationLevel) : e);
}
}
return array;
}
function addSaturation(color, saturation) {
const hsl = Color(color).hsl();
hsl.color[1] = saturation;
return hsl.hex();
}
function generateColorTint(color, tintLevel) {
const hsl = Color(color).hsl();
hsl.color[2] = tintLevel;
return hsl.hex();
}
function validateRGB(value) {
if (isNaN(value) || value > 255 || value < 0) {
throw new Error(`${value} is invalid rgb code, please use number between 0-255`);
}
return value;
}
function validateHex(value) {
if (!/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value)) {
throw new Error(`${value} is invalid hex color`);
}
value = value.replace('#', '');
if (value.length === 3) {
value = threeDigitHexToSix(value);
}
return value;
}
function threeDigitHexToSix(value) {
return value.replace(/./g, '$&$&');
}
const TypedColors = Colors;
const colorObject = new TypedColors();
colorObject.loadColors(colorsPalette);
export default colorObject;