refactor(projects): refactor @sa/color-palette => @sa/color & perf @sa/utils

This commit is contained in:
Soybean
2024-04-26 01:42:35 +08:00
parent 1cb3816e48
commit 34999971fd
31 changed files with 269 additions and 171 deletions

View File

@ -0,0 +1,16 @@
{
"name": "@sa/color",
"version": "1.0.5",
"exports": {
".": "./src/index.ts"
},
"typesVersions": {
"*": {
"*": ["./src/*"]
}
},
"dependencies": {
"@sa/utils": "workspace:*",
"colord": "2.9.3"
}
}

View File

@ -0,0 +1,2 @@
export * from './name';
export * from './palette';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,356 @@
import type { ColorPaletteFamily } from '../types';
export const colorPalettes: ColorPaletteFamily[] = [
{
name: 'Slate',
palettes: [
{ hex: '#f8fafc', number: 50 },
{ hex: '#f1f5f9', number: 100 },
{ hex: '#e2e8f0', number: 200 },
{ hex: '#cbd5e1', number: 300 },
{ hex: '#94a3b8', number: 400 },
{ hex: '#64748b', number: 500 },
{ hex: '#475569', number: 600 },
{ hex: '#334155', number: 700 },
{ hex: '#1e293b', number: 800 },
{ hex: '#0f172a', number: 900 },
{ hex: '#020617', number: 950 }
]
},
{
name: 'Gray',
palettes: [
{ hex: '#f9fafb', number: 50 },
{ hex: '#f3f4f6', number: 100 },
{ hex: '#e5e7eb', number: 200 },
{ hex: '#d1d5db', number: 300 },
{ hex: '#9ca3af', number: 400 },
{ hex: '#6b7280', number: 500 },
{ hex: '#4b5563', number: 600 },
{ hex: '#374151', number: 700 },
{ hex: '#1f2937', number: 800 },
{ hex: '#111827', number: 900 },
{ hex: '#030712', number: 950 }
]
},
{
name: 'Zinc',
palettes: [
{ hex: '#fafafa', number: 50 },
{ hex: '#f4f4f5', number: 100 },
{ hex: '#e4e4e7', number: 200 },
{ hex: '#d4d4d8', number: 300 },
{ hex: '#a1a1aa', number: 400 },
{ hex: '#71717a', number: 500 },
{ hex: '#52525b', number: 600 },
{ hex: '#3f3f46', number: 700 },
{ hex: '#27272a', number: 800 },
{ hex: '#18181b', number: 900 },
{ hex: '#09090b', number: 950 }
]
},
{
name: 'Neutral',
palettes: [
{ hex: '#fafafa', number: 50 },
{ hex: '#f5f5f5', number: 100 },
{ hex: '#e5e5e5', number: 200 },
{ hex: '#d4d4d4', number: 300 },
{ hex: '#a3a3a3', number: 400 },
{ hex: '#737373', number: 500 },
{ hex: '#525252', number: 600 },
{ hex: '#404040', number: 700 },
{ hex: '#262626', number: 800 },
{ hex: '#171717', number: 900 },
{ hex: '#0a0a0a', number: 950 }
]
},
{
name: 'Stone',
palettes: [
{ hex: '#fafaf9', number: 50 },
{ hex: '#f5f5f4', number: 100 },
{ hex: '#e7e5e4', number: 200 },
{ hex: '#d6d3d1', number: 300 },
{ hex: '#a8a29e', number: 400 },
{ hex: '#78716c', number: 500 },
{ hex: '#57534e', number: 600 },
{ hex: '#44403c', number: 700 },
{ hex: '#292524', number: 800 },
{ hex: '#1c1917', number: 900 },
{ hex: '#0c0a09', number: 950 }
]
},
{
name: 'Red',
palettes: [
{ hex: '#fef2f2', number: 50 },
{ hex: '#fee2e2', number: 100 },
{ hex: '#fecaca', number: 200 },
{ hex: '#fca5a5', number: 300 },
{ hex: '#f87171', number: 400 },
{ hex: '#ef4444', number: 500 },
{ hex: '#dc2626', number: 600 },
{ hex: '#b91c1c', number: 700 },
{ hex: '#991b1b', number: 800 },
{ hex: '#7f1d1d', number: 900 },
{ hex: '#450a0a', number: 950 }
]
},
{
name: 'Orange',
palettes: [
{ hex: '#fff7ed', number: 50 },
{ hex: '#ffedd5', number: 100 },
{ hex: '#fed7aa', number: 200 },
{ hex: '#fdba74', number: 300 },
{ hex: '#fb923c', number: 400 },
{ hex: '#f97316', number: 500 },
{ hex: '#ea580c', number: 600 },
{ hex: '#c2410c', number: 700 },
{ hex: '#9a3412', number: 800 },
{ hex: '#7c2d12', number: 900 },
{ hex: '#431407', number: 950 }
]
},
{
name: 'Amber',
palettes: [
{ hex: '#fffbeb', number: 50 },
{ hex: '#fef3c7', number: 100 },
{ hex: '#fde68a', number: 200 },
{ hex: '#fcd34d', number: 300 },
{ hex: '#fbbf24', number: 400 },
{ hex: '#f59e0b', number: 500 },
{ hex: '#d97706', number: 600 },
{ hex: '#b45309', number: 700 },
{ hex: '#92400e', number: 800 },
{ hex: '#78350f', number: 900 },
{ hex: '#451a03', number: 950 }
]
},
{
name: 'Yellow',
palettes: [
{ hex: '#fefce8', number: 50 },
{ hex: '#fef9c3', number: 100 },
{ hex: '#fef08a', number: 200 },
{ hex: '#fde047', number: 300 },
{ hex: '#facc15', number: 400 },
{ hex: '#eab308', number: 500 },
{ hex: '#ca8a04', number: 600 },
{ hex: '#a16207', number: 700 },
{ hex: '#854d0e', number: 800 },
{ hex: '#713f12', number: 900 },
{ hex: '#422006', number: 950 }
]
},
{
name: 'Lime',
palettes: [
{ hex: '#f7fee7', number: 50 },
{ hex: '#ecfccb', number: 100 },
{ hex: '#d9f99d', number: 200 },
{ hex: '#bef264', number: 300 },
{ hex: '#a3e635', number: 400 },
{ hex: '#84cc16', number: 500 },
{ hex: '#65a30d', number: 600 },
{ hex: '#4d7c0f', number: 700 },
{ hex: '#3f6212', number: 800 },
{ hex: '#365314', number: 900 },
{ hex: '#1a2e05', number: 950 }
]
},
{
name: 'Green',
palettes: [
{ hex: '#f0fdf4', number: 50 },
{ hex: '#dcfce7', number: 100 },
{ hex: '#bbf7d0', number: 200 },
{ hex: '#86efac', number: 300 },
{ hex: '#4ade80', number: 400 },
{ hex: '#22c55e', number: 500 },
{ hex: '#16a34a', number: 600 },
{ hex: '#15803d', number: 700 },
{ hex: '#166534', number: 800 },
{ hex: '#14532d', number: 900 },
{ hex: '#052e16', number: 950 }
]
},
{
name: 'Emerald',
palettes: [
{ hex: '#ecfdf5', number: 50 },
{ hex: '#d1fae5', number: 100 },
{ hex: '#a7f3d0', number: 200 },
{ hex: '#6ee7b7', number: 300 },
{ hex: '#34d399', number: 400 },
{ hex: '#10b981', number: 500 },
{ hex: '#059669', number: 600 },
{ hex: '#047857', number: 700 },
{ hex: '#065f46', number: 800 },
{ hex: '#064e3b', number: 900 },
{ hex: '#022c22', number: 950 }
]
},
{
name: 'Teal',
palettes: [
{ hex: '#f0fdfa', number: 50 },
{ hex: '#ccfbf1', number: 100 },
{ hex: '#99f6e4', number: 200 },
{ hex: '#5eead4', number: 300 },
{ hex: '#2dd4bf', number: 400 },
{ hex: '#14b8a6', number: 500 },
{ hex: '#0d9488', number: 600 },
{ hex: '#0f766e', number: 700 },
{ hex: '#115e59', number: 800 },
{ hex: '#134e4a', number: 900 },
{ hex: '#042f2e', number: 950 }
]
},
{
name: 'Cyan',
palettes: [
{ hex: '#ecfeff', number: 50 },
{ hex: '#cffafe', number: 100 },
{ hex: '#a5f3fc', number: 200 },
{ hex: '#67e8f9', number: 300 },
{ hex: '#22d3ee', number: 400 },
{ hex: '#06b6d4', number: 500 },
{ hex: '#0891b2', number: 600 },
{ hex: '#0e7490', number: 700 },
{ hex: '#155e75', number: 800 },
{ hex: '#164e63', number: 900 },
{ hex: '#083344', number: 950 }
]
},
{
name: 'Sky',
palettes: [
{ hex: '#f0f9ff', number: 50 },
{ hex: '#e0f2fe', number: 100 },
{ hex: '#bae6fd', number: 200 },
{ hex: '#7dd3fc', number: 300 },
{ hex: '#38bdf8', number: 400 },
{ hex: '#0ea5e9', number: 500 },
{ hex: '#0284c7', number: 600 },
{ hex: '#0369a1', number: 700 },
{ hex: '#075985', number: 800 },
{ hex: '#0c4a6e', number: 900 },
{ hex: '#082f49', number: 950 }
]
},
{
name: 'Blue',
palettes: [
{ hex: '#eff6ff', number: 50 },
{ hex: '#dbeafe', number: 100 },
{ hex: '#bfdbfe', number: 200 },
{ hex: '#93c5fd', number: 300 },
{ hex: '#60a5fa', number: 400 },
{ hex: '#3b82f6', number: 500 },
{ hex: '#2563eb', number: 600 },
{ hex: '#1d4ed8', number: 700 },
{ hex: '#1e40af', number: 800 },
{ hex: '#1e3a8a', number: 900 },
{ hex: '#172554', number: 950 }
]
},
{
name: 'Indigo',
palettes: [
{ hex: '#eef2ff', number: 50 },
{ hex: '#e0e7ff', number: 100 },
{ hex: '#c7d2fe', number: 200 },
{ hex: '#a5b4fc', number: 300 },
{ hex: '#818cf8', number: 400 },
{ hex: '#6366f1', number: 500 },
{ hex: '#4f46e5', number: 600 },
{ hex: '#4338ca', number: 700 },
{ hex: '#3730a3', number: 800 },
{ hex: '#312e81', number: 900 },
{ hex: '#1e1b4b', number: 950 }
]
},
{
name: 'Violet',
palettes: [
{ hex: '#f5f3ff', number: 50 },
{ hex: '#ede9fe', number: 100 },
{ hex: '#ddd6fe', number: 200 },
{ hex: '#c4b5fd', number: 300 },
{ hex: '#a78bfa', number: 400 },
{ hex: '#8b5cf6', number: 500 },
{ hex: '#7c3aed', number: 600 },
{ hex: '#6d28d9', number: 700 },
{ hex: '#5b21b6', number: 800 },
{ hex: '#4c1d95', number: 900 },
{ hex: '#2e1065', number: 950 }
]
},
{
name: 'Purple',
palettes: [
{ hex: '#faf5ff', number: 50 },
{ hex: '#f3e8ff', number: 100 },
{ hex: '#e9d5ff', number: 200 },
{ hex: '#d8b4fe', number: 300 },
{ hex: '#c084fc', number: 400 },
{ hex: '#a855f7', number: 500 },
{ hex: '#9333ea', number: 600 },
{ hex: '#7e22ce', number: 700 },
{ hex: '#6b21a8', number: 800 },
{ hex: '#581c87', number: 900 },
{ hex: '#3b0764', number: 950 }
]
},
{
name: 'Fuchsia',
palettes: [
{ hex: '#fdf4ff', number: 50 },
{ hex: '#fae8ff', number: 100 },
{ hex: '#f5d0fe', number: 200 },
{ hex: '#f0abfc', number: 300 },
{ hex: '#e879f9', number: 400 },
{ hex: '#d946ef', number: 500 },
{ hex: '#c026d3', number: 600 },
{ hex: '#a21caf', number: 700 },
{ hex: '#86198f', number: 800 },
{ hex: '#701a75', number: 900 },
{ hex: '#4a044e', number: 950 }
]
},
{
name: 'Pink',
palettes: [
{ hex: '#fdf2f8', number: 50 },
{ hex: '#fce7f3', number: 100 },
{ hex: '#fbcfe8', number: 200 },
{ hex: '#f9a8d4', number: 300 },
{ hex: '#f472b6', number: 400 },
{ hex: '#ec4899', number: 500 },
{ hex: '#db2777', number: 600 },
{ hex: '#be185d', number: 700 },
{ hex: '#9d174d', number: 800 },
{ hex: '#831843', number: 900 },
{ hex: '#500724', number: 950 }
]
},
{
name: 'Rose',
palettes: [
{ hex: '#fff1f2', number: 50 },
{ hex: '#ffe4e6', number: 100 },
{ hex: '#fecdd3', number: 200 },
{ hex: '#fda4af', number: 300 },
{ hex: '#fb7185', number: 400 },
{ hex: '#f43f5e', number: 500 },
{ hex: '#e11d48', number: 600 },
{ hex: '#be123c', number: 700 },
{ hex: '#9f1239', number: 800 },
{ hex: '#881337', number: 900 },
{ hex: '#4c0519', number: 950 }
]
}
];

View File

@ -0,0 +1,7 @@
import { colorPalettes } from './constant';
export * from './palette';
export * from './shared';
export { colorPalettes };
export * from './types';

View File

@ -0,0 +1,176 @@
import type { AnyColor, HsvColor } from 'colord';
import { getHex, getHsv, isValidColor, mixColor } from '../shared';
import type { ColorIndex } from '../types';
/** Hue step */
const hueStep = 2;
/** Saturation step, light color part */
const saturationStep = 16;
/** Saturation step, dark color part */
const saturationStep2 = 5;
/** Brightness step, light color part */
const brightnessStep1 = 5;
/** Brightness step, dark color part */
const brightnessStep2 = 15;
/** Light color count, main color up */
const lightColorCount = 5;
/** Dark color count, main color down */
const darkColorCount = 4;
/**
* Get AntD palette color by index
*
* @param color - Color
* @param index - The color index of color palette (the main color index is 6)
* @returns Hex color
*/
export function getAntDPaletteColorByIndex(color: AnyColor, index: ColorIndex): string {
if (!isValidColor(color)) {
throw new Error('invalid input color value');
}
if (index === 6) {
return getHex(color);
}
const isLight = index < 6;
const hsv = getHsv(color);
const i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;
const newHsv: HsvColor = {
h: getHue(hsv, i, isLight),
s: getSaturation(hsv, i, isLight),
v: getValue(hsv, i, isLight)
};
return getHex(newHsv);
}
/** Map of dark color index and opacity */
const darkColorMap = [
{ index: 7, opacity: 0.15 },
{ index: 6, opacity: 0.25 },
{ index: 5, opacity: 0.3 },
{ index: 5, opacity: 0.45 },
{ index: 5, opacity: 0.65 },
{ index: 5, opacity: 0.85 },
{ index: 5, opacity: 0.9 },
{ index: 4, opacity: 0.93 },
{ index: 3, opacity: 0.95 },
{ index: 2, opacity: 0.97 },
{ index: 1, opacity: 0.98 }
];
/**
* Get AntD color palette
*
* @param color - Color
* @param darkTheme - Dark theme
* @param darkThemeMixColor - Dark theme mix color (default: #141414)
*/
export function getAntDColorPalette(color: AnyColor, darkTheme = false, darkThemeMixColor = '#141414'): string[] {
const indexes: ColorIndex[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const patterns = indexes.map(index => getAntDPaletteColorByIndex(color, index));
if (darkTheme) {
const darkPatterns = darkColorMap.map(({ index, opacity }) => {
const darkColor = mixColor(darkThemeMixColor, patterns[index], opacity);
return darkColor;
});
return darkPatterns.map(item => getHex(item));
}
return patterns;
}
/**
* Get hue
*
* @param hsv - Hsv format color
* @param i - The relative distance from 6
* @param isLight - Is light color
*/
function getHue(hsv: HsvColor, i: number, isLight: boolean) {
let hue: number;
const hsvH = Math.round(hsv.h);
if (hsvH >= 60 && hsvH <= 240) {
hue = isLight ? hsvH - hueStep * i : hsvH + hueStep * i;
} else {
hue = isLight ? hsvH + hueStep * i : hsvH - hueStep * i;
}
if (hue < 0) {
hue += 360;
}
if (hue >= 360) {
hue -= 360;
}
return hue;
}
/**
* Get saturation
*
* @param hsv - Hsv format color
* @param i - The relative distance from 6
* @param isLight - Is light color
*/
function getSaturation(hsv: HsvColor, i: number, isLight: boolean) {
if (hsv.h === 0 && hsv.s === 0) {
return hsv.s;
}
let saturation: number;
if (isLight) {
saturation = hsv.s - saturationStep * i;
} else if (i === darkColorCount) {
saturation = hsv.s + saturationStep;
} else {
saturation = hsv.s + saturationStep2 * i;
}
if (saturation > 100) {
saturation = 100;
}
if (isLight && i === lightColorCount && saturation > 10) {
saturation = 10;
}
if (saturation < 6) {
saturation = 6;
}
return saturation;
}
/**
* Get value of hsv
*
* @param hsv - Hsv format color
* @param i - The relative distance from 6
* @param isLight - Is light color
*/
function getValue(hsv: HsvColor, i: number, isLight: boolean) {
let value: number;
if (isLight) {
value = hsv.v + brightnessStep1 * i;
} else {
value = hsv.v - brightnessStep2 * i;
}
if (value > 100) {
value = 100;
}
return value;
}

View File

@ -0,0 +1,45 @@
import type { AnyColor } from 'colord';
import { getHex } from '../shared';
import type { ColorPaletteNumber } from '../types';
import { getRecommendedColorPalette } from './recommend';
import { getAntDColorPalette } from './antd';
/**
* get color palette by provided color
*
* @param color
* @param recommended whether to get recommended color palette (the provided color may not be the main color)
*/
export function getColorPalette(color: AnyColor, recommended = false) {
const colorMap = new Map<ColorPaletteNumber, string>();
if (recommended) {
const colorPalette = getRecommendedColorPalette(getHex(color));
colorPalette.palettes.forEach(palette => {
colorMap.set(palette.number, palette.hex);
});
} else {
const colors = getAntDColorPalette(color);
const colorNumbers: ColorPaletteNumber[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
colorNumbers.forEach((number, index) => {
colorMap.set(number, colors[index]);
});
}
return colorMap;
}
/**
* get color palette color by number
*
* @param color the provided color
* @param number the color palette number
* @param recommended whether to get recommended color palette (the provided color may not be the main color)
*/
export function getPaletteColorByNumber(color: AnyColor, number: ColorPaletteNumber, recommended = false) {
const colorMap = getColorPalette(color, recommended);
return colorMap.get(number as ColorPaletteNumber)!;
}

View File

@ -0,0 +1,152 @@
import { getColorName, getDeltaE, getHsl, isValidColor, transformHslToHex } from '../shared';
import { colorPalettes } from '../constant';
import type {
ColorPalette,
ColorPaletteFamily,
ColorPaletteFamilyWithNearestPalette,
ColorPaletteMatch,
ColorPaletteNumber
} from '../types';
/**
* get recommended color palette by provided color
*
* @param color the provided color
*/
export function getRecommendedColorPalette(color: string) {
const colorPaletteFamily = getRecommendedColorPaletteFamily(color);
const colorMap = new Map<ColorPaletteNumber, ColorPalette>();
colorPaletteFamily.palettes.forEach(palette => {
colorMap.set(palette.number, palette);
});
const mainColor = colorMap.get(500)!;
const matchColor = colorPaletteFamily.palettes.find(palette => palette.hex === color)!;
const colorPalette: ColorPaletteMatch = {
...colorPaletteFamily,
colorMap,
main: mainColor,
match: matchColor
};
return colorPalette;
}
/**
* get recommended palette color by provided color
*
* @param color the provided color
* @param number the color palette number
*/
export function getRecommendedPaletteColorByNumber(color: string, number: ColorPaletteNumber) {
const colorPalette = getRecommendedColorPalette(color);
const { hex } = colorPalette.colorMap.get(number)!;
return hex;
}
/**
* get color palette family by provided color and color name
*
* @param color the provided color
*/
export function getRecommendedColorPaletteFamily(color: string) {
if (!isValidColor(color)) {
throw new Error('Invalid color, please check color value!');
}
let colorName = getColorName(color);
colorName = colorName.toLowerCase().replace(/\s/g, '-');
const { h: h1, s: s1 } = getHsl(color);
const { nearestLightnessPalette, palettes } = getNearestColorPaletteFamily(color, colorPalettes);
const { number, hex } = nearestLightnessPalette;
const { h: h2, s: s2 } = getHsl(hex);
const deltaH = h1 - h2;
const sRatio = s1 / s2;
const colorPaletteFamily: ColorPaletteFamily = {
name: colorName,
palettes: palettes.map(palette => {
let hexValue = color;
const isSame = number === palette.number;
if (!isSame) {
const { h: h3, s: s3, l } = getHsl(palette.hex);
const newH = deltaH < 0 ? h3 + deltaH : h3 - deltaH;
const newS = s3 * sRatio;
hexValue = transformHslToHex({
h: newH,
s: newS,
l
});
}
return {
hex: hexValue,
number: palette.number
};
})
};
return colorPaletteFamily;
}
/**
* get nearest color palette family
*
* @param color color
* @param families color palette families
*/
function getNearestColorPaletteFamily(color: string, families: ColorPaletteFamily[]) {
const familyWithConfig = families.map(family => {
const palettes = family.palettes.map(palette => {
return {
...palette,
delta: getDeltaE(color, palette.hex)
};
});
const nearestPalette = palettes.reduce((prev, curr) => (prev.delta < curr.delta ? prev : curr));
return {
...family,
palettes,
nearestPalette
};
});
const nearestPaletteFamily = familyWithConfig.reduce((prev, curr) =>
prev.nearestPalette.delta < curr.nearestPalette.delta ? prev : curr
);
const { l } = getHsl(color);
const paletteFamily: ColorPaletteFamilyWithNearestPalette = {
...nearestPaletteFamily,
nearestLightnessPalette: nearestPaletteFamily.palettes.reduce((prev, curr) => {
const { l: prevLightness } = getHsl(prev.hex);
const { l: currLightness } = getHsl(curr.hex);
const deltaPrev = Math.abs(prevLightness - l);
const deltaCurr = Math.abs(currLightness - l);
return deltaPrev < deltaCurr ? prev : curr;
})
};
return paletteFamily;
}

View File

@ -0,0 +1,93 @@
import { colord, extend } from 'colord';
import namesPlugin from 'colord/plugins/names';
import mixPlugin from 'colord/plugins/mix';
import labPlugin from 'colord/plugins/lab';
import type { AnyColor, HslColor, RgbColor } from 'colord';
extend([namesPlugin, mixPlugin, labPlugin]);
export function isValidColor(color: AnyColor) {
return colord(color).isValid();
}
export function getHex(color: AnyColor) {
return colord(color).toHex();
}
export function getRgb(color: AnyColor) {
return colord(color).toRgb();
}
export function getHsl(color: AnyColor) {
return colord(color).toHsl();
}
export function getHsv(color: AnyColor) {
return colord(color).toHsv();
}
export function getDeltaE(color1: AnyColor, color2: AnyColor) {
return colord(color1).delta(color2);
}
export function transformHslToHex(color: HslColor) {
return colord(color).toHex();
}
/**
* Add color alpha
*
* @param color - Color
* @param alpha - Alpha (0 - 1)
*/
export function addColorAlpha(color: AnyColor, alpha: number) {
return colord(color).alpha(alpha).toHex();
}
/**
* Mix color
*
* @param firstColor - First color
* @param secondColor - Second color
* @param ratio - The ratio of the second color (0 - 1)
*/
export function mixColor(firstColor: AnyColor, secondColor: AnyColor, ratio: number) {
return colord(firstColor).mix(secondColor, ratio).toHex();
}
/**
* Transform color with opacity to similar color without opacity
*
* @param color - Color
* @param alpha - Alpha (0 - 1)
* @param bgColor Background color (usually white or black)
*/
export function transformColorWithOpacity(color: AnyColor, alpha: number, bgColor = '#ffffff') {
const originColor = addColorAlpha(color, alpha);
const { r: oR, g: oG, b: oB } = colord(originColor).toRgb();
const { r: bgR, g: bgG, b: bgB } = colord(bgColor).toRgb();
function calRgb(or: number, bg: number, al: number) {
return bg + (or - bg) * al;
}
const resultRgb: RgbColor = {
r: calRgb(oR, bgR, alpha),
g: calRgb(oG, bgG, alpha),
b: calRgb(oB, bgB, alpha)
};
return colord(resultRgb).toHex();
}
/**
* Is white color
*
* @param color - Color
*/
export function isWhiteColor(color: AnyColor) {
return colord(color).isEqual('#ffffff');
}
export { colord };

View File

@ -0,0 +1,2 @@
export * from './colord';
export * from './name';

View File

@ -0,0 +1,49 @@
import { colorNames } from '../constant';
import { getHex, getHsl, getRgb } from './colord';
/**
* Get color name
*
* @param color
*/
export function getColorName(color: string) {
const hex = getHex(color);
const rgb = getRgb(color);
const hsl = getHsl(color);
let ndf = 0;
let ndf1 = 0;
let ndf2 = 0;
let cl = -1;
let df = -1;
let name = '';
colorNames.some((item, index) => {
const [hexValue, colorName] = item;
const match = hex === hexValue;
if (match) {
name = colorName;
} else {
const { r, g, b } = getRgb(hexValue);
const { h, s, l } = getHsl(hexValue);
ndf1 = (rgb.r - r) ** 2 + (rgb.g - g) ** 2 + (rgb.b - b) ** 2;
ndf2 = (hsl.h - h) ** 2 + (hsl.s - s) ** 2 + (hsl.l - l) ** 2;
ndf = ndf1 + ndf2 * 2;
if (df < 0 || df > ndf) {
df = ndf;
cl = index;
}
}
return match;
});
name = colorNames[cl][1];
return name;
}

View File

@ -0,0 +1,58 @@
/**
* the color palette number
*
* the main color number is 500
*/
export type ColorPaletteNumber = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950;
/** the color palette */
export type ColorPalette = {
/** the color hex value */
hex: string;
/**
* the color number
*
* - 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950
*/
number: ColorPaletteNumber;
};
/** the color palette family */
export type ColorPaletteFamily = {
/** the color palette family name */
name: string;
/** the color palettes */
palettes: ColorPalette[];
};
/** the color palette with delta */
export type ColorPaletteWithDelta = ColorPalette & {
delta: number;
};
/** the color palette family with nearest palette */
export type ColorPaletteFamilyWithNearestPalette = ColorPaletteFamily & {
nearestPalette: ColorPaletteWithDelta;
nearestLightnessPalette: ColorPaletteWithDelta;
};
/** the color palette match */
export type ColorPaletteMatch = ColorPaletteFamily & {
/** the color map of the palette */
colorMap: Map<ColorPaletteNumber, ColorPalette>;
/**
* the main color of the palette
*
* which number is 500
*/
main: ColorPalette;
/** the match color of the palette */
match: ColorPalette;
};
/**
* The color index of color palette
*
* From left to right, the color is from light to dark, 6 is main color
*/
export type ColorIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ESNext",
"jsx": "preserve",
"lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext",
"moduleResolution": "node",
"resolveJsonModule": true,
"types": ["node"],
"strict": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}