@@ -4,15 +4,13 @@ import React, {
44 SVGAttributes ,
55 useContext ,
66 useRef ,
7- useState ,
87 useEffect ,
98 useCallback ,
109} from 'react' ;
1110import classnames from 'classnames' ;
1211import svg4everybody from 'svg4everybody' ;
1312import { registerStyle , getAssetRoot } from './util' ;
1413import { ComponentSettingsContext } from './ComponentSettings' ;
15- import { useEventCallback } from './hooks' ;
1614import { createFC } from './common' ;
1715
1816svg4everybody ( ) ;
@@ -222,23 +220,19 @@ function useInitComponentStyle() {
222220
223221function getIconColor (
224222 fillColor : string | undefined ,
225- category : string | undefined ,
223+ category : IconCategory ,
226224 icon : string
227225) {
228226 /* eslint-disable no-unneeded-ternary */
229- return category === 'doctype'
230- ? null
231- : fillColor === 'none'
227+ return fillColor === 'none'
232228 ? null
233229 : fillColor
234230 ? fillColor
235231 : category === 'utility'
236232 ? null
237- : category === 'custom'
238- ? icon . replace ( / ^ c u s t o m / , 'custom-' )
239- : category === 'action' && / ^ n e w _ c u s t o m / . test ( icon )
233+ : category === 'action' && / ^ n e w _ c u s t o m / . test ( icon ) // not needed for the current SLDS2 icons
240234 ? icon . replace ( / ^ n e w _ c u s t o m / , 'custom-' )
241- : `${ category ?? '' } -${ ( icon ?? '' ) . replace ( / _ / g, '-' ) } ` ;
235+ : `${ category } -${ icon . replace ( / _ / g, '-' ) } ` ;
242236 /* eslint-enable no-unneeded-ternary */
243237}
244238
@@ -251,14 +245,21 @@ export type IconCategory =
251245 | 'doctype'
252246 | 'standard'
253247 | 'utility' ;
254- export type IconSize = 'x-small' | 'small' | 'medium' | 'large' ;
255- export type IconContainer = boolean | 'default' | 'circle' ;
256- export type IconTextColor = 'default' | 'warning' | 'error' | null ;
248+ export type IconSize = 'xx-small' | 'x-small' | 'small' | 'medium' | 'large' ;
249+ export type IconContainer = 'circle' ;
250+ export type IconTextColor =
251+ | 'default'
252+ | 'success'
253+ | 'warning'
254+ | 'error'
255+ | 'light'
256+ | null ;
257257
258258/**
259259 *
260260 */
261261export type IconProps = {
262+ label ?: string ;
262263 containerClassName ?: string ;
263264 category ?: IconCategory ;
264265 icon : string ;
@@ -290,7 +291,6 @@ const SvgIcon = forwardRef(
290291 iconColor,
291292 size = '' ,
292293 align,
293- container,
294294 textColor = 'default' ,
295295 style,
296296 ...rprops
@@ -300,10 +300,10 @@ const SvgIcon = forwardRef(
300300 'react-slds-icon' ,
301301 {
302302 'slds-icon' : ! / s l d s - b u t t o n _ _ i c o n / . test ( className ) ,
303- [ `slds-icon_${ size } ` ] : / ^ ( x - s m a l l | s m a l l | m e d i u m | l a r g e ) $ / . test ( size ) ,
303+ [ `slds-icon_${ size } ` ] : / ^ ( x x - s m a l l | x - s m a l l | s m a l l | l a r g e ) $ / . test ( size ) ,
304304 [ `slds-icon-text-${ textColor ?? 'default' } ` ] :
305- / ^ ( d e f a u l t | w a r n i n g | e r r o r ) $ / . test ( textColor ?? '' ) && ! iconColor ,
306- [ `slds-icon- ${ iconColor ?? '' } ` ] : ! container && iconColor ,
305+ / ^ ( d e f a u l t | s u c c e s s | w a r n i n g | e r r o r | l i g h t ) $ / . test ( textColor ?? '' ) &&
306+ ! iconColor ,
307307 'slds-m-left_x-small' : align === 'right' ,
308308 'slds-m-right_x-small' : align === 'left' ,
309309 } ,
@@ -327,18 +327,43 @@ const SvgIcon = forwardRef(
327327 }
328328) ;
329329
330+ export const SvgButtonIcon = (
331+ props : {
332+ className ?: string ;
333+ category ?: IconCategory ;
334+ icon : string ;
335+ } & SVGAttributes < SVGElement >
336+ ) => {
337+ const {
338+ className = '' ,
339+ category : category_ = 'utility' ,
340+ icon : icon_ ,
341+ style,
342+ ...rprops
343+ } = props ;
344+ const { assetRoot = getAssetRoot ( ) } = useContext ( ComponentSettingsContext ) ;
345+
346+ // icon and category prop should not include chars other than alphanumerics, underscore, and hyphen
347+ const icon = ( icon_ ?? '' ) . replace ( / [ ^ \w - ] / g, '' ) ; // eslint-disable-line no-param-reassign
348+ const category = ( category_ ?? '' ) . replace ( / [ ^ \w - ] / g, '' ) ; // eslint-disable-line no-param-reassign
349+ const iconUrl = `${ assetRoot } /icons/${ category } -sprite/svg/symbols.svg#${ icon } ` ;
350+ return (
351+ < svg className = { className } aria-hidden style = { style } { ...rprops } >
352+ < use xlinkHref = { iconUrl } />
353+ </ svg >
354+ ) ;
355+ } ;
330356/**
331357 *
332358 */
333359export const Icon = createFC < IconProps , { ICONS : typeof ICONS } > (
334360 ( props ) => {
335- const { container, containerClassName, fillColor, ...rprops } = props ;
361+ const { label, container, containerClassName, fillColor, ...rprops } =
362+ props ;
336363 let { category = 'utility' , icon } = props ;
337364
338365 useInitComponentStyle ( ) ;
339366
340- const iconContainerRef = useRef < HTMLSpanElement | null > ( null ) ;
341-
342367 const svgIconRef = useRef < SVGSVGElement | null > ( null ) ;
343368
344369 const svgIconRefCallback = useCallback (
@@ -351,72 +376,37 @@ export const Icon = createFC<IconProps, { ICONS: typeof ICONS }>(
351376 [ props . tabIndex ]
352377 ) ;
353378
354- const [ iconColor , setIconColor ] = useState < string | null > ( null ) ;
355-
356- const checkIconColor = useEventCallback ( ( ) => {
357- if (
358- fillColor ||
359- category === 'doctype' ||
360- ( ! fillColor && category === 'utility' ) ||
361- iconColor === 'standard-default'
362- ) {
363- return ;
364- }
365- const el = container ? iconContainerRef . current : svgIconRef . current ;
366- if ( ! el ) {
367- return ;
368- }
369- const bgColorStyle = getComputedStyle ( el ) . backgroundColor ;
370- // if no background color set to the icon
371- if (
372- bgColorStyle &&
373- / ^ ( t r a n s p a r e n t | r g b a \( 0 , \s * 0 , \s * 0 , \s * 0 \) ) $ / . test ( bgColorStyle )
374- ) {
375- setIconColor ( 'standard-default' ) ;
376- }
377- } ) ;
378-
379379 useEffect ( ( ) => {
380380 svgIconRefCallback ( svgIconRef . current ) ;
381381 } , [ svgIconRefCallback ] ) ;
382382
383- useEffect ( ( ) => {
384- checkIconColor ( ) ;
385- } , [ checkIconColor ] ) ;
386-
387383 if ( icon . indexOf ( ':' ) > 0 ) {
388384 [ category , icon ] = icon . split ( ':' ) as [ IconCategory , string ] ;
389385 }
390386
391- const fillIconColor =
392- iconColor || container ? getIconColor ( fillColor , category , icon ) : null ;
387+ const fillIconColor = getIconColor ( fillColor , category , icon ) ;
393388
394- const svgIcon = (
395- < SvgIcon
396- ref = { svgIconRefCallback }
397- { ...rprops }
398- { ...{
399- container,
400- category,
401- icon,
402- iconColor : fillIconColor ,
403- } }
404- />
389+ const ccontainerClassName = classnames (
390+ containerClassName ,
391+ 'slds-icon_container' ,
392+ container === 'circle' ? 'slds-icon_container_circle' : null ,
393+ category === 'utility' ? `slds-icon-utility-${ icon } ` : null ,
394+ fillIconColor ? `slds-icon-${ fillIconColor } ` : null
395+ ) ;
396+ return (
397+ < span className = { ccontainerClassName } title = { label } >
398+ < SvgIcon
399+ ref = { svgIconRefCallback }
400+ { ...rprops }
401+ { ...{
402+ category,
403+ icon,
404+ iconColor : fillIconColor ,
405+ } }
406+ />
407+ { label ? < span className = 'slds-assistive-text' > { label } </ span > : null }
408+ </ span >
405409 ) ;
406- if ( container ) {
407- const ccontainerClassName = classnames (
408- containerClassName ,
409- 'slds-icon_container' ,
410- container === 'circle' ? 'slds-icon_container_circle' : null ,
411- fillIconColor ? `slds-icon-${ fillIconColor } ` : null
412- ) ;
413- return (
414- < span className = { ccontainerClassName } ref = { iconContainerRef } >
415- { svgIcon }
416- </ span >
417- ) ;
418- }
419- return svgIcon ;
420410 } ,
421411 { ICONS }
422412) ;
0 commit comments