All files / components/Icon Icon.jsx

100% Statements 7/7
75% Branches 3/4
100% Functions 0/0
100% Lines 7/7
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          120x               120x                 120x                                                                                             240x                                         116x         116x         116x                                          
import _ from 'lodash';
import React from 'react';
import { lucidClassNames } from '../../util/style-helpers';
import { createClass, omitProps } from '../../util/component-types';
 
const cx = lucidClassNames.bind('&-Icon');
 
const {
	any,
	string,
	number,
	object,
	bool,
} = React.PropTypes;
 
/**
 *
 * {"categories": ["visual design", "icons"]}
 *
 * A basic svg icon. Any props that are not explicitly called out below will be
 * passed through to the native `svg` component.
 */
const Icon = createClass({
	displayName: 'Icon',
	propTypes: {
		/**
		 * Styles that are passed through to the `svg`.
		 */
		style: object,
		/**
		 * Classes that are appended to the component defaults. This prop is run
		 * through the `classnames` library.
		 */
		className: any,
		/**
		 * Size variations of the icons. `size` directly effects height and width
		 * but the developer should also be conscious of the relationship with
		 * `viewBox`.
		 */
		size: number,
		/**
		 * `viewBox` is very important for SVGs. You can think of `viewBox` as the
		 * "artboard" for our SVG while `size` is the presented height and width.
		 */
		viewBox: string,
		/**
		 * Any valid SVG aspect ratio.
		 */
		aspectRatio: string,
		/**
		 * Add badge styling.
		 */
		isBadge: bool,
		/**
		 * Adds styling that makes the icon appear clickable.
		 */
		isClickable: bool,
		/**
		 * Adds styling that makes the icon appear disabled.
		 * Also forces isClickable to be false.
		 */
		isDisabled: bool,
		/**
		 * Any valid React children.
		 */
		children: any,
	},
 
	getDefaultProps() {
		return {
			size: 16,
			aspectRatio: 'xMidYMid meet',
			viewBox: '0 0 16 16',
			isBadge: false,
			isDisabled: false,
		};
	},
 
	render() {
		const {
			className,
			children,
			size,
			style,
			viewBox,
			aspectRatio,
			isBadge,
			isClickable,
			isDisabled,
			...passThroughs,
		} = this.props;
 
		// Because we control the icon size inline, we must also control the border
		// radius in the case where they user wants `isBadge`. Later one, we filter
		// out any `undefined` properties using lodash methods.
		const actualStyle = {
			...style,
			borderRadius: _.get(style, 'borderRadius', isBadge ? `${size}px` : undefined),
		};
 
		return (
			<svg
				width={size}
				height={size}
				viewBox={viewBox}
				preserveAspectRatio={aspectRatio}
				{...omitProps(passThroughs, Icon)}
				style={_.pickBy(actualStyle, _.negate(_.isUndefined))}
				className={cx('&', {
					'&-is-badge': isBadge,
					'&-is-clickable': !isDisabled && isClickable,
					'&-is-disabled': isDisabled,
				}, className)}
			>
				{children}
			</svg>
		);
	},
});
 
export default Icon;