1 | import * as React from 'react';
|
2 | import * as PropTypes from 'prop-types';
|
3 |
|
4 | import propTypeUtils from 'airbnb-prop-types';
|
5 | import { BoxProps as ReakitBoxProps } from 'reakit/ts';
|
6 |
|
7 | import _get from 'lodash/get';
|
8 |
|
9 | import { withTheme } from '../styled';
|
10 | import parseIcons, { ParsedIcon, Opts as ParseIconOpts } from '../parseIcons';
|
11 | import { Omit, Size, sizePropType } from '../types';
|
12 | import _Icon from './styled';
|
13 |
|
14 | export type Props = {
|
15 | children?: React.ReactNode;
|
16 |
|
17 | color?: string;
|
18 | className?: string;
|
19 |
|
20 | icon: string | ParsedIcon;
|
21 |
|
22 | size?: string;
|
23 | theme?: Object;
|
24 | type?: ParseIconOpts['type'];
|
25 | };
|
26 | export type PropsWithA11yHidden = Props & {
|
27 |
|
28 | a11yHidden: boolean;
|
29 | };
|
30 | export type PropsWithA11yLabel = Props & {
|
31 |
|
32 | a11yLabel: string;
|
33 | };
|
34 | export type LocalIconProps = PropsWithA11yHidden | PropsWithA11yLabel;
|
35 | export type IconProps = Omit<ReakitBoxProps, 'size'> & LocalIconProps;
|
36 |
|
37 | export const Icon: React.FunctionComponent<LocalIconProps> = ({
|
38 |
|
39 | a11yHidden,
|
40 |
|
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 |
|
53 | let iconInfo = icons[newIcon];
|
54 | if (type) {
|
55 |
|
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 |
|
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 |
|
80 | export const iconPropTypes = {
|
81 | a11yHidden: propTypeUtils.mutuallyExclusiveProps(PropTypes.bool, 'a11yHidden', 'a11yLabel'),
|
82 | a11yLabel: propTypeUtils.mutuallyExclusiveProps(PropTypes.string, 'a11yHidden', 'a11yLabel'),
|
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,
|
96 | type: PropTypes.oneOf(['font-awesome', 'font-awesome-standalone']) as PropTypes.Validator<LocalIconProps['type']>
|
97 | };
|
98 | Icon.propTypes = iconPropTypes;
|
99 |
|
100 | export const iconDefaultProps = {
|
101 | children: null,
|
102 | className: undefined,
|
103 | color: undefined,
|
104 | icon: undefined,
|
105 | size: 'default',
|
106 | type: undefined
|
107 | };
|
108 | Icon.defaultProps = iconDefaultProps;
|
109 |
|
110 |
|
111 | const C: React.FunctionComponent<IconProps> = withTheme(Icon);
|
112 | export default C;
|