Skip to content

Commit

Permalink
feat(avt): a11y status page and a11y status table component (#3866)
Browse files Browse the repository at this point in the history
* chore: wip

* feat: add missing components to overview page

* chore: conflict

* chore: yarn

* chore: wip

* feat: a11y status page content

* feat: add screenreader data and tag style fixes

* chore: cleanup

* feat: add partially tested

* feat: add all components from testing data

* chore: yarn install state

* chore: cleanup code

* feat: add launch icon

* chore: merge conflict

* feat: add redirect

* chore: fix install state

* fix: update ui shell link

* fix: link to use carbon link component

* fix: add Equal Access Checker link

* fix: add missing links to content

* fix: add Taylor copy updates

* fix: more copy updates

* fix: copy updates

* fix: copy updates

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* Update src/pages/components/overview/accessibility-status.mdx

Co-authored-by: Taylor Jones <[email protected]>

* chore: format

* fix: component data

* fix: data

* fix: update screenreader status for experimental components

* fix: tag for experimental components

* chore: remove style override for tag font

* fix: update data

* feat: add tooltips

* fix: style specificity

* chore: cleanup

* feat: add filter for specific components

* feat: add tooltips

* chore: add missing title

* chore: add code comments

* chore: oops

* feat: update descriptions, add tooltip, fix wrapping

* feat: add to all a11y component pages

* fix: update github url to handle names with multiple spaces

* chore: remove console log

* fix: paragraph spacings

* chore: rename component and update theme

* fix: add link component

* fix: anchor links

* fix: url for aspect ratio

* fix: mobile paragraph spacing

---------

Co-authored-by: Taylor Jones <[email protected]>
Co-authored-by: Andrea N. Cardona <[email protected]>
  • Loading branch information
3 people authored Feb 2, 2024
1 parent 2e87101 commit c6abcfb
Show file tree
Hide file tree
Showing 55 changed files with 1,163 additions and 44 deletions.
Binary file modified .yarn/install-state.gz
Binary file not shown.
5 changes: 4 additions & 1 deletion conf.d/rewrite.conf
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,7 @@ rewrite /guidelines/icons/contribute/ /contributing/contribute-icons/ permanent;
rewrite /guidelines/pictograms/contribute/ /contributing/contribute-pictograms/ permanent;

#Grid
rewrite /guidelines/2x-grid/implementation/ /guidelines/2x-grid/usage/ permanent;
rewrite /guidelines/2x-grid/implementation/ /guidelines/2x-grid/usage/ permanent;

#Component overview
rewrite /components/overview/ /components/overview/components/ permanent;
370 changes: 370 additions & 0 deletions src/components/A11yStatus/A11yStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
DefinitionTooltip,
Link,
Toggletip,
ToggletipButton,
ToggletipContent,
} from '@carbon/react';
import A11yStatusTag from '../A11yStatusTag';
import H2 from 'gatsby-theme-carbon/src/components/markdown/H2';
import H3 from 'gatsby-theme-carbon/src/components/markdown/H3';
import { ArrowRight, Help, Launch } from '@carbon/icons-react';
import componentList from '../../data/components.json';
import * as avtTestData from '@carbon/react/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json';
import packageJson from '../../../package.json';

import {
headingLink,
help,
moreLink,
table,
version,
} from './a11y-status.module.scss';

const A11yStatus = ({ components }) => {
const reactVersion = packageJson.dependencies['@carbon/react'];

// Check if 'components' is a string and convert it to an array
const componentsArray =
typeof components === 'string' ? [components] : components;

// Check if 'componentsArray' exists and has elements
const filteredComponentList =
componentsArray && componentsArray.length
? // If 'componentsArray' is valid, filter 'componentList.components' based on the order of 'componentsArray'
componentsArray
.map((component) =>
componentList.components.find(
(item) => item.component === component
)
)
.filter((item) => item !== undefined)
: // If 'componentsArray' is not provided or is empty, filter based on 'a11ystatus'
componentList.components.filter((item) => item.a11ystatus !== false);

const helpTooltip = (
<Toggletip className={help}>
<ToggletipButton label="Help">
<Help size={20} />
</ToggletipButton>
<ToggletipContent>
<p>
For every latest release, Carbon runs tests on all components to meet
the{' '}
<Link
inline
href="https://www.ibm.com/able/requirements/requirements/">
accessibility requirements
</Link>
. These different statuses report the work that Carbon has done in the
back end. These tests appear only when the components are stable.
</p>
</ToggletipContent>
</Toggletip>
);

return (
<>
<div className="cds--row">
<div className="cds--col-lg-12">
{components ? (
<H3>
Accessibility testing status
{helpTooltip}
</H3>
) : (
<>
<span
id="all-component-accessibility-status-anchor"
className={headingLink}></span>
<H2>
<span id="all-component-accessibility-status"></span>
All component accessibility status
{helpTooltip}
</H2>
<p>
This table reflects the current AVT status of stable components
within @carbon/react.
</p>
</>
)}
<p className={version}>
<strong>Latest version:</strong> {reactVersion} |{' '}
<strong>Framework</strong> React (@carbon/react)
</p>
</div>
<div
className={`${table} cds--col-lg-12 cds--col-no-gutter page-table__container`}>
<table className="page-table">
<thead>
<tr>
<th>Component</th>
<th>Accessibility test</th>
<th>Status</th>
<th>Link to source code</th>
</tr>
</thead>
<tbody>
{Object.keys(filteredComponentList).map((component) => {
const componentName =
filteredComponentList[component].component;
const componentTestData = avtTestData.default.suites.find(
(suite) => {
return suite.title
.toLowerCase()
.includes(componentName.toLowerCase().replace(' ', ''));
}
);

const githubUrl = `https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/${componentName
.replace(/\b\w/g, (char) => char.toUpperCase())
.replace(/\s+/g, '')}`;

// Function to check if the spec has a specific tag and
// if the status is skipped
function checkAVTStatus(componentTestData, tag) {
let hasAVT = false;
let hasSkippedAVT = false;

// Check if componentTestData exists
if (componentTestData) {
// Check for the presence of the specified tag in any spec
hasAVT = componentTestData.suites.some((suite) => {
const searchSuites = suite.suites || [suite];
return searchSuites.some((innerSuite) =>
innerSuite.specs.some((spec) =>
spec.tags.some((specTag) => specTag.includes(tag))
)
);
});

// Check if any spec with the specified tag has tests with status 'skipped'
// this will render partially tested tag
hasSkippedAVT = componentTestData.suites.some((suite) =>
(suite.suites || [suite]).some((innerSuite) =>
innerSuite.specs.some(
(spec) =>
spec.tags?.includes(tag) &&
spec.tests.some((test) => test.status === 'skipped')
)
)
);
}

return { hasAVT, hasSkippedAVT };
}

// Check AVT status for 'avt-default-state'
const {
hasAVT: hasDefaultAVT,
hasSkippedAVT: hasSkippedDefaultAVT,
} = checkAVTStatus(componentTestData, 'avt-default-state');

// Check AVT status for 'avt-advanced-states'
const {
hasAVT: hasAdvancedAVT,
hasSkippedAVT: hasSkippedAdvancedAVT,
} = checkAVTStatus(componentTestData, 'avt-advanced-states');

// Check AVT status for 'avt-keyboard-nav'
const {
hasAVT: hasKeyboardNavAVT,
hasSkippedAVT: hasSkippedKeyboardNavAVT,
} = checkAVTStatus(componentTestData, 'avt-keyboard-nav');

// tag for default AVT
let defaultAVTTag;
if (hasSkippedDefaultAVT == true) {
defaultAVTTag = <A11yStatusTag tag="partial" />;
} else if (hasDefaultAVT == true) {
defaultAVTTag = <A11yStatusTag tag="tested" />;
} else {
defaultAVTTag = <A11yStatusTag tag="nottested" />;
}

// tag for advanced AVT
let advancedAVTTag;
if (hasSkippedAdvancedAVT == true) {
advancedAVTTag = <A11yStatusTag tag="partial" />;
} else if (hasAdvancedAVT == true) {
advancedAVTTag = <A11yStatusTag tag="tested" />;
} else {
advancedAVTTag = <A11yStatusTag tag="nottested" />;
}

// tag for keyboard AVT
let keyboardNavAVTTag;
if (hasSkippedKeyboardNavAVT == true) {
keyboardNavAVTTag = <A11yStatusTag tag="partial" />;
} else if (hasKeyboardNavAVT == true) {
keyboardNavAVTTag = <A11yStatusTag tag="tested" />;
} else {
keyboardNavAVTTag = <A11yStatusTag tag="notavailable" />;
}

// tag for screen reader AVT
const screenReaderAVT =
filteredComponentList[component]?.testing.screenreader;
let screenReaderAVTTag;
switch (screenReaderAVT) {
case 'manual':
screenReaderAVTTag = <A11yStatusTag tag="manual" />;
break;
case 'partial':
screenReaderAVTTag = <A11yStatusTag tag="partial" />;
break;
case 'notavailable':
screenReaderAVTTag = <A11yStatusTag tag="notavailable" />;
break;
default:
screenReaderAVTTag = <A11yStatusTag tag="nottested" />;
}

// link for component name in table
let componentUrl;
if (componentName === 'Aspect ratio') {
componentUrl = '/guidelines/2x-grid/overview/#aspect-ratio';
} else if (componentName === 'Grid') {
componentUrl = '/guidelines/2x-grid/code#css-grid';
} else if (componentName === 'Flex grid') {
componentUrl = '/guidelines/2x-grid/code#flexbox-grid';
} else if (componentName === 'UI Shell') {
componentUrl = '/components/UI-shell-header/usage';
} else if (componentName === 'Theme') {
componentUrl = '/guidelines/themes/overview/';
} else if (componentName === 'Skeleton') {
componentUrl = '/patterns/loading-pattern/#skeleton-states';
} else if (componentName === 'Layer') {
componentUrl =
'/guidelines/color/usage#implementing-layering';
}

// if a parent component is set link to the parent component
else if (filteredComponentList[component].parentComponent) {
componentUrl = `/components/${filteredComponentList[
component
].parentComponent
.toLowerCase()
.replace(' ', '-')}/usage`;
}
// if component isn't linked on overview page and no parent
// component set then there is no where to link to so set
// to null
else if (
filteredComponentList[component].overview === false &&
filteredComponentList[component].parentComponent === undefined
) {
componentUrl = null;
} else {
componentUrl = `/components/${componentName
.toLowerCase()
.replace(' ', '-')}/usage`;
}

return (
<React.Fragment key={`avt-tests-${componentName}`}>
<tr>
<td>
{componentUrl === null ? (
componentName
) : (
<Link href={componentUrl}>{componentName}</Link>
)}
</td>
<td>
{' '}
<DefinitionTooltip
openOnHover
definition="Test(s) that ensure the initial render state of a component is accessible.">
Default state
</DefinitionTooltip>
</td>
<td>{defaultAVTTag}</td>
<td>
<Link
href={githubUrl}
renderIcon={() => <Launch aria-label="Launch" />}>
Github link
</Link>
</td>
</tr>
<tr>
<td></td>
<td>
<DefinitionTooltip
openOnHover
definition="Tests that ensure additional states of the component are accessible. This could be interactive states of a component or its multiple variants.">
Advanced states
</DefinitionTooltip>
</td>
<td>{advancedAVTTag}</td>
<td></td>
</tr>
<tr>
<td></td>
<td>
{' '}
<DefinitionTooltip
openOnHover
definition="Tests that ensure focus is properly managed, and all interactive functions of a component have a proper keyboard-accessible equivalent.">
Keyboard navigation
</DefinitionTooltip>
</td>
<td>{keyboardNavAVTTag}</td>
<td></td>
</tr>
<tr>
<td></td>
<td>
<DefinitionTooltip
openOnHover
definition="This manual testing ensures that the visual information on the screen is properly conveyed and read correctly by screen readers such as JAWS, VoiceOver, and NVDA.">
Screen reader
</DefinitionTooltip>
</td>
<td>{screenReaderAVTTag}</td>
<td></td>
</tr>
</React.Fragment>
);
})}
</tbody>
</table>
</div>
</div>
{components && (
<div className="cds--row">
<div className="cds--col-lg-12">
<p className={moreLink}>
<Link
href="/components/overview/accessibility-status"
renderIcon={() => <ArrowRight />}>
Learn more about tag and test meaning
</Link>
<br />
<Link
href="/components/overview/accessibility-status#all-component-accessibility-status-anchor"
renderIcon={() => <ArrowRight />}>
View all component accessibility status
</Link>
</p>
</div>
</div>
)}
</>
);
};

A11yStatus.propTypes = {
/**
* Components to render in the table
*/
components: PropTypes.oneOfType([
PropTypes.string, // for a single component
PropTypes.arrayOf(PropTypes.string), // for multiple components
]),
};

export default A11yStatus;
Loading

0 comments on commit c6abcfb

Please sign in to comment.