Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

[terra-icon] accessibility upgrade #3598

Merged
merged 44 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
8875918
added isdecorative logic
Feb 9, 2022
acf4172
added svg source prop
Feb 9, 2022
634bca5
converted tag to img tag
Feb 24, 2022
7131b51
updated props and logic for terra-icon
Feb 25, 2022
e4bc1fc
almost working wdio tests
Feb 28, 2022
946f51e
updated wdio snapshots
Feb 28, 2022
ab22f7e
updated wdio snapshots
Mar 1, 2022
8d34365
initial commit
Mar 8, 2022
300a5fb
updated IconBase to be meaningful
Mar 8, 2022
faee111
made prop required
Mar 9, 2022
0e779de
added title to examples
Mar 9, 2022
62b70c0
updated icon
Mar 9, 2022
f57f200
updated icon
Mar 9, 2022
9f687f4
updated docs and iconbase
Mar 10, 2022
04d7021
Merge branch 'issue-6242' of https://github.com/cerner/terra-core int…
jeremyfuksa Mar 10, 2022
67f695e
updated title prop to a11yLabel
Mar 11, 2022
841dce8
updated icon all tests
Mar 11, 2022
f58c2d8
formatted all icons test
Mar 12, 2022
3248c89
updated props in documentation
Mar 12, 2022
f3c8e48
updated changelog
Mar 12, 2022
5db4499
updated test labels
Mar 12, 2022
91340a1
generated decorative icons, untested
Mar 14, 2022
73a54b2
Merge branch 'issue-6242' of https://github.com/cerner/terra-core int…
Mar 14, 2022
e0100aa
documenting decorative icon generation
Mar 14, 2022
4b66ada
whoops... :)
Mar 14, 2022
2013fc4
fixed prop typo
Mar 14, 2022
b399fbe
updated scripts
Mar 14, 2022
52f9355
created decorative icons
Mar 14, 2022
4277119
updated decorative icons
Mar 15, 2022
598d9d8
updated decorative icons
Mar 15, 2022
c689895
finished icons
Mar 15, 2022
7324ffc
finished icon tests
Mar 15, 2022
d1f74e5
added documentation
Mar 15, 2022
3b8ad03
Merge branch 'issue-6242' of https://github.com/cerner/terra-core int…
jeremyfuksa Mar 16, 2022
73c4ca4
updated docs
Mar 16, 2022
6eb54de
updated tests
Mar 16, 2022
4f16e98
undoed merge conflicts
Mar 16, 2022
bea1d0f
undoed merge conflicts
Mar 16, 2022
2ad806b
updated generation scripts
Mar 16, 2022
14c694b
updated icons
Mar 16, 2022
6f33283
restored snapshots
Mar 16, 2022
8175669
Update packages/terra-icon/scripts/src/README.md
sdadn Mar 17, 2022
6e36b79
updated scripts
Mar 17, 2022
bdda562
updated scripts
Mar 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import IconBasePropsTable from 'terra-icon/src/IconBase?dev-site-props-table';
# Terra Icon

