All files / utils mix-color.ts

100% Statements 26/26
100% Branches 4/4
100% Functions 6/6
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52                9x 181x 181x 181x     9x 9x 115x   9x 60x   9x 30x 30x   30x 30x 30x         30x 30x 30x     30x   30x 67x 268x 201x       67x   67x      
import { mix } from './mix';
import { hsla, rgba, hex, Color } from 'style-value-types';
import { invariant } from 'hey-listen';
 
// Linear color space blending
// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
// Demonstrated http://codepen.io/osublake/pen/xGVVaN
 
export const mixLinearColor = (from: number, to: number, v: number) => {
  const fromExpo = from * from;
  const toExpo = to * to;
  return Math.sqrt(Math.max(0, v * (toExpo - fromExpo) + fromExpo));
};
 
const colorTypes = [hex, rgba, hsla];
const getColorType = (v: Color | string) =>
  colorTypes.find(type => type.test(v));
 
const notAnimatable = (color: Color | string) =>
  `'${color}' is not an animatable color. Use the equivalent color code instead.`;
 
export const mixColor = (from: Color | string, to: Color | string) => {
  const fromColorType = getColorType(from);
  const toColorType = getColorType(to);
 
  invariant(!!fromColorType, notAnimatable(from));
  invariant(!!toColorType, notAnimatable(to));
  invariant(
    fromColorType.transform === toColorType.transform,
    'Both colors must be hex/RGBA, OR both must be HSLA.'
  );
 
  const fromColor = fromColorType.parse(from);
  const toColor = toColorType.parse(to);
  const blended = { ...fromColor };
 
  // Only use the linear blending function for rgba and hex
  const mixFunc = fromColorType === hsla ? mix : mixLinearColor;
 
  return (v: number) => {
    for (const key in blended) {
      if (key !== 'alpha') {
        blended[key] = mixFunc(fromColor[key], toColor[key], v);
      }
    }
 
    blended.alpha = mix(fromColor.alpha, toColor.alpha, v);
 
    return fromColorType.transform(blended);
  };
};