All files / src/Icon Icon.tsx

100% Statements 18/18
100% Branches 13/13
100% Functions 3/3
100% Lines 18/18

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                                                              35x   663x   663x               663x 663x 663x   663x 663x   1x 1x 662x 1x   663x   663x                 283x                 35x   662x 662x                        
import * as React from 'react';
import { Box as ReakitBox } from 'reakit';
import _get from 'lodash/get';
 
import {
  useClassName,
  createComponent,
  createElement,
  createHook,
  parseIcons,
  useTheme,
  ParsedIcon,
  Opts as ParseIconOpts
} from '../utils';
import { Box, BoxProps } from '../Box';
 
import * as styles from './styles';
 
export type LocalIconProps = {
  /** Color of the icon. Can be a color from the palette, or any other color. */
  color?: string;
  /** The name of your icon or parsed icon. */
  icon?: string | ParsedIcon;
  /** A label for the icon which can be read by screen readers. This is required if a11yHidden is false. */
  label?: string;
  /** Size of the icon. */
  fontSize?: string;
  type?: ParseIconOpts['type'];
};
export type IconProps = BoxProps & LocalIconProps;
 
const useProps = createHook<IconProps>(
  (props, { themeKey, themeKeyOverride }) => {
    const boxProps = Box.useProps(props);
 
    const className = useClassName({
      style: styles.Icon,
      styleProps: props,
      themeKey,
      themeKeyOverride,
      prevClassName: boxProps.className
    });
 
    const theme = useTheme();
    const icon = _get(theme, `Icon.iconNames[${props.icon}]`) || props.icon;
    const icons = _get(theme, `Icon.icons`, {});
 
    let iconInfo = icons[icon];
    if (props.type) {
      // @ts-ignore
      const parsedIcons = parseIcons([props.icon], { type: props.type });
      iconInfo = Object.entries(parsedIcons)[0][1];
    } else if (typeof props.icon === 'object') {
      iconInfo = props.icon;
    }
    const { viewBoxWidth = 0, viewBoxHeight = 0, paths = [] } = iconInfo || {};
 
    return {
      role: 'img',
      viewBox: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
      ...boxProps,
      className,
      children: (
        <React.Fragment>
          {props.label && <title>{props.label}</title>}
          {paths.map((path: string) => (
            <path key={path} d={path} fill="currentColor" fillRule="evenodd" />
          ))}
        </React.Fragment>
      )
    };
  },
  { themeKey: 'Icon' }
);
 
export const Icon = createComponent<IconProps>(
  props => {
    const iconProps = useProps(props);
    return createElement({ children: props.children, component: ReakitBox, use: props.use, htmlProps: iconProps });
  },
  {
    attach: {
      useProps
    },
    defaultProps: {
      use: 'svg'
    },
    themeKey: 'Icon'
  }
);