Skip to content

Commit

Permalink
Initial icon update
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelArestad committed Jul 26, 2022
1 parent ff16fc8 commit 2ba3db9
Show file tree
Hide file tree
Showing 3 changed files with 1,487 additions and 386 deletions.
122 changes: 67 additions & 55 deletions code/lib/components/src/icon/icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,77 +1,89 @@
import React from 'react';
import { styled } from '@storybook/theming';
import { storiesOf } from '@storybook/react';
import { styled, css } from '@storybook/theming';

import { Icons } from './icon';
import { icons, IconKey } from './icons';
import { icons } from './icons';

const Meta = styled.div({
color: '#333',
fontSize: 12,
});
const Meta = styled.div`
color: #666;
font-size: 12px;
`;

interface ItemProps {
minimal?: boolean;
}
const Item = styled.li<{ minimal?: boolean }>`
display: inline-flex;
flex-direction: row;
align-items: center;
flex: 0 1 16%;
min-width: 120px;
margin: 16px;
const Item = styled.div<ItemProps>(
{
display: 'inline-flex',
flexDirection: 'row',
alignItems: 'center',
flex: '0 1 20%',
minWidth: 120,
svg {
margin-right: 6px;
width: 14px;
height: 14px;
}
padding: '0px 7.5px 20px',
${(props) =>
props.minimal &&
css`
flex: none;
min-width: auto;
padding: 0;
margin: 16px;
'& svg': {
marginRight: 10,
width: 24,
height: 24,
},
},
({ minimal }) =>
minimal
? {
flex: 'none',
minWidth: 'auto',
padding: 0,
background: '#fff',
border: '1px solid #666',
svg {
display: block;
margin-right: 0;
width: 14px;
height: 14px;
}
`};
`;

'& svg': {
display: 'block',
marginRight: 0,
width: 48,
height: 48,
},
}
: {}
);
const List = styled.ul`
display: flex;
flex-flow: row wrap;
list-style: none;
padding: 0;
margin: 0;
`;

const Header = styled.h2`
font-size: 16px;
margin: 16px;
`;

const List = styled.div({
display: 'flex',
flexFlow: 'row wrap',
});
export default {
title: 'Basics/Icon',
component: Icons,
};

const list = Object.keys(icons).sort() as IconKey[];
export const Basic = (args) => <Icons {...args} />;
Basic.args = { icon: 'watch' };

storiesOf('Basics/Icon', module)
.add('labels', () => (
export const Labels = () => (
<>
<Header>{Object.keys(icons).length} icons</Header>
<List>
{list.map((key) => (
{Object.keys(icons).map((key) => (
<Item key={key}>
<Icons icon={key} /> <Meta>{key}</Meta>
<Icons icon={key as keyof typeof icons} aria-hidden />
<Meta>{key}</Meta>
</Item>
))}
</List>
))
.add('no labels', () => (
</>
);

export const NoLabels = () => (
<>
<Header>{Object.keys(icons).length} icons</Header>
<List>
{list.map((key) => (
{Object.keys(icons).map((key) => (
<Item minimal key={key}>
<Icons icon={key} />
<Icons icon={key as keyof typeof icons} aria-label={key} />
</Item>
))}
</List>
));
</>
);
53 changes: 34 additions & 19 deletions code/lib/components/src/icon/icon.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,54 @@
import React, { ComponentProps, memo } from 'react';
import React, { FunctionComponent, ComponentProps, memo } from 'react';
import { styled } from '@storybook/theming';
import icons, { IconKey } from './icons';
import { icons, IconKey } from './icons';

import Svg from './svg';
const Svg = styled.svg`
display: inline-block;
shape-rendering: inherit;
transform: translate3d(0, 0, 0);
vertical-align: middle;
const Path = styled.path({
fill: 'currentColor',
});
path {
fill: currentColor;
}
`;

export interface IconsProps extends ComponentProps<typeof Svg> {
icon?: IconKey;
symbol?: IconKey;
/**
* An Icon is a piece of visual element, but we must ensure its accessibility while using it.
* It can have 2 purposes:
*
* - *decorative only*: for example, it illustrates a label next to it. We must ensure that it is ignored by screen readers, by setting `aria-hidden` attribute (ex: `<Icon icon="check" aria-hidden />`)
* - *non-decorative*: it means that it delivers information. For example, an icon as only child in a button. The meaning can be obvious visually, but it must have a proper text alternative via `aria-label` for screen readers. (ex: `<Icon icon="print" aria-label="Print this document" />`)
*/
export interface IconProps {
icon: IconType;
symbol?: IconType;
}

// TODO: if we can resize the 1024 to 20, we can remove the size attributes
export const Icons = memo<IconsProps>(({ icon, symbol, ...props }) => (
<Svg viewBox="0 0 1024 1024" {...props}>
{symbol ? <use xlinkHref={`#icon--${symbol}`} /> : <Path d={icons[icon]} />}
</Svg>
));
export const Icons: FunctionComponent<IconProps> = ({ icon, symbol, ...props }: IconProps) => {
return (
<Svg viewBox="0 0 14 14" width="14px" height="14px" {...props}>
{symbol ? <use xlinkHref={`#icon--${symbol}`} /> : icons[icon]}
</Svg>
);
};

export type IconType = keyof typeof icons;

export interface SymbolsProps extends ComponentProps<typeof Svg> {
icons?: IconKey[];
}

export const Symbols = memo<SymbolsProps>(({ icons: keys = Object.keys(icons) }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
<Svg
viewBox="0 0 14 14"
style={{ position: 'absolute', width: 0, height: 0 }}
data-chromatic="ignore"
>
{keys.map((key: IconKey) => (
<symbol id={`icon--${key}`} key={key}>
<Path d={icons[key]} />
{icons[key]}
</symbol>
))}
</svg>
</Svg>
));
Loading

0 comments on commit 2ba3db9

Please sign in to comment.