You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			218 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			218 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
import styled, { css, keyframes } from 'styled-components';
 | 
						|
 | 
						|
import { memo } from 'react';
 | 
						|
import { icons, SessionIconSize, SessionIconType } from '.';
 | 
						|
 | 
						|
export type SessionIconProps = {
 | 
						|
  iconType: SessionIconType;
 | 
						|
  iconSize: SessionIconSize | number;
 | 
						|
  iconColor?: string;
 | 
						|
  iconRotation?: number;
 | 
						|
  iconPadding?: string;
 | 
						|
  rotateDuration?: number;
 | 
						|
  glowDuration?: number;
 | 
						|
  borderRadius?: string;
 | 
						|
  glowStartDelay?: number;
 | 
						|
  noScale?: boolean;
 | 
						|
  backgroundColor?: string;
 | 
						|
  dataTestId?: string;
 | 
						|
};
 | 
						|
 | 
						|
const getIconDimensionFromIconSize = (iconSize: SessionIconSize | number) => {
 | 
						|
  if (typeof iconSize === 'number') {
 | 
						|
    return iconSize;
 | 
						|
  }
 | 
						|
  switch (iconSize) {
 | 
						|
    case 'tiny':
 | 
						|
      return 12;
 | 
						|
    case 'small':
 | 
						|
      return 15;
 | 
						|
    case 'medium':
 | 
						|
      return 20;
 | 
						|
    case 'large':
 | 
						|
      return 25;
 | 
						|
    case 'huge':
 | 
						|
      return 30;
 | 
						|
    case 'huge2':
 | 
						|
      return 40;
 | 
						|
    case 'max':
 | 
						|
      return 80;
 | 
						|
    default:
 | 
						|
      return 20;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
type StyledSvgProps = {
 | 
						|
  width: string | number;
 | 
						|
  height: string | number;
 | 
						|
  iconRotation: number;
 | 
						|
  rotateDuration?: number;
 | 
						|
  borderRadius?: string;
 | 
						|
  iconPadding?: string;
 | 
						|
  glowDuration?: number;
 | 
						|
  glowStartDelay?: number;
 | 
						|
  noScale?: boolean;
 | 
						|
  iconColor?: string;
 | 
						|
  backgroundColor?: string;
 | 
						|
};
 | 
						|
 | 
						|
const rotate = keyframes`
 | 
						|
  from {
 | 
						|
    transform: rotate(0deg);
 | 
						|
  }
 | 
						|
  to {
 | 
						|
    transform: rotate(360deg);
 | 
						|
  }
 | 
						|
`;
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates a glow animation made for multiple element sequentially
 | 
						|
 */
 | 
						|
const glow = (color: string, glowDuration: number, glowStartDelay: number) => {
 | 
						|
  // increase shadow intensity by 3
 | 
						|
  const dropShadow = `drop-shadow(0px 0px 6px ${color});`;
 | 
						|
 | 
						|
  // creating keyframe for sequential animations
 | 
						|
  let kf = '';
 | 
						|
  const durationWithLoop = glowDuration + 1;
 | 
						|
  for (let i = 0; i <= durationWithLoop; i++) {
 | 
						|
    const percent = (100 / durationWithLoop) * i;
 | 
						|
 | 
						|
    if (i === glowStartDelay + 1) {
 | 
						|
      kf += `${percent}% {
 | 
						|
        filter: ${dropShadow}
 | 
						|
        transform: scale(1.1);
 | 
						|
      }`;
 | 
						|
    } else {
 | 
						|
      kf += `${percent}% {
 | 
						|
        filter: none;
 | 
						|
        transform: scale(0.9);
 | 
						|
      }`;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return keyframes`${kf}`;
 | 
						|
};
 | 
						|
 | 
						|
const animation = (props: {
 | 
						|
  rotateDuration?: number;
 | 
						|
  glowDuration?: number;
 | 
						|
  glowStartDelay?: number;
 | 
						|
  iconColor?: string;
 | 
						|
  noScale?: boolean;
 | 
						|
}) => {
 | 
						|
  if (props.rotateDuration) {
 | 
						|
    return css`
 | 
						|
      animation: ${rotate} ${props.rotateDuration}s linear infinite;
 | 
						|
    `;
 | 
						|
  }
 | 
						|
  if (props.noScale) {
 | 
						|
    return css``;
 | 
						|
  }
 | 
						|
 | 
						|
  if (props.glowDuration !== undefined && props.glowStartDelay !== undefined && props.iconColor) {
 | 
						|
    return css`
 | 
						|
      animation: ${glow(props.iconColor, props.glowDuration, props.glowStartDelay)}
 | 
						|
        ${props.glowDuration}s ease infinite;
 | 
						|
    `;
 | 
						|
  }
 | 
						|
  return undefined;
 | 
						|
};
 | 
						|
 | 
						|
const Svg = memo(styled.svg<StyledSvgProps>`
 | 
						|
  width: ${props => props.width};
 | 
						|
  transform: ${props => `rotate(${props.iconRotation}deg)`};
 | 
						|
  ${props => animation(props)};
 | 
						|
  border-radius: ${props => props.borderRadius};
 | 
						|
  background-color: ${props =>
 | 
						|
    props.backgroundColor ? props.backgroundColor : '--button-icon-background-color'};
 | 
						|
  border-radius: ${props => (props.borderRadius ? props.borderRadius : '')};
 | 
						|
  filter: ${props => (props.noScale ? `drop-shadow(0px 0px 4px ${props.iconColor})` : '')};
 | 
						|
  fill: ${props => (props.iconColor ? props.iconColor : '--button-icon-stroke-color')};
 | 
						|
  padding: ${props => (props.iconPadding ? props.iconPadding : '')};
 | 
						|
  transition: inherit;
 | 
						|
`);
 | 
						|
 | 
						|
const SessionSvg = (props: {
 | 
						|
  viewBox: string;
 | 
						|
  path: string | Array<string>;
 | 
						|
  width: string | number;
 | 
						|
  height: string | number;
 | 
						|
  iconRotation: number;
 | 
						|
  iconColor?: string;
 | 
						|
  rotateDuration?: number;
 | 
						|
  glowDuration?: number;
 | 
						|
  glowStartDelay?: number;
 | 
						|
  noScale?: boolean;
 | 
						|
  borderRadius?: string;
 | 
						|
  backgroundColor?: string;
 | 
						|
  iconPadding?: string;
 | 
						|
  dataTestId?: string;
 | 
						|
}) => {
 | 
						|
  const colorSvg = props.iconColor ? props.iconColor : '--button-icon-stroke-color';
 | 
						|
  const pathArray = props.path instanceof Array ? props.path : [props.path];
 | 
						|
  const propsToPick = {
 | 
						|
    width: props.width,
 | 
						|
    height: props.height,
 | 
						|
    rotateDuration: props.rotateDuration,
 | 
						|
    iconRotation: props.iconRotation,
 | 
						|
    viewBox: props.viewBox,
 | 
						|
    glowDuration: props.glowDuration,
 | 
						|
    glowStartDelay: props.glowStartDelay,
 | 
						|
    iconColor: props.iconColor,
 | 
						|
    noScale: props.noScale,
 | 
						|
    backgroundColor: props.backgroundColor,
 | 
						|
    borderRadius: props.borderRadius,
 | 
						|
    iconPadding: props.iconPadding,
 | 
						|
    dataTestId: props.dataTestId,
 | 
						|
  };
 | 
						|
 | 
						|
  return (
 | 
						|
    <Svg data-testid={props.dataTestId} {...propsToPick}>
 | 
						|
      {pathArray.map((path, index) => {
 | 
						|
        return <path key={index} fill={colorSvg} d={path} />;
 | 
						|
      })}
 | 
						|
    </Svg>
 | 
						|
  );
 | 
						|
};
 | 
						|
 | 
						|
export const SessionIcon = (props: SessionIconProps) => {
 | 
						|
  const {
 | 
						|
    iconType,
 | 
						|
    iconColor,
 | 
						|
    rotateDuration,
 | 
						|
    glowDuration,
 | 
						|
    borderRadius,
 | 
						|
    glowStartDelay,
 | 
						|
    noScale,
 | 
						|
    backgroundColor,
 | 
						|
    iconPadding,
 | 
						|
    dataTestId,
 | 
						|
  } = props;
 | 
						|
  let { iconSize, iconRotation } = props;
 | 
						|
  iconSize = iconSize || 'medium';
 | 
						|
  iconRotation = iconRotation || 0;
 | 
						|
 | 
						|
  const iconDimensions = getIconDimensionFromIconSize(iconSize);
 | 
						|
  const iconDef = icons[iconType];
 | 
						|
  const ratio = iconDef?.ratio || 1;
 | 
						|
 | 
						|
  return (
 | 
						|
    <SessionSvg
 | 
						|
      viewBox={iconDef.viewBox}
 | 
						|
      path={iconDef.path}
 | 
						|
      width={iconDimensions * ratio}
 | 
						|
      height={iconDimensions}
 | 
						|
      rotateDuration={rotateDuration}
 | 
						|
      glowDuration={glowDuration}
 | 
						|
      glowStartDelay={glowStartDelay}
 | 
						|
      noScale={noScale}
 | 
						|
      borderRadius={borderRadius}
 | 
						|
      iconRotation={iconRotation}
 | 
						|
      iconColor={iconColor}
 | 
						|
      backgroundColor={backgroundColor}
 | 
						|
      iconPadding={iconPadding}
 | 
						|
      dataTestId={dataTestId}
 | 
						|
    />
 | 
						|
  );
 | 
						|
};
 |