Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6940df8
commit 420658b
Showing
7 changed files
with
408 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,133 +1,210 @@ | ||
// @flow strict | ||
import type { Node } from 'react'; | ||
import { Icon } from 'gestalt'; | ||
import Example from '../components/Example.js'; | ||
import PropTable from '../components/PropTable.js'; | ||
import Combination from '../components/Combination.js'; | ||
import CombinationNew from '../components/CombinationNew.js'; | ||
import PageHeader from '../components/PageHeader.js'; | ||
import CardPage from '../components/CardPage.js'; | ||
import MainSection from '../components/MainSection.js'; | ||
import GeneratedPropTable from '../components/GeneratedPropTable.js'; | ||
import Page from '../components/Page.js'; | ||
import docgen, { type DocGen } from '../components/docgen.js'; | ||
|
||
const cards: Array<Node> = []; | ||
const card = (c) => cards.push(c); | ||
|
||
const icons: Array<string> = Icon?.icons ?? []; | ||
|
||
card( | ||
<PageHeader | ||
name="Icon" | ||
description=" | ||
Show icons with different colors and sizes in an accessible way. | ||
" | ||
/>, | ||
); | ||
|
||
card( | ||
<PropTable | ||
props={[ | ||
{ | ||
name: 'accessibilityLabel', | ||
type: 'string', | ||
required: true, | ||
description: | ||
'String that clients such as VoiceOver will read to describe the element. Always localize the label.', | ||
href: 'iconWithLabel', | ||
}, | ||
{ | ||
name: 'color', | ||
type: `"blue" | "darkGray" | "eggplant" | "gray" | "green" | "lightGray" | "maroon" | "midnight" | "navy" | "olive" | "orange" | "orchid" | "pine" | "purple" | "red" | "watermelon" | "white"`, | ||
defaultValue: 'gray', | ||
href: 'sizeColorCombinations', | ||
}, | ||
{ | ||
name: 'icon', | ||
type: icons.map((name) => `'${name}'`).join(' | '), | ||
description: `This allows us to type check for a valid icon name based on the keys from the list of icons shown below.`, | ||
href: 'iconCombinations', | ||
}, | ||
{ | ||
name: 'size', | ||
type: `number | string`, | ||
description: `Use a number for pixel sizes or a string for percentage based sizes`, | ||
defaultValue: 16, | ||
href: 'sizeColorCombinations', | ||
}, | ||
{ | ||
name: 'inline', | ||
type: 'boolean', | ||
defaultValue: false, | ||
}, | ||
{ | ||
name: 'dangerouslySetSvgPath', | ||
type: `{ __path: string }`, | ||
description: `When using this prop, make sure that the viewbox around the SVG path is 24x24`, | ||
}, | ||
]} | ||
/>, | ||
); | ||
|
||
card( | ||
<MainSection name="Usage guidelines"> | ||
<MainSection.Subsection columns={2}> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="do" | ||
title="When to Use" | ||
description={` | ||
- As symbolic communication for elements that do not have room for text, like number of pins in a carousel. In this case, ensure the icon choice is easily recognizable and makes sense to international users. | ||
- To convey a critical meaning that cannot be communicated with words, like a downward chevron in a Button to indicate it reveals a menu. | ||
`} | ||
export default function IconPage({ generatedDocGen }: {| generatedDocGen: DocGen |}): Node { | ||
return ( | ||
<Page title="Icon"> | ||
<PageHeader | ||
name="Icon" | ||
description="Icons are the symbolic representation of an action or information, providing visual context and improving usability." | ||
defaultCode={` | ||
<Flex gap={1}> | ||
<Icon icon="pin" accessibilityLabel="Pin" color="darkGray" /> | ||
<Text align="center" color="darkGray" weight="bold"> | ||
</Text> | ||
</Flex>`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="don't" | ||
title="When Not to Use" | ||
description={` | ||
- For purposes that are decorative or for visual embellishment, such as how illustrations are typically used. Contact us if this is needed. | ||
- As a visual reinforcement for associated text, without adding new meaning. | ||
- To communicate status or health. Use [Status](/status) instead. | ||
- As an interactive element (e.g., utilizing hover, focus, click/tap). Use [IconButton](/iconbutton) instead. | ||
`} | ||
/> | ||
</MainSection.Subsection> | ||
</MainSection>, | ||
); | ||
<GeneratedPropTable generatedDocGen={generatedDocGen} /> | ||
<MainSection name="Usage guidelines"> | ||
<MainSection.Subsection columns={2}> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="do" | ||
title="When to Use" | ||
description={` | ||
- As symbolic communication for elements that do not have room for text, like the number of pins in a carousel. In this case, ensure the icon choice is easily recognizable and makes sense to international users. | ||
- To convey a critical meaning that cannot be communicated with words, like a downward chevron in a Button to indicate it reveals a menu. | ||
- To help with quick scanning by adding rhythm and hierarchy to the design.`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="don't" | ||
title="When Not to Use" | ||
description={` | ||
- For purposes that are decorative or for visual embellishment, such as how illustrations are typically used. Contact us if this is needed. | ||
- As a visual reinforcement for associated text, without adding new meaning. | ||
- To communicate status or health. Use [Status](/status) instead. | ||
- As an interactive element (e.g., utilizing hover, focus, click/tap). Use [IconButton](/iconbutton) instead.`} | ||
/> | ||
</MainSection.Subsection> | ||
</MainSection> | ||
<MainSection name="Best practices"> | ||
<MainSection.Subsection columns={2}> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="do" | ||
description="Use icons intentionally, ensuring the Icon choice is easily recognizable and makes sense in the context. " | ||
defaultCode={` | ||
<Flex gap={1}> | ||
<Icon icon="eye" accessibilityLabel="Number of views" color="darkGray" /> | ||
<Text weight="bold" size="lg">4</Text> | ||
</Flex>`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="don't" | ||
description="Repurpose icons. Using icons for their intended meaning supports good comprehension." | ||
defaultCode={` | ||
<Flex gap={2}> | ||
<Icon icon="sound" accessibilityLabel="" color="darkGray" /> | ||
<Text size="lg" weight="bold">24 monthly views</Text> | ||
</Flex>`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="do" | ||
description="Pair text and icons when possible to provide better clarity." | ||
defaultCode={` | ||
<Flex gap={1}> | ||
<Icon icon="tag" accessibilityLabel="" color="darkGray" /> | ||
<Text size="lg" weight="bold"> | ||
Shopping spotlight | ||
</Text> | ||
</Flex>`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="don't" | ||
description="Don't create interactive Icons using TapArea. Use [IconButton](/iconbutton) instead." | ||
defaultCode={` | ||
<Tooltip text="Pinterest"> | ||
<TapArea> | ||
<Icon icon="share" accessibilityLabel="" color="darkGray" /> | ||
</TapArea> | ||
</Tooltip> | ||
`} | ||
/> | ||
</MainSection.Subsection> | ||
</MainSection> | ||
<MainSection | ||
name="Accessibility" | ||
description="Icons are a great way to help users who have difficulties with reading, focus attention, and low vision impairments." | ||
> | ||
<MainSection.Subsection | ||
title="ARIA attributes" | ||
columns={2} | ||
description={` | ||
If the icon appears without text, the Icon requires \`accessibilityLabel\`, a text description for screen readers to announce and communicate the represented [Icon](/Icon), as shown in the first example. | ||
Avoid using the generic words like "image" or "icon"; instead, use verbs that describe the meaning of the icon, for example: “pins". | ||
card( | ||
<Example | ||
id="iconWithLabel" | ||
description="Icon with a label" | ||
name="Example" | ||
defaultCode={` | ||
<Box alignItems="center" display="flex"> | ||
<Box marginEnd={1} padding={1}> | ||
<Icon icon="pin" accessibilityLabel="Pin" color="darkGray" /> | ||
</Box> | ||
<Text align="center" color="darkGray" weight="bold"> | ||
If an icon has a visible label that describes what the icon represents, \`accessibilityLabel\` can be an empty string, as shown in the second example. | ||
`} | ||
> | ||
<MainSection.Card | ||
cardSize="md" | ||
defaultCode={` | ||
<Flex gap={1}> | ||
<Icon icon="tag" accessibilityLabel="" color="darkGray" /> | ||
<Text align="center" weight="bold"> | ||
Shopping spotlight | ||
</Text> | ||
</Flex>`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
defaultCode={` | ||
<Flex gap={1}> | ||
<Icon icon="tag" accessibilityLabel="" color="darkGray" /> | ||
<Text align="center" weight="bold"> | ||
Shopping spotlight | ||
</Text> | ||
</Box> | ||
</Flex>`} | ||
/> | ||
</MainSection.Subsection> | ||
<MainSection.Subsection | ||
title="Legibility and touch area" | ||
description="Ensure that icons use a contrast ratio of 4.5:1 between icon color and background color." | ||
/> | ||
</MainSection> | ||
<MainSection name="Localization" description="Be sure to localize `accessibilityLabel`." /> | ||
<MainSection name="Variants"> | ||
<MainSection.Subsection title="Primary-color combinations"> | ||
<CombinationNew color={['gray', 'darkGray', 'red']}> | ||
{({ color }) => <Icon icon="heart" accessibilityLabel="" color={color} />} | ||
</CombinationNew> | ||
</MainSection.Subsection> | ||
<MainSection.Subsection | ||
title="Size" | ||
description={` | ||
These are the guidelines for icon sizes (in px): | ||
1. \`12\` | ||
Used sparingly in tight spaces. When possible, use a text label next to the icon, as it can be hard to see for visually impaired people. | | ||
2. \`16\` | ||
Used often any time an icon is needed. Default icon size. | ||
3. \`24\` | ||
Used frequently any time an icon is needed. | ||
4. \`32\` | ||
Used occasionally, on more dense UI. | ||
5. \`32+\` | ||
Should be used sparingly and only in places where the UI is very dense and a larger icon is required. | ||
`} | ||
/>, | ||
); | ||
|
||
card( | ||
<Combination id="iconCombinations" name="Icon Combinations" icon={icons}> | ||
{(props) => <Icon color="darkGray" accessibilityLabel="" size={32} {...props} />} | ||
</Combination>, | ||
); | ||
/> | ||
</MainSection> | ||
<MainSection name="Writing"> | ||
<MainSection.Subsection columns={2}> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="do" | ||
description={` | ||
- Use a descriptive label to describe the Icon | ||
- Be succinct. Exclude unnecessary words. | ||
- Be informative and accurate | ||
- Write in the active voice | ||
- Avoid technical jargon | ||
`} | ||
/> | ||
<MainSection.Card | ||
cardSize="md" | ||
type="don't" | ||
description={` | ||
- Use the words "image" or "icon" in the description label; instead, use words that indicate the purpose of the icon. | ||
`} | ||
/> | ||
</MainSection.Subsection> | ||
</MainSection> | ||
<MainSection name="Related"> | ||
<MainSection.Subsection | ||
description={` | ||
**[IconButton](/IconButton)** | ||
Use IconButton when only an icon is needed to represent an action instead of text. | ||
card( | ||
<Combination | ||
id="sizeColorCombinations" | ||
name="Size & Color Combinations" | ||
size={[16, 24, 32]} | ||
color={['gray', 'darkGray', 'red']} | ||
> | ||
{(props, i) => <Icon key={i} icon="heart" accessibilityLabel="" {...props} />} | ||
</Combination>, | ||
); | ||
**[Button](/Button)** | ||
Use Button to allow users to take an action. | ||
`} | ||
/> | ||
</MainSection> | ||
</Page> | ||
); | ||
} | ||
|
||
export default function IconPage(): Node { | ||
return <CardPage cards={cards} page="Icon" />; | ||
export async function getStaticProps(): Promise<{| props: {| generatedDocGen: DocGen |} |}> { | ||
const generatedDocGen = await docgen('Icon'); | ||
if (generatedDocGen?.props?.icon?.flowType) { | ||
generatedDocGen.props.icon.flowType = { | ||
name: 'union', | ||
raw: (Icon?.icons ?? []).map((icon) => `'${icon}'`).join(' | '), | ||
}; | ||
} | ||
return { | ||
props: { generatedDocGen }, | ||
}; | ||
} |
Oops, something went wrong.