| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- import { strings } from './constants';
- // type ColorType = 'Hex' | 'Hsl' | 'Hsla' | 'Rgb' | 'Rgba' | 'Semi Design Tokens';
- type Generate = {
- startColor: string;
- endColor: string;
- size: number
- };
- type StrokeSet = { percent: number; color: string };
- type StrokeArr = Array<StrokeSet>;
- function generateColor(s: StrokeArr, percent: number, gradient: boolean): string | undefined {
- try {
- const gradientColorArr = generate(s, percent, gradient);
- if (gradientColorArr.length !== 0) return gradientColorArr;
- } catch (e) {
- return undefined;
- }
- return undefined;
- }
- function generate(s: StrokeArr, percent: number, gradient: boolean): string | undefined {
- s.sort((a, b) => a.percent - b.percent);
- if (s[0].percent > percent) {
- return strings.STROKE_DEFAULT;
- }
- const endS = s[s.length - 1];
- if (endS.percent < percent) {
- return formatToHex(endS.color);
- }
- for (const [index, item] of s.entries()) {
- if (item.percent === percent) {
- return formatToHex(item.color);
- }
- if (percent > item.percent) continue;
- const oldItem = s[index - 1];
- if (!gradient) {
- return formatToHex(oldItem.color);
- }
- return generateGradients(
- {
- startColor: formatToHex(oldItem.color),
- endColor: formatToHex(item.color),
- size: item.percent - oldItem.percent - 1,
- },
- percent - oldItem.percent - 1
- ) as string;
- }
- return undefined;
- }
- function generateGradients(g: Generate, index: number | undefined): Array<string> | string {
- const { startColor, endColor, size } = g;
- const sA = startColor.split('');
- const eA = endColor.split('');
- const rC = [parseInt(`${sA[1]}${sA[2]}`, 16), parseInt(`${eA[1]}${eA[2]}`, 16)];
- const gC = [parseInt(`${sA[3]}${sA[4]}`, 16), parseInt(`${eA[3]}${eA[4]}`, 16)];
- const bC = [parseInt(`${sA[5]}${sA[6]}`, 16), parseInt(`${eA[5]}${eA[6]}`, 16)];
- const aC = [parseInt(`${sA[7]}${sA[8]}`, 16), parseInt(`${eA[7]}${eA[8]}`, 16)];
- const rStep = (rC[0] - rC[1]) / (size + 1);
- const gStep = (gC[0] - gC[1]) / (size + 1);
- const bStep = (bC[0] - bC[1]) / (size + 1);
- const aStep = (aC[0] - aC[1]) / (size + 1);
- function tHex(i: number) {
- const rS = Math.round(rC[0] - rStep * (i + 1)).toString(16);
- const gS = Math.round(gC[0] - gStep * (i + 1)).toString(16);
- const bS = Math.round(bC[0] - bStep * (i + 1)).toString(16);
- const h = `${padTwo(rS)}${padTwo(gS)}${padTwo(bS)}`;
- const t = Math.floor(aStep * (i + 1) + aC[1]).toString(16);
- return toHex.Hex(`#${h}`, t);
- }
- function padTwo(s: string) {
- if (s.length === 1) {
- return `0${s}`;
- }
- if (s.length === 0) {
- return '00';
- }
- return s;
- }
- if (typeof index === 'undefined') {
- const gradientColorArr = [startColor];
- for (let i = 0; i < size; i += 1) {
- gradientColorArr.push(tHex(i));
- }
- return gradientColorArr;
- }
- return tHex(index);
- }
- // Resolve the colour type contained within `ColorType` to Hex
- function formatToHex(color: string): string | undefined {
- color = color.trim().toLowerCase();
- // Hex
- if (REG_S.hex.test(color)) {
- return toHex.Hex(color, undefined);
- }
- // Hsl or Hsla
- if (REG_S.hslA.test(color)) {
- return toHex.Hex(toHex.HslA(color), undefined);
- }
- // Rgb or Rgba
- if (REG_S.rgbA.test(color)) {
- return toHex.Hex(toHex.RgbA(color), undefined);
- }
- // Semi Design Tokens
- if (REG_S.semiDesignTokens.test(color)) {
- if (SEMI_DESIGN_TOKENS.ALONG.indexOf(color) !== -1) {
- return toHex.SemiDesignToken(color);
- }
- if (SEMI_DESIGN_TOKENS.SEQUENCE.indexOf(color) !== -1) {
- return toHex.SemiDesignToken(`${color}-5`);
- }
- return toHex.SemiDesignToken(`${color}`);
- }
- return undefined;
- }
- const toHex = {
- Hex(color: string, transparency: string | undefined): string {
- color = color.replace('#', '');
- if (color.length === 8) return `#${color}`;
- if (color.length === 6) return `#${color}${transparency || 'ff'}`;
- if (color.length === 3) {
- color = color
- .split('')
- .map(c => c + c)
- .join('');
- }
- return `#${color}${transparency || 'ff'}`;
- },
- SemiDesignToken(color: string): string | undefined {
- // ! Only produces effects when used, the conditions for running need to occur after the real DOM is rendered
- if (typeof window === 'undefined') {
- return undefined;
- }
- const variable = getComputedStyle(document.body).getPropertyValue(`--semi-${color}`);
- if (variable === '') return undefined;
- const rgba = `rgba(${variable}, 1)`;
- return toHex.RgbA(rgba);
- },
- HslA(color: string): string {
- const hsla = REG_S.hslA.exec(color);
- const h = parseInt(hsla[2]);
- const s = parseInt(hsla[3]) / 100;
- const l = parseInt(hsla[4]) / 100;
- const a = hsla[5];
- const c = (1 - Math.abs(2 * l - 1)) * s,
- x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
- m = l - c / 2;
- let r: string | number = 0,
- g: string | number = 0,
- b: string | number = 0;
- if (0 <= h && h < 60) {
- r = c;
- g = x;
- b = 0;
- } else if (60 <= h && h < 120) {
- r = x;
- g = c;
- b = 0;
- } else if (120 <= h && h < 180) {
- r = 0;
- g = c;
- b = x;
- } else if (180 <= h && h < 240) {
- r = 0;
- g = x;
- b = c;
- } else if (240 <= h && h < 300) {
- r = x;
- g = 0;
- b = c;
- } else if (300 <= h && h < 360) {
- r = c;
- g = 0;
- b = x;
- }
- r = Math.round((r + m) * 255).toString(16);
- g = Math.round((g + m) * 255).toString(16);
- b = Math.round((b + m) * 255).toString(16);
- return toHex.utils.pAL(r, g, b, a);
- },
- RgbA(color: string): string {
- const rgba = REG_S.rgbA.exec(color);
- const r = parseInt(rgba[2], 10).toString(16),
- g = parseInt(rgba[3], 10).toString(16),
- b = parseInt(rgba[4], 10).toString(16),
- a = rgba[5];
- return toHex.utils.pAL(r, g, b, a);
- },
- utils: {
- pAL(r: string, g: string, b: string, a: string) {
- if (r.length == 1) r = '0' + r;
- if (g.length == 1) g = '0' + g;
- if (b.length == 1) b = '0' + b;
- if (typeof a !== 'undefined') {
- a = Math.round(parseInt(a) * 255).toString(16);
- if (a.length == 1) a = '0' + a;
- return '#' + r + g + b + a;
- }
- return '#' + r + g + b;
- },
- },
- };
- const REG_S = {
- hex: /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,
- hslA: /(hsl)a?\(\s*?(\d+),?\s*?(\d+)%,?\s*?(\d+)%,?\s*?\/?(\s*?[\d.]+)?\s*?\)/,
- rgbA: /(rgb)a?\(\s*?(\d+),?\s*?(\d+),?\s*?(\d+),?\s*?\/?(\s*?[\d.]+)?\s*?\)/,
- semiDesignTokens: /(\w+)?-?(\w+)-?(\d)?/,
- };
- // From src/components/palette.js
- const SEMI_DESIGN_TOKENS = {
- // No sequence
- ALONG: ["black", "white"],
- // Sequence: 0-9
- SEQUENCE: [
- "amber",
- "blue",
- "cyan",
- "green",
- "grey",
- "indigo",
- "light-blue",
- "light-green",
- "lime",
- "orange",
- "pink",
- "purple",
- "red",
- "teal",
- "violet",
- "yellow"
- ]
- };
- export { generateColor, StrokeArr };
|