UNPKG

3.56 kBTypeScriptView Raw
1import * as React from 'react';
2import * as PropTypes from 'prop-types';
3// @ts-ignore
4import propTypeUtils from 'airbnb-prop-types';
5import { BoxProps as ReakitBoxProps } from 'reakit/ts';
6// @ts-ignore
7import _get from 'lodash/get';
8
9import { withTheme } from '../styled';
10import parseIcons, { ParsedIcon, Opts as ParseIconOpts } from '../parseIcons';
11import { Omit, Size, sizePropType } from '../types';
12import _Icon from './styled';
13
14export type Props = {
15 children?: React.ReactNode;
16 /** Color of the icon. Can be a color from the palette, or any other color. */
17 color?: string;
18 className?: string;
19 /** The name of your icon from the free Font Awesome Icon Set (https://fontawesome.com/icons?d=gallery&m=free). */
20 icon: string | ParsedIcon;
21 /** Size of the icon. */
22 size?: string;
23 theme?: Object;
24 type?: ParseIconOpts['type'];
25};
26export type PropsWithA11yHidden = Props & {
27 /** Indicates that this element should be skipped by assistive technologies. */
28 a11yHidden: boolean;
29};
30export type PropsWithA11yLabel = Props & {
31 /** A label for the icon which can be read by screen readers. This is required if a11yHidden is false. */
32 a11yLabel: string;
33};
34export type LocalIconProps = PropsWithA11yHidden | PropsWithA11yLabel;
35export type IconProps = Omit<ReakitBoxProps, 'size'> & LocalIconProps;
36
37export const Icon: React.FunctionComponent<LocalIconProps> = ({
38 // @ts-ignore
39 a11yHidden,
40 // @ts-ignore
41 a11yLabel,
42 children,
43 icon,
44 size: _size,
45 theme,
46 type,
47 ...props
48}) => {
49 const size = _get(theme, `fannypack.fontSizes[${_size || ''}]`, 1);
50 const newIcon = _get(theme, `fannypack.Icon.iconNames[${icon}]`) || icon;
51 const icons = _get(theme, `fannypack.Icon.icons`, {});
52 // @ts-ignore
53 let iconInfo = icons[newIcon];
54 if (type) {
55 // @ts-ignore
56 const parsedIcons = parseIcons([icon], { type });
57 iconInfo = Object.entries(parsedIcons)[0][1];
58 } else if (typeof icon === 'object') {
59 iconInfo = icon;
60 }
61 const { viewBoxWidth, viewBoxHeight, paths } = iconInfo;
62 return (
63 // @ts-ignore
64 <_Icon
65 use="svg"
66 aria-hidden={a11yHidden}
67 role="img"
68 size={size}
69 viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
70 {...props}
71 >
72 {a11yLabel && <title>{a11yLabel}</title>}
73 {paths.map((path: string) => (
74 <path key={path} d={path} fill="currentColor" fillRule="evenodd" />
75 ))}
76 </_Icon>
77 );
78};
79
80export const iconPropTypes = {
81 a11yHidden: propTypeUtils.mutuallyExclusiveProps(PropTypes.bool, 'a11yHidden', 'a11yLabel'), // eslint-disable-line
82 a11yLabel: propTypeUtils.mutuallyExclusiveProps(PropTypes.string, 'a11yHidden', 'a11yLabel'), // eslint-disable-line
83 children: PropTypes.node,
84 color: PropTypes.string,
85 className: PropTypes.string,
86 icon: PropTypes.oneOfType([
87 PropTypes.string,
88 PropTypes.shape({
89 viewBoxHeight: PropTypes.number,
90 viewBoxWidth: PropTypes.number,
91 paths: PropTypes.arrayOf(PropTypes.string)
92 })
93 ]) as PropTypes.Validator<LocalIconProps['icon']>,
94 size: PropTypes.string,
95 theme: PropTypes.object, // eslint-disable-line
96 type: PropTypes.oneOf(['font-awesome', 'font-awesome-standalone']) as PropTypes.Validator<LocalIconProps['type']>
97};
98Icon.propTypes = iconPropTypes;
99
100export const iconDefaultProps = {
101 children: null,
102 className: undefined,
103 color: undefined,
104 icon: undefined,
105 size: 'default',
106 type: undefined
107};
108Icon.defaultProps = iconDefaultProps;
109
110// @ts-ignore
111const C: React.FunctionComponent<IconProps> = withTheme(Icon);
112export default C;