The terra-icon component is used to visually represent a literal or symbolic object intended to initiate an action, communicate a status, or navigate the workflow.
Icons can be `meaningful` where they used to convey a semantic meaning or `decorative` where they are are simply used for aesthetic purposes.
See [Usage](#usage) for more information.

## Getting Started

Expand All @@ -19,20 +21,35 @@ The terra-icon component is used to visually represent a literal or symbolic obj
This component requires the following peer dependencies be installed in your app for the component to properly function.

| Peer Dependency | Version |
|-|-|
| react | ^16.8.5 |
| react-dom | ^16.8.5 |
| react-intl | ^2.8.0 |
|-----------------|---------|
| react | ^16.8.5 |
| react-dom | ^16.8.5 |
| react-intl | ^2.8.0 |

<!-- AUTO-GENERATED-CONTENT:END -->

## Usage

### Meaningful Icons
Each Icon can be imported individually.

```jsx
import IconAdd from 'terra-icon/lib/icon/IconAdd';
import IconEdit from 'terra-icon/lib/icon/IconEdit';

<div>
<IconAdd a11yLabel="add item"/>
<IconEdit a11yLabel="edit item"/>
</div>
```

By default, the icons imported are `meaningful` which means that they are intended to convey meaning and thus, the `a11yLabel` prop is required for screenreaders.
If icons are intended for aesthetic purposes, then `decorative` icons and be imported as follows:

```jsx
import IconAddDecorative from 'terra-icon/lib/icon/decorative/IconAdd';
import IconEditDecorative from 'terra-icon/lib/icon/decoartive/IconEdit';

<div>
<IconAdd />
<IconEdit />
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import IconAlert from 'terra-icon/lib/icon/IconAlert';
import IconAlertDecorative from 'terra-icon/lib/icon/decorative/IconAlert';

const IconAccessibleLabel = () => (
<div>
<h3>Meaningful icon</h3>
<div>
<IconAlert a11yLabel="alert icon"/>
</div>

<h3>Decorative icon</h3>
<div>
<IconAlertDecorative a11yLabel="alert icon"/>
</div>
</div>
);

export default IconAccessibleLabel;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
:local {
.icon {
height: 40px;
margin: 5px;
width: 40px;
margin: 5px;
}

.icon-inverse {
Expand Down
618 changes: 309 additions & 309 deletions packages/terra-core-docs/src/terra-dev-site/test/icon/IconAll.test.jsx

Large diffs are not rendered by default.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ const IconBidi = () => (
<div dir="rtl">
<h3>Icon where isBidi is false by default</h3>
<h4>Default</h4>
<IconDeviceCheck />
<IconDeviceCheck a11yLabel="device check icon"/>
<h4>Set isBidi true</h4>
<IconDeviceCheck isBidi />
<IconDeviceCheck a11yLabel="device check icon" isBidi />
<h4>Set isBidi false</h4>
<IconDeviceCheck isBidi={false} />
<IconDeviceCheck a11yLabel="device check icon" isBidi={false} />

<h3>Icon where isBidi is true by default</h3>
<h4>Default</h4>
<IconComment />
<IconComment a11yLabel="comment icon"/>
<h4>Set isBidi true</h4>
<IconComment isBidi />
<IconComment a11yLabel="comment icon" isBidi />
<h4>Set isBidi false</h4>
<IconComment isBidi={false} />
<IconComment a11yLabel="comment icon" isBidi={false} />
</div>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import IconAdd from 'terra-icon/lib/icon/IconAdd';
const IconDefault = () => (
<div>
<h3>Default Icon</h3>
<IconAdd id="icon-default" />
<IconAdd id="icon-default" a11yLabel="add icon"/>
</div>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ const cx = classNames.bind(styles);
const IconHeightWidth = () => (
<div>
<h3>Default</h3>
<IconAlert />
<IconAlert a11yLabel="alert icon"/>
<h3>Height and Width are 50px</h3>
<IconAlert id="icon-height-50-width-50" height="50" width="50" />
<IconAlert a11yLabel="alert icon" id="icon-height-50-width-50" height="50" width="50" />
<h3>Height and Width are 5em</h3>
<IconAlert id="icon-height-5em-width-5em" height="5em" width="5em" />
<IconAlert a11yLabel="alert icon" id="icon-height-5em-width-5em" height="5em" width="5em" />
<h3>Container font size is 5em</h3>
<div className={cx('icon-wrapper')}>
<IconAlert />
<IconAlert a11yLabel="alert icon"/>
</div>
<h3>Height of 5em</h3>
<IconAlert id="icon-height-5em" height="5em" />
<IconAlert a11yLabel="alert icon" id="icon-height-5em" height="5em" />
<h3>Width of 5em</h3>
<IconAlert id="icon-width-5em" width="5em" />
<IconAlert a11yLabel="alert icon" id="icon-width-5em" width="5em" />
</div>
);

Expand Down
2 changes: 2 additions & 0 deletions packages/terra-icon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## Unreleased
* Breaking changes
* Updated terra-icon to meet accessibility standards.

## 3.46.1 - (January 4, 2022)

Expand Down
10 changes: 8 additions & 2 deletions packages/terra-icon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,24 @@
"scripts": {
"compilescripts": "npm run compilescripts:clean && npm run compilescripts:build",
"compilescripts:clean": "rm -rf scripts/lib",
"create-decorative-dir": "mkdir -p src/icon/decorative && cp -r src/icon/*.jsx src/icon/decorative/",
"compilescripts:build": "babel --root-mode upward scripts/src --out-dir scripts/lib --copy-files",
"migrate-csv": "node scripts/lib/migrate-csv/index.js",
"migrate-svg": "node scripts/lib/migrate-svg/index.js",
"generate-json": "node scripts/lib/generate-json/index.js",
"generate-icon": "node scripts/lib/generate-icon/index.js",
"generate-all-icons": "npm run generate-meaningful-icons && npm run generate-decorative-icons",
"generate-meaningful-icons": "npm run compilescripts && node scripts/lib/generate-icon/index.js",
"generate-decorative-icons": "npm run create-decorative-dir && npm run replace-decorative-baseclass && npm run replace-decorative-import && npm run replace-decorative-displayname",
"generate-example": "node scripts/lib/generate-example/index.js",
"migrate-cerner-one-icons": "npm run compilescripts && npm run migrate-csv && npm run migrate-svg && npm run generate-json && npm run generate-icon && npm run generate-example",
"migrate-cerner-one-icons": "npm run compilescripts && npm run migrate-csv && npm run migrate-svg && npm run generate-json && npm run generate-all-icons && npm run generate-example",
"compile": "babel --root-mode upward src --out-dir lib --copy-files",
"lint": "npm run lint:js && npm run lint:scss",
"lint:js": "eslint --ext .js,.jsx . --ignore-path ../../.eslintignore",
"lint:scss": "stylelint src/**/*.scss",
"precompile": "rm -rf lib",
"replace-decorative-baseclass": "find src/icon/decorative -type f -exec perl -i -pe's|IconBase|IconBaseDec|g' {} +",
"replace-decorative-import": "find src/icon/decorative -type f -exec perl -i -pe's|\\Q../\\E|../../|g' {} +",
"replace-decorative-displayname": "find src/icon/decorative -type f -exec perl -i -pe's/(SvgIcon\\.displayName = \")(\\w[\\w\\d]+)(\";)/\\1\\2Dec\\3/g' {} +",
"test": "npm run lint && npm run jest && npm run wdio",
"jest": "jest --config ../../jest.config.js",
"wdio-default": "cd ../.. && terra wdio",
Expand Down
32 changes: 24 additions & 8 deletions packages/terra-icon/scripts/src/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
# Update all SVG icons
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A command could be added for each heading in this file with more than one command under it: update-all-svg-icons, generate-meaningful-icons, generate-decorative-icons

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated scripts here: 6e36b79

Copy link
Contributor

@eawww eawww Mar 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dove a little deeper into this:

  • npm run migrate-cerner-one-icons won't work now because npm generate-icon isn't a script.
    • If npm run generate-all-icons is supposed to be part of npm run migrate-cerner-one-icons, wouldn't all steps in this document be completed in step 1?
  • Under the "Step 2 - Generate meaningful icons" heading:
    • npm run generate-icon isn't a thing now.
    • Once it's changed to reflect the new name for the command, everything but the last command is done directly by the command in step 1.
  • npm run replace-decorative-import is part of the generate-decorative-icons command but isn't in the list of commands in this file to generate decorative icons

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh try pulling. I updated the readme and scripts.


```
npm run migrate-cerner-one-icons
```
* npm run compilescripts
* npm run migrate-csv
* npm run migrate-svg
* npm run generate-icon
* npm run generate-example
### Step 1. Initate scripts

npm run compilescripts

### Step 2. (Optional) Migrate icons from a csv file
You can skip this step if you're not updating the svg files in `packages/terra-icon/src/svg`.

npm run migrate-csv
npm run migrate-svg

### Step 3. Generate icons based
This will generate icons based on the files in `packages/terra-icon/src/svg`, whether they are newly migrated or pre-existing.

npm run generate-all-icons

Meaningful icons will be generated in `packages/terra-icon/src/icon`, directly in the folder.
Decorative icons will be generated in `packages/terra-icon/src/icon/decorative`.


### Alternative run all steps command

Alternatively, if you need to run steps 1, 2 and 3, then you can execute them all with a single command:

npm run migrate-cerner-one-icons
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Icon from './Icon';
const parseSvg = filepath => new Promise((resolve) => {
const source = fs.readFileSync(filepath, 'utf-8');
const { name } = path.parse(filepath);

const { document } = new JSDOM(source).window;
const icon = new Icon(name, document.querySelector('svg'));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const SvgIcon = (customProps) => {
const attributes = Object.assign({}, customProps);

return (
<IconBase {...attributes}>
<IconBase {...attributes} >
<%= icon.children %>
</IconBase>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { FormattedMessage } from 'react-intl';

const SvgIcon = (customProps) => {
const attributes = Object.assign({}, customProps);

return (
<FormattedMessage id="Terra.icon.<%= icon.name %>.title">
{iconTitle => (
<span aria-label={iconTitle} title={iconTitle}>
<IconBase {...attributes}>
<IconBase {...attributes} >
<%= icon.children %>
</IconBase>
</span>
Expand Down
30 changes: 13 additions & 17 deletions packages/terra-icon/src/IconBase.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import styles from './Icon.module.scss';
const cx = classNamesBind.bind(styles);

const propTypes = {
/**
* String that labels the current element.
*/
a11yLabel: PropTypes.string.isRequired,
/**
* Should the svg mirror when dir="rtl".
*/
Expand All @@ -29,11 +33,6 @@ const propTypes = {
* Width of SVG.
*/
width: PropTypes.string,
/**
* String that labels the current element. If 'aria-label' is present,
* role is set to 'img' and aria-hidden is removed.
*/
ariaLabel: PropTypes.string,
/**
* Focusable attribute. IE 10/11 are focusable without this attribute.
*/
Expand All @@ -46,17 +45,20 @@ const defaultProps = {
children: null,
height: '1em',
width: '1em',
ariaLabel: null,
focusable: 'false',
};

// Returns a SVG representing the icon. Is utilized as: <Iconbase {..props} ><svg children></IconBase>
// Note: while an img is the ideal recommended approach by accessibility guidelines,
// IconBase returns a svg so that non-static icons can be themable by using the CSS color property.

const IconBase = ({
a11yLabel,
isBidi,
isSpin,
children,
height,
width,
ariaLabel,
focusable,
...customProps
}) => {
Expand All @@ -73,20 +75,14 @@ const IconBase = ({
attributes.className,
);

// aria-label is present, remove aria-hidden, set role to img
if (ariaLabel) {
attributes['aria-label'] = ariaLabel;
attributes.role = 'img';
attributes['aria-hidden'] = null;
} else {
attributes['aria-hidden'] = 'true';
}

attributes.height = height;
attributes.width = width;
attributes.focusable = focusable;

const svgA11yLabel = React.createElement('title', {}, a11yLabel);
const svgChildren = new Array(svgA11yLabel).concat(children);

return <svg {...attributes} className={classes}>{children}</svg>;
return <svg {...attributes} className={classes}>{svgChildren}</svg>;
};

IconBase.propTypes = propTypes;
Expand Down
Loading