Skip to content
This repository has been archived by the owner on Mar 31, 2021. It is now read-only.

Commit

Permalink
Add Icon component
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Nov 13, 2018
1 parent 01b7569 commit 6ce8aa5
Show file tree
Hide file tree
Showing 11 changed files with 997 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"contributors:generate": "all-contributors generate"
},
"dependencies": {
"@blueprintjs/icons": "3.3.0",
"classnames": "2.2.6",
"conditional-wrap": "1.0.0",
"lodash": "4.17.11",
Expand Down
57 changes: 57 additions & 0 deletions src/Icon/Icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @flow
import React, { type Node } from 'react';
import { withTheme } from 'reakit/styled';
import { IconSvgPaths16, IconSvgPaths20 } from '@blueprintjs/icons';
import _get from 'lodash/get';

import _Icon from './styled';
import type { Size } from '../types';

type Props = {
/** A label for the icon which can be read by screen readers. This is required! */
a11yLabel: string,
children: Node,
/** Color of the icon. Can be a color from the palette, or any other color. */
color: string,
className?: string,
/** The name of your icon from the Blueprint set (https://blueprintjs.com/docs/#icons). */
icon: string,
/** Size of the icon. Available values: "small", "medium", "large" */
size?: Size,
theme: Object
};

const DEFAULT_VIEW_BOX_SIZE = 16;
const LARGE_VIEW_BOX_SIZE = 20;

export const Icon = ({ a11yLabel, children, icon, size: _size, theme, ...props }: Props) => {
const size = _get(theme, `fannypack.fontSizes[${_size || ''}]`, 1);
const svgPaths = size >= LARGE_VIEW_BOX_SIZE ? IconSvgPaths20 : IconSvgPaths16;
const viewBoxSize = size >= LARGE_VIEW_BOX_SIZE ? LARGE_VIEW_BOX_SIZE : DEFAULT_VIEW_BOX_SIZE;
const paths = svgPaths[icon];
return (
<_Icon
as="svg"
role="img"
height={`${size}em`}
width={`${size}em`}
viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}
{...props}
>
{a11yLabel && <title>{a11yLabel}</title>}
{paths.map(path => (
<path key={path} d={path} fillRule="even-odd" />
))}
</_Icon>
);
};

Icon.defaultProps = {
a11yLabel: undefined,
className: undefined,
color: undefined,
icon: undefined,
size: 'default'
};

export default withTheme(Icon);
76 changes: 76 additions & 0 deletions src/Icon/Icon.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
name: Icon
route: /components/icon
menu: Components
---

import { Playground, PropsTable } from 'docz';
import { Box } from '../primitives/index';
import Icon from './index';
import { Icon as IconProps } from './Icon';
import Text from '../Text';
import Heading from '../Heading';

# Icon

Fannypack uses [Blueprint Icons](https://blueprintjs.com/docs/#icons) for its icons as they provide an extensive and useful set of icons.

## Import

`import { Icon } from 'fannypack'`

## Basic Usage

<Playground>
<Icon a11yLabel="Settings" icon="cog" />
</Playground>

> You can find a list of icon names from the [Blueprint Icons Directory](https://blueprintjs.com/docs/#icons).
## Sizes

Change the size of an icon with the `size` prop.

<Playground>
<Icon a11yLabel="Settings" icon="cog" size="small" />
<Icon a11yLabel="Settings" icon="cog" marginLeft="xxxsmall" />
<Icon a11yLabel="Settings" icon="cog" size="medium" marginLeft="xxxsmall" />
<Icon a11yLabel="Settings" icon="cog" size="large" marginLeft="xxxsmall" />
<Icon a11yLabel="Settings" icon="cog" size="xlarge" marginLeft="xxxsmall" />
<Icon a11yLabel="Settings" icon="cog" size="xxlarge" marginLeft="xxxsmall" />
<Icon a11yLabel="Settings" icon="cog" size="xxxlarge" marginLeft="xxxsmall" />
</Playground>

## Colors

Change the color of an icon with the `color` prop. It can be any color from the [palette](/palette), or any other color like `#ff0000` or `red`.

<Playground>
<Icon a11yLabel="Success" icon="tick-circle" color="success" />
<Icon a11yLabel="Error" icon="error" color="danger" marginLeft="xxxsmall" />
<Icon a11yLabel="Warning" icon="warning-sign" color="warning" marginLeft="xxxsmall" />
<Icon a11yLabel="Copy" icon="clipboard" color="primary" marginLeft="xxxsmall" />
</Playground>

## Usage in text

Icons will be the same size as its text by default.

<Playground>
<Text>This is text with an icon! <Icon a11yLabel="Thumbs up" icon="thumbs-up" /></Text>
<Heading as="h3" marginTop="xsmall">This is a heading with an icon! <Icon a11yLabel="Thumbs up" icon="thumbs-up" /></Heading>
</Playground>

## Props

<PropsTable of={IconProps} />

## Theming

### Schema

```jsx
{
base: string | Object
}
```
27 changes: 27 additions & 0 deletions src/Icon/__tests__/Icon.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import render from '../../_utils/tests/render';
import Icon from '../Icon';
import 'jest-styled-components';

it('renders correctly for a basic icon', () => {
const { container } = render(<Icon a11yLabel="Settings" icon="cog" />);
expect(container.firstChild).toMatchSnapshot();
});

describe('colors', () => {
['danger', 'success', 'warning', 'primary'].forEach(color => {
it(`renders correctly for an icon with color ${color}`, () => {
const { container } = render(<Icon a11yLabel="Settings" color={color} icon="cog" />);
expect(container.firstChild).toMatchSnapshot();
});
});
});

describe('sizes', () => {
['small', 'medium', 'large', 'xlarge', 'xxlarge', 'xxxlarge'].forEach(size => {
it(`renders correctly for an icon with size ${size}`, () => {
const { container } = render(<Icon a11yLabel="Settings" size={size} icon="cog" />);
expect(container.firstChild).toMatchSnapshot();
});
});
});
Loading

0 comments on commit 6ce8aa5

Please sign in to comment.