All files / src/theme/neumorphism styleBuilder.ts

0% Statements 0/128
0% Branches 0/1
0% Functions 0/1
0% Lines 0/128

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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                                                                                                                                                                                                                                                               
import { isValidColor, colorLuminance } from './utils';

export enum NeumorphismShapeType {
  flat = 0,
  pressed = 1,
  concave = 2,
  convex = 3
}
// It seams the angle of shadow
export enum NeumorphismActiveLightSourceType {
  topLeft = 1,
  topRight = 2,
  bottomRight = 3,
  bottomLeft = 4
}
const NEUMORPHISM_SHAPE = NeumorphismShapeType.flat;
const ACTIVE_LIGHT_SOURCE = NeumorphismActiveLightSourceType.topLeft;
const SHADOW_DISTANCE = '20px';
const SHADOW_BLUR = '30px';
export const BORDERRADIUS = 50;

function getActiveLightSource(activeLightSource: NeumorphismActiveLightSourceType, distance: number) {
  switch (activeLightSource) {
    case NeumorphismActiveLightSourceType.topLeft:
      return {
        positionX: distance,
        positionY: distance,
        angle: 145
      };
    case NeumorphismActiveLightSourceType.topRight:
      return {
        positionX: distance * -1,
        positionY: distance,
        angle: 225
      };
    case NeumorphismActiveLightSourceType.bottomRight:
      return {
        positionX: distance * -1,
        positionY: distance * -1,
        angle: 315
      };
    case 4:
      return {
        positionX: distance,
        positionY: distance * -1,
        angle: 45
      };
    default: // NeumorphismActiveLightSourceType.topLeft
      return {
        positionX: distance,
        positionY: distance,
        angle: 145
      };
  }
}

export interface NeumorphismStyleParams {
  color: string // must hexadecimal (means like #FFFFFF)
  neumorphismShape?: NeumorphismShapeType
  activeLightSource?: NeumorphismActiveLightSourceType
  shadowDistance?: string;
  shadowBlur?: string;
  borderRadiusVal?: number;
}
export function getNeumorphismStyle({
  color,
  neumorphismShape = NEUMORPHISM_SHAPE,
  activeLightSource = ACTIVE_LIGHT_SOURCE,
  shadowDistance = SHADOW_DISTANCE,
  shadowBlur = SHADOW_BLUR,
  borderRadiusVal = BORDERRADIUS }: NeumorphismStyleParams) {
  // const
  const maxRadius = 150;
  const colorDifference = 0.15;
  // var
  const shape = neumorphismShape;
  const radius = borderRadiusVal;
  let gradient = false;
  if (shape === 2 || shape === 3) {
    gradient = true;
  }
  const distance = parseInt(shadowDistance.replace('px', ''), 10);
  const { positionX, positionY, angle } = getActiveLightSource(activeLightSource, distance);
  const firstGradientColor = gradient && shape !== 1 ? colorLuminance(color, shape === 3 ? 0.07 : -0.1) : color;
  const secondGradientColor = gradient && shape !== 1 ? colorLuminance(color, shape === 2 ? 0.07 : -0.1) : color;
  const blur = parseInt(shadowBlur.replace('px', ''), 10);
  const darkColor = colorLuminance(color, colorDifference * -1);
  const lightColor = colorLuminance(color, colorDifference);
  // key code
  const borderRadius = radius >= maxRadius ? '50%' : radius + 'px';
  const background = gradient && shape !== 1
    ? `linear-gradient(${angle}deg, ${firstGradientColor}, ${secondGradientColor})`
    : `${color}`;
  const boxShadowPosition = shape === 1 ? 'inset' : '';
  const firstBoxShadow = `${boxShadowPosition} ${positionX}px ${positionY}px ${blur}px ${darkColor}`;
  const secondBoxShadow = `${boxShadowPosition} ${positionX * -1}px ${positionY * -1}px ${blur}px ${lightColor}`;

  const styleObj = {
    borderRadius: borderRadius,
    background: background,
    boxShadow: `${firstBoxShadow},${secondBoxShadow}`
  };

  return styleObj;
}

export default function neumorphismBuild(params: Omit<NeumorphismStyleParams, 'neumorphismShape'>) {
  let result = {};
  if (!isValidColor(params.color)) {
    result = {
      flat: {},
      pressed: {},
      convex: {},
      concave: {}
    };
  }
  const flat = getNeumorphismStyle({ ...params, neumorphismShape: NeumorphismShapeType.flat });
  const pressed = getNeumorphismStyle({ ...params, neumorphismShape: NeumorphismShapeType.pressed });
  const convex = getNeumorphismStyle({ ...params, neumorphismShape: NeumorphismShapeType.convex });
  const concave = getNeumorphismStyle({ ...params, neumorphismShape: NeumorphismShapeType.concave });
  result = {
    flat,
    pressed,
    convex,
    concave
  };
  return result;
}