Skip to content
Permalink
Browse files

feat(icons): make decorative required + icon docs (#165)

* feat(icons): make decorative required

* feat(website): add icons docs

* fix(spinner): fix story derp

* fix(website): icon docs fixes

* fix(website): update icon docs with pr comments

* fix: more review notes

* fix: add link to storybook icon list

* fix(website): icon docs refactored

* fix(website): add sidebar submenu indentation

* fix(spinner): forgot to pass 'title' prop to icon

* fix(website): add aria-expanded to new sidebar item

* fix: minor nits

* fix: checkpoint major changes

* chore: adding some image assets for docs

* docs: how to add an icon page + nav fixes

* fix: pr feedback

* fix: build issue

* fix: remove sub styles for tsc

* test(buttons): update snapshot

* chore: rebuild

* fix: many cr fixes

* fix: jin comments

* fix(button): story fixes for decorative icons

* fix: eslint

* fix: fancy quotes
  • Loading branch information
TheSisb committed Nov 20, 2019
1 parent 81fa3b2 commit 15ccbc2e0f259d60af83bf8503c8ee18a1191cb8
Showing with 516 additions and 99 deletions.
  1. +6 −6 packages/paste-core/components/button/__tests__/__snapshots__/button.test.tsx.snap
  2. +1 −1 packages/paste-core/components/button/src/index.tsx
  3. +17 −17 packages/paste-core/components/button/stories/index.stories.tsx
  4. +2 −3 packages/paste-core/components/spinner/src/index.tsx
  5. +11 −2 packages/paste-core/components/spinner/stories/index.stories.tsx
  6. +6 −6 packages/paste-icons/README.md
  7. +21 −20 packages/paste-icons/src/LoadingIcon.tsx
  8. +21 −20 packages/paste-icons/src/PlusIcon.tsx
  9. +15 −15 packages/paste-icons/tools/templates/reactIconTemplate.js
  10. +1 −1 packages/paste-icons/tools/templates/storybookListTemplate.js
  11. +4 −2 packages/paste-website/package.json
  12. BIN packages/paste-website/src/assets/images/icon-guide/formatting-an-icon-1.png
  13. BIN packages/paste-website/src/assets/images/icon-guide/formatting-an-icon-2.png
  14. BIN packages/paste-website/src/assets/images/icon-guide/formatting-an-icon-3.png
  15. BIN packages/paste-website/src/assets/images/icon-guide/using-streamline-icons-1.png
  16. BIN packages/paste-website/src/assets/images/icon-guide/using-streamline-icons-2.png
  17. BIN packages/paste-website/src/assets/images/icon-guide/using-streamline-icons-3.png
  18. +8 −0 packages/paste-website/src/components/paste-mdx-provider/index.tsx
  19. +1 −0 packages/paste-website/src/components/site-wrapper/sidebar/SidebarNavigation.styles.ts
  20. +29 −6 packages/paste-website/src/components/site-wrapper/sidebar/SidebarNavigation.tsx
  21. +1 −0 packages/paste-website/src/constants.ts
  22. +134 −0 packages/paste-website/src/pages/icon-system/how-to-add-an-icon.mdx
  23. +238 −0 packages/paste-website/src/pages/icon-system/index.mdx
@@ -588,7 +588,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="1"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -634,7 +634,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="2"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -680,7 +680,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="3"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -726,7 +726,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="4"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -772,7 +772,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="5"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -818,7 +818,7 @@ exports[`Button States Has a loading state 1`] = `
<title
id="6"
>
Loading Icon
Loading, please wait.
</title>
<path
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
@@ -98,7 +98,7 @@ const Button: React.FC<ButtonProps> = props => {
<ButtonChildren buttonState={buttonState}>{props.children}</ButtonChildren>
{showLoading ? (
<SpinnerWrapper as="span">
<Spinner title=". Loading, please wait." />
<Spinner decorative={false} title="Loading, please wait." />
</SpinnerWrapper>
) : null}
</ButtonWrapper>
@@ -50,7 +50,7 @@ storiesOf('Components|Button', module)
onFocus={action('handleFocus')}
onBlur={action('handleBlur')}
>
<PlusIcon />
<PlusIcon decorative />
<span>Activate</span>
</Button>
);
@@ -71,7 +71,7 @@ storiesOf('Components|Button', module)
onFocus={action('handleFocus')}
onBlur={action('handleBlur')}
>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
);
})
@@ -105,13 +105,13 @@ storiesOf('Components|Button', module)
<br />
<section>
<Button variant="primary" size="icon">
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="primary" size="icon" loading>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="primary" size="icon" disabled>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
</section>
<br />
@@ -153,13 +153,13 @@ storiesOf('Components|Button', module)
<br />
<section>
<Button variant="secondary" size="icon">
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="secondary" size="icon" loading>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="secondary" size="icon" disabled>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
</section>
<br />
@@ -201,13 +201,13 @@ storiesOf('Components|Button', module)
<br />
<section>
<Button variant="destructive" size="icon">
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="destructive" size="icon" loading>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="destructive" size="icon" disabled>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
</section>
<br />
@@ -249,13 +249,13 @@ storiesOf('Components|Button', module)
<br />
<section>
<Button variant="link" size="icon">
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="link" size="icon" loading>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="link" size="icon" disabled>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
</section>
<br />
@@ -297,13 +297,13 @@ storiesOf('Components|Button', module)
<br />
<section>
<Button variant="destructive_link" size="icon">
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="destructive_link" size="icon" loading>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
<Button variant="destructive_link" size="icon" disabled>
<PlusIcon />
<PlusIcon decorative={false} title="Add to cart" />
</Button>
</section>
<br />
@@ -34,15 +34,14 @@ interface SpinnerProps extends LoadingIconProps {
size?: IconSize;
}

const Spinner: React.FC<SpinnerProps> = ({as, size, iconColor, decorative}) => (
const Spinner: React.FC<SpinnerProps> = ({as, size, iconColor, decorative, title}) => (
<SpinningWrapper size={size}>
<LoadingIcon as={as} size={size} iconColor={iconColor} decorative={decorative} />
<LoadingIcon as={as} size={size} iconColor={iconColor} decorative={decorative} title={title} />
</SpinningWrapper>
);

Spinner.defaultProps = {
size: 'sizeIcon20',
decorative: false,
};

Spinner.displayName = 'Spinner';
@@ -1,6 +1,6 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {withKnobs, text, select} from '@storybook/addon-knobs';
import {withKnobs, text, select, boolean} from '@storybook/addon-knobs';
import {TextColor, IconSize} from '@twilio-paste/types';
import {DefaultTheme} from '@twilio-paste/theme-tokens';
import {Spinner} from '../src';
@@ -13,15 +13,24 @@ storiesOf('Components|Spinner', module)
.add('Default', () => {
const iconColorValue = select('iconColor', IconColorOptions, 'currentColor') as TextColor;
const sizeValue = select('size', SizeOptions, 'sizeIcon20') as IconSize;
const decorativeValue = boolean('decorative', false);

return <Spinner iconColor={iconColorValue} size={sizeValue} title={text('title', 'Now loading')} />;
return (
<Spinner
iconColor={iconColorValue}
size={sizeValue}
title={text('title', 'Now loading')}
decorative={decorativeValue}
/>
);
})
.add('Responsive', () => {
return (
<Spinner
iconColor={['colorText', 'colorTextError']}
size={['sizeIcon10', 'sizeIcon20', 'sizeIcon30', 'sizeIcon40']}
title={text('title', 'Now loading')}
decorative={false}
/>
);
});
@@ -19,12 +19,12 @@ import AssetsIcon from '@twilio-paste/icons/react/AssetsIcon';

### Standard Props

| Prop | Type | Description | Default |
| ----------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| decorative? | boolean | Whether or not the SVG is just visual flair or adds meaning to the page. Specifically for screenreaders to know whether to read out the title or not. | true |
| title? | string | The accesibility text that is read when screenreaders get to this component | Component name |
| size? | number | The width and height value (all icons are square) in pixels | 24 |
| color? | string | The color of your icon | currentColor - whatever is the font-color inherited from up the DOM tree |
| Prop | Type | Description | Default |
| ---------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| decorative | boolean | Whether or not the SVG is just visual flair or adds meaning to the page. Specifically for screenreaders to know whether to read out the title or not. | true |
| title? | string | The accesibility text that is read when screenreaders get to this component | Component name |
| size? | number | The width and height value (all icons are square) in pixels | 24 |
| color? | string | The color of your icon | currentColor - whatever is the font-color inherited from up the DOM tree |

Keep in mind these props are the **Base Guarantee** for icon components. Some icons may have additional functionality as needed (a way to style two color options for example).

@@ -7,29 +7,30 @@ import {IconWrapper, IconWrapperProps} from './helpers/IconWrapper';

export interface LoadingIconProps extends IconWrapperProps {
title?: string;
decorative?: boolean;
decorative: boolean;
}

const LoadingIcon: React.FC<LoadingIconProps> = ({title, decorative, ...props}) => (
<IconWrapper {...props}>
<UID>
{uid => (
<svg role="img" aria-hidden={decorative} aria-labelledby={uid} width="100%" height="100%" viewBox="0 0 24 24">
{title ? <title id={uid}>{title}</title> : null}
<path
fill="currentColor"
fillRule="evenodd"
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
/>
</svg>
)}
</UID>
</IconWrapper>
);
const LoadingIcon: React.FC<LoadingIconProps> = ({as, size, iconColor, title, decorative}) => {
if (!decorative && title == null) {
throw new Error('[LoadingIcon]: Missing a title for non-decorative icon.');
}

LoadingIcon.defaultProps = {
title: 'Loading Icon',
decorative: true,
return (
<IconWrapper as={as} size={size} iconColor={iconColor}>
<UID>
{uid => (
<svg role="img" aria-hidden={decorative} aria-labelledby={uid} width="100%" height="100%" viewBox="0 0 24 24">
{title ? <title id={uid}>{title}</title> : null}
<path
fill="currentColor"
fillRule="evenodd"
d="M20.085 13.123a1 1 0 01.71 1.224A9.103 9.103 0 014.717 17.46l-.15 1.756a1 1 0 11-1.992-.17l.407-4.773a1 1 0 011.357-.848l4.47 1.728a1 1 0 11-.72 1.865l-1.691-.652a7.103 7.103 0 0012.463-2.533 1 1 0 011.223-.71zM12.008 2.892a9.1 9.1 0 017.283 3.64l.148-1.756a1 1 0 011.993.17l-.407 4.773a1 1 0 01-1.357.847l-4.47-1.727a1 1 0 01.72-1.866l1.691.653a7.103 7.103 0 00-12.463 2.533 1 1 0 01-1.932-.514 9.103 9.103 0 018.794-6.753z"
/>
</svg>
)}
</UID>
</IconWrapper>
);
};

LoadingIcon.displayName = 'LoadingIcon';
@@ -7,29 +7,30 @@ import {IconWrapper, IconWrapperProps} from './helpers/IconWrapper';

export interface PlusIconProps extends IconWrapperProps {
title?: string;
decorative?: boolean;
decorative: boolean;
}

const PlusIcon: React.FC<PlusIconProps> = ({title, decorative, ...props}) => (
<IconWrapper {...props}>
<UID>
{uid => (
<svg role="img" aria-hidden={decorative} aria-labelledby={uid} width="100%" height="100%" viewBox="0 0 24 24">
{title ? <title id={uid}>{title}</title> : null}
<path
fill="currentColor"
fillRule="evenodd"
d="M12 3.348a1 1 0 011 1V11h6.652a1 1 0 01.993.883l.007.117a1 1 0 01-1 1H13v6.652a1 1 0 01-.883.993l-.117.007a1 1 0 01-1-1V13H4.348a1 1 0 01-.993-.883L3.348 12a1 1 0 011-1H11V4.348a1 1 0 01.883-.993z"
/>
</svg>
)}
</UID>
</IconWrapper>
);
const PlusIcon: React.FC<PlusIconProps> = ({as, size, iconColor, title, decorative}) => {
if (!decorative && title == null) {
throw new Error('[PlusIcon]: Missing a title for non-decorative icon.');
}

PlusIcon.defaultProps = {
title: 'Plus Icon',
decorative: true,
return (
<IconWrapper as={as} size={size} iconColor={iconColor}>
<UID>
{uid => (
<svg role="img" aria-hidden={decorative} aria-labelledby={uid} width="100%" height="100%" viewBox="0 0 24 24">
{title ? <title id={uid}>{title}</title> : null}
<path
fill="currentColor"
fillRule="evenodd"
d="M12 3.348a1 1 0 011 1V11h6.652a1 1 0 01.993.883l.007.117a1 1 0 01-1 1H13v6.652a1 1 0 01-.883.993l-.117.007a1 1 0 01-1-1V13H4.348a1 1 0 01-.993-.883L3.348 12a1 1 0 011-1H11V4.348a1 1 0 01.883-.993z"
/>
</svg>
)}
</UID>
</IconWrapper>
);
};

PlusIcon.displayName = 'PlusIcon';
@@ -1,6 +1,4 @@
// Note on a11y: https://css-tricks.com/can-make-icon-system-accessible/
const {pascalCaseWordSplitter} = require('../utils');

const reactIconTemplate = ({componentName, svg}) => `
/**
* This file was automatically generated with @twilio-labs/svg-to-react
@@ -11,23 +9,25 @@ import {IconWrapper, IconWrapperProps} from './helpers/IconWrapper';
export interface ${componentName}Props extends IconWrapperProps {
title?: string;
decorative?: boolean;
decorative: boolean;
}
const ${componentName}: React.FC<${componentName}Props> = ({title, decorative, ...props}) => (
<IconWrapper {...props}>
<UID>
{uid => (
${svg}
)}
</UID>
</IconWrapper>
);
const ${componentName}: React.FC<${componentName}Props> = ({as, size, iconColor, title, decorative}) => {
if (!decorative && title == null) {
throw new Error('[${componentName}]: Missing a title for non-decorative icon.');
}
${componentName}.defaultProps = {
title: '${pascalCaseWordSplitter(componentName)}',
decorative: true,
return (
<IconWrapper as={as} size={size} iconColor={iconColor}>
<UID>
{uid => (
${svg}
)}
</UID>
</IconWrapper>
);
}
${componentName}.displayName = '${componentName}';
export {${componentName}};
@@ -22,7 +22,7 @@ ${importIconList}
interface IconProps {
title?: string;
decorative?: boolean;
decorative: boolean;
size?: number;
color?: string;
}

1 comment on commit 15ccbc2

@now

This comment has been minimized.

Please sign in to comment.
You can’t perform that action at this time.