import classNames from "classnames"; import * as React from "react"; import { IconName, IconSvgPaths16, IconSvgPaths20 } from "reui-icons"; import { Classes, DISPLAYNAME_PREFIX, IIntentProps, IProps } from "../../common"; export { IconName }; export interface IIconProps extends IIntentProps, IProps { /** This component does not support custom children. Use the `icon` prop. */ children?: never; /** * Color of icon. Equivalent to setting CSS `fill` property. */ color?: string; /** * Name of a Blueprint UI icon, or an icon element, to render. * This prop is required because it determines the content of the component, but it can * be explicitly set to falsy values to render nothing. * * - If `null` or `undefined` or `false`, this component will render nothing. * - If given an `IconName` (a string literal union of all icon names), * that icon will be rendered as an `` with `` tags. * - If given a `JSX.Element`, that element will be rendered and _all other props on this component are ignored._ * This type is supported to simplify usage of this component in other Blueprint components. * As a consumer, you should never use `}` directly; simply render `` instead. */ icon: IconName | JSX.Element | false | null | undefined; /** * Size of the icon, in pixels. * Blueprint contains 16px and 20px SVG icon images, * and chooses the appropriate resolution based on this prop. * @default Icon.SIZE_STANDARD = 16 */ iconSize?: number; /** CSS style properties. */ style?: React.CSSProperties; /** * Description string. This string does not appear in normal browsers, but * it increases accessibility. For instance, screen readers will use it for * aural feedback. By default, this is set to the icon's name for * accessibility. */ title?: string | false | null; } export class Icon extends React.PureComponent> { public static displayName = `${DISPLAYNAME_PREFIX}.Icon`; public static readonly SIZE_STANDARD = 16; public static readonly SIZE_LARGE = 20; public render() { const { className, color, icon, iconSize = Icon.SIZE_STANDARD, intent, title = icon, ...svgProps } = this.props; if (icon == null) { return null; } else if (typeof icon !== "string") { return icon; } // choose which pixel grid is most appropriate for given icon size const pixelGridSize = iconSize >= Icon.SIZE_LARGE ? Icon.SIZE_LARGE : Icon.SIZE_STANDARD; const paths = this.renderSvgPaths(pixelGridSize, icon); if (paths == null) { return null; } const classes = classNames(Classes.ICON, Classes.intentClass(intent), className); const viewBox = `0 0 ${pixelGridSize} ${pixelGridSize}`; // ICON class will apply a "fill" CSS style, so we need to inject an inline style to override it let { style = {} } = this.props; if (color != null) { style = { ...style, fill: color }; } return ( {title && {title}} {paths} ); } private renderSvgPaths(pathsSize: number, iconName: IconName) { const svgPathsRecord = pathsSize === Icon.SIZE_STANDARD ? IconSvgPaths16 : IconSvgPaths20; const pathStrings = svgPathsRecord[iconName]; if (pathStrings == null) { return null; } return pathStrings.map((d, i) => ); } }