11import React from 'react' ;
2- import PropTypes from 'prop-types' ;
32import classNames from 'classnames' ;
43
54import newId from '../utils/newId' ;
@@ -12,16 +11,53 @@ import withDeprecatedProps, { DeprTypes } from '../withDeprecatedProps';
1211 * - focusable is set to false on the svg in all cases as a workaround for an ie11 bug
1312 */
1413
14+ interface SvgAttrs extends React . SVGAttributes < SVGElement > {
15+ 'aria-label' ?: string ;
16+ 'aria-labelledby' ?: string ;
17+ 'aria-hidden' ?: boolean ;
18+ }
19+
20+ export interface IconProps extends Omit < React . ComponentPropsWithoutRef < 'span' > , 'id' | 'className' > {
21+ /**
22+ * An icon component to render.
23+ * Example import of a Paragon icon component: `import { Check } from '@openedx/paragon/icons';`
24+ */
25+ src ?: React . ComponentType < React . SVGAttributes < SVGElement > > ;
26+ /** HTML element attributes to pass through to the underlying svg element */
27+ svgAttrs ?: SvgAttrs ;
28+ /**
29+ * the `id` property of the Icon element, by default this value is generated
30+ * with the `newId` function with the `prefix` of `Icon`.
31+ */
32+ id ?: string | null ;
33+ /** The size of the icon. */
34+ size ?: 'xs' | 'sm' | 'md' | 'lg' | 'inline' ;
35+ /** A class name that will define what the Icon looks like. */
36+ className ?: string | string [ ] ;
37+ /**
38+ * a boolean that determines the value of `aria-hidden` attribute on the Icon span,
39+ * this value is `true` by default.
40+ */
41+ hidden ?: boolean ;
42+ /**
43+ * a string or an element that will be used on a secondary span leveraging the `sr-only` style
44+ * for screenreader only text, this value is `undefined` by default. This value is recommended for use unless
45+ * the Icon is being used in a way that is purely decorative or provides no additional context for screen
46+ * reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
47+ */
48+ screenReaderText ?: React . ReactNode ;
49+ }
50+
1551function Icon ( {
1652 src : Component ,
1753 id,
1854 className,
19- hidden,
55+ hidden = true ,
2056 screenReaderText,
21- svgAttrs,
57+ svgAttrs = { } ,
2258 size,
2359 ...attrs
24- } ) {
60+ } : IconProps ) {
2561 if ( Component ) {
2662 // If no aria label is specified, hide this icon from screenreaders
2763 const hasAriaLabel = svgAttrs [ 'aria-label' ] || svgAttrs [ 'aria-labelledby' ] ;
@@ -35,8 +71,8 @@ function Icon({
3571
3672 return (
3773 < span
38- className = { classNames ( 'pgn__icon' , { [ `pgn__icon__${ size } ` ] : ! ! size } , className ) }
39- id = { id }
74+ className = { classNames ( 'pgn__icon' , { [ `pgn__icon__${ size } ` ] : ! ! size } , Array . isArray ( className ) ? className . join ( ' ' ) : className ) }
75+ id = { id || undefined }
4076 { ...attrs }
4177 >
4278 < Component
@@ -57,7 +93,7 @@ function Icon({
5793 < >
5894 < span
5995 id = { id || newId ( 'Icon' ) }
60- className = { className }
96+ className = { Array . isArray ( className ) ? className . join ( ' ' ) : className }
6197 aria-hidden = { hidden }
6298 />
6399 { screenReaderText && (
@@ -69,55 +105,11 @@ function Icon({
69105 ) ;
70106}
71107
72- Icon . propTypes = {
73- /**
74- * An icon component to render.
75- * Example import of a Paragon icon component: `import { Check } from '@openedx/paragon/icons';`
76- */
77- src : PropTypes . elementType ,
78- /** HTML element attributes to pass through to the underlying svg element */
79- svgAttrs : PropTypes . shape ( {
80- 'aria-label' : PropTypes . string ,
81- 'aria-labelledby' : PropTypes . string ,
82- } ) ,
83- /**
84- * the `id` property of the Icon element, by default this value is generated
85- * with the `newId` function with the `prefix` of `Icon`.
86- */
87- id : PropTypes . string ,
88- /** The size of the icon. */
89- size : PropTypes . oneOf ( [ 'xs' , 'sm' , 'md' , 'lg' ] ) ,
90- /** A class name that will define what the Icon looks like. */
91- className : PropTypes . string ,
92- /**
93- * a boolean that determines the value of `aria-hidden` attribute on the Icon span,
94- * this value is `true` by default.
95- */
96- hidden : PropTypes . bool ,
97- /**
98- * a string or an element that will be used on a secondary span leveraging the `sr-only` style
99- * for screenreader only text, this value is `undefined` by default. This value is recommended for use unless
100- * the Icon is being used in a way that is purely decorative or provides no additional context for screen
101- * reader users. This field should be thought of the same way an `alt` attribute would be used for `image` tags.
102- */
103- screenReaderText : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . element ] ) ,
104- } ;
105-
106- Icon . defaultProps = {
107- src : null ,
108- svgAttrs : { } ,
109- id : undefined ,
110- hidden : true ,
111- screenReaderText : undefined ,
112- size : undefined ,
113- className : undefined ,
114- } ;
115-
116108export default withDeprecatedProps ( Icon , 'Icon' , {
117109 className : {
118110 deprType : DeprTypes . FORMAT ,
119- expect : value => typeof value === 'string' ,
120- transform : value => ( Array . isArray ( value ) ? value . join ( ' ' ) : value ) ,
111+ expect : ( value : any ) => typeof value === 'string' ,
112+ transform : ( value : any ) => ( Array . isArray ( value ) ? value . join ( ' ' ) : value ) ,
121113 message : 'It should be a string.' ,
122114 } ,
123115} ) ;
0 commit comments