Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions src/Icon/index.d.ts

This file was deleted.

104 changes: 44 additions & 60 deletions src/Icon/index.jsx → src/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import newId from '../utils/newId';
import withDeprecatedProps, { DeprTypes } from '../withDeprecatedProps';

/**
* An svg with an "img" role must satisfy the following a11y requirements
Expand All @@ -12,16 +10,53 @@ import withDeprecatedProps, { DeprTypes } from '../withDeprecatedProps';
* - focusable is set to false on the svg in all cases as a workaround for an ie11 bug
*/

interface SvgAttrs extends React.SVGAttributes<SVGElement> {
'aria-label'?: string;
'aria-labelledby'?: string;
'aria-hidden'?: boolean;
}

export interface IconProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'id' | 'className'> {
/**
* An icon component to render.
* Example import of a Paragon icon component: `import { Check } from '@openedx/paragon/icons';`
*/
src?: React.ComponentType<React.SVGAttributes<SVGElement>>;
/** HTML element attributes to pass through to the underlying svg element */
svgAttrs?: SvgAttrs;
/**
* the `id` property of the Icon element, by default this value is generated
* with the `newId` function with the `prefix` of `Icon`.
*/
id?: string | null;
/** The size of the icon. */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'inline';
/** A class name that will define what the Icon looks like. */
className?: string | string[];
/**
* a boolean that determines the value of `aria-hidden` attribute on the Icon span,
* this value is `true` by default.
*/
hidden?: boolean;
/**
* a string or an element that will be used on a secondary span leveraging the `sr-only` style
* for screenreader only text, this value is `undefined` by default. This value is recommended for use unless
* the Icon is being used in a way that is purely decorative or provides no additional context for screen
* reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
*/
screenReaderText?: React.ReactNode;
}

function Icon({
src: Component,
id,
className,
hidden,
hidden = true,
screenReaderText,
svgAttrs,
svgAttrs = {},
size,
...attrs
}) {
}: IconProps) {
if (Component) {
// If no aria label is specified, hide this icon from screenreaders
const hasAriaLabel = svgAttrs['aria-label'] || svgAttrs['aria-labelledby'];
Expand All @@ -35,8 +70,8 @@ function Icon({

return (
<span
className={classNames('pgn__icon', { [`pgn__icon__${size}`]: !!size }, className)}
id={id}
className={classNames('pgn__icon', { [`pgn__icon__${size}`]: !!size }, Array.isArray(className) ? className.join(' ') : className)}
id={id || undefined}
{...attrs}
>
<Component
Expand All @@ -57,7 +92,7 @@ function Icon({
<>
<span
id={id || newId('Icon')}
className={className}
className={Array.isArray(className) ? className.join(' ') : className}
aria-hidden={hidden}
/>
{screenReaderText && (
Expand All @@ -69,55 +104,4 @@ function Icon({
);
}

Icon.propTypes = {
/**
* An icon component to render.
* Example import of a Paragon icon component: `import { Check } from '@openedx/paragon/icons';`
*/
src: PropTypes.elementType,
/** HTML element attributes to pass through to the underlying svg element */
svgAttrs: PropTypes.shape({
'aria-label': PropTypes.string,
'aria-labelledby': PropTypes.string,
}),
/**
* the `id` property of the Icon element, by default this value is generated
* with the `newId` function with the `prefix` of `Icon`.
*/
id: PropTypes.string,
/** The size of the icon. */
size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
/** A class name that will define what the Icon looks like. */
className: PropTypes.string,
/**
* a boolean that determines the value of `aria-hidden` attribute on the Icon span,
* this value is `true` by default.
*/
hidden: PropTypes.bool,
/**
* a string or an element that will be used on a secondary span leveraging the `sr-only` style
* for screenreader only text, this value is `undefined` by default. This value is recommended for use unless
* the Icon is being used in a way that is purely decorative or provides no additional context for screen
* reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
*/
screenReaderText: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
};

Icon.defaultProps = {
src: null,
svgAttrs: {},
id: undefined,
hidden: true,
screenReaderText: undefined,
size: undefined,
className: undefined,
};

export default withDeprecatedProps(Icon, 'Icon', {
className: {
deprType: DeprTypes.FORMAT,
expect: value => typeof value === 'string',
transform: value => (Array.isArray(value) ? value.join(' ') : value),
message: 'It should be a string.',
},
});
export default Icon;
Loading