1- import React , { DOMAttributes , FC , useState , useMemo } from 'react'
1+ import PropTypes from 'prop-types'
2+ import React , { DOMAttributes , forwardRef , useState , useMemo } from 'react'
23import classNames from 'classnames'
34import './CIcon.css'
45
5- export interface CIconProps extends DOMAttributes < SVGSVGElement | HTMLImageElement > {
6+ export interface CIconProps extends DOMAttributes < SVGSVGElement > {
67 /**
78 * A string of all className you want applied to the component. [docs]
89 */
@@ -18,15 +19,23 @@ export interface CIconProps extends DOMAttributes<SVGSVGElement|HTMLImageElement
1819 /**
1920 * Size of the icon. Available sizes: 'sm', 'lg', 'xl', '2xl'...'9xl', 'custom', 'custom-size'. [docs]
2021 */
21- size ?: 'custom' | 'custom-size' | 'sm' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | '8xl' | '9xl'
22+ size ?:
23+ | 'custom-size'
24+ | 'sm'
25+ | 'lg'
26+ | 'xl'
27+ | '2xl'
28+ | '3xl'
29+ | '4xl'
30+ | '5xl'
31+ | '6xl'
32+ | '7xl'
33+ | '8xl'
34+ | '9xl'
2235 /**
2336 * Use for replacing default CIcon component classes. Prop is overriding the 'size' prop. [docs]
2437 */
25- customClasses ?: string | object | Array < string >
26- /**
27- * Link to the icon. If defined component will be rendered as 'img' tag. [docs]
28- */
29- src ?: string
38+ customClassName ?: string | object | Array < string >
3039 /**
3140 * If defined component will be rendered using 'use' tag. [docs]
3241 */
@@ -35,8 +44,8 @@ export interface CIconProps extends DOMAttributes<SVGSVGElement|HTMLImageElement
3544 * Title tag content. [docs]
3645 */
3746 title ?: string
38- width ?: string
39- height ?: string
47+ // width?: string
48+ // height?: string
4049}
4150
4251let warned = { }
@@ -48,127 +57,106 @@ const colog = (msg: string, icon?: string) => {
4857}
4958
5059const toCamelCase = ( str : string ) => {
51- return str . replace ( / ( [ - _ ] [ a - z 0 - 9 ] ) / ig, ( $1 ) => {
52- return $1 . toUpperCase ( )
53- } ) . replace ( / - / ig, '' )
60+ return str
61+ . replace ( / ( [ - _ ] [ a - z 0 - 9 ] ) / gi, ( $1 ) => {
62+ return $1 . toUpperCase ( )
63+ } )
64+ . replace ( / - / gi, '' )
5465}
5566
56- //component - CoreUI / CIcon
57- const CIcon : FC < CIconProps > = ( {
58- className,
59- name,
60- content,
61- customClasses,
62- size,
63- src,
64- title,
65- use,
66- ...rest
67- } ) => {
68-
69- const [ change , setChange ] = useState ( 0 )
70-
71- useMemo ( ( ) => setChange ( change + 1 ) , [ name , JSON . stringify ( content ) ] )
72-
73- const iconName = useMemo ( ( ) => ( name && name . includes ( '-' ) ) ? toCamelCase ( name ) : name , [ change ] )
74-
75- const titleCode = title ? `<title>${ title } </title>` : ''
76-
77- const code = useMemo ( ( ) => {
78- if ( content ) {
79- return content
80- } else if ( name && React [ 'icons' ] ) {
81- return React [ 'icons' ] [ iconName ] ? React [ 'icons' ] [ iconName ] :
82- colog ( `CIcon component: icon name '${ iconName } ' does not exist in React.icons object. ` +
83- `To use icons by 'name' prop you need to make them available globally ` +
84- `by adding them to React.icons object. CIcon component docs: https://coreui.io/react/docs/components/CIcon \n` ,
85- iconName
86- )
87- }
88- } , [ change ] )
67+ export const CIcon = forwardRef < SVGSVGElement , CIconProps > (
68+ ( { className, name, content, customClassName, size, title, use, ...rest } , ref ) => {
69+ const [ change , setChange ] = useState ( 0 )
8970
90- const iconCode = useMemo ( ( ) => {
91- return Array . isArray ( code ) ? code [ 1 ] || code [ 0 ] : code
92- } , [ change ] )
71+ useMemo ( ( ) => setChange ( change + 1 ) , [ name , JSON . stringify ( content ) ] )
9372
94- const scale = ( ( ) => {
95- return Array . isArray ( code ) && code . length > 1 ? code [ 0 ] : '64 64'
96- } ) ( )
73+ const iconName = useMemo (
74+ ( ) => ( name && name . includes ( '-' ) ? toCamelCase ( name ) : name ) ,
75+ [ change ] ,
76+ )
9777
98- const viewBox = ( ( ) => {
99- return rest [ 'viewBox' ] || `0 0 ${ scale } `
100- } ) ( )
78+ const titleCode = title ? `<title>${ title } </title>` : ''
79+
80+ const code = useMemo ( ( ) => {
81+ if ( content ) {
82+ return content
83+ } else if ( name && React [ 'icons' ] ) {
84+ return React [ 'icons' ] [ iconName ]
85+ ? React [ 'icons' ] [ iconName ]
86+ : colog (
87+ `CIcon component: icon name '${ iconName } ' does not exist in React.icons object. ` +
88+ `To use icons by 'name' prop you need to make them available globally ` +
89+ `by adding them to React.icons object. CIcon component docs: https://coreui.io/react/docs/components/CIcon \n` ,
90+ iconName ,
91+ )
92+ }
93+ } , [ change ] )
10194
102- // render
95+ const iconCode = useMemo ( ( ) => {
96+ return Array . isArray ( code ) ? code [ 1 ] || code [ 0 ] : code
97+ } , [ change ] )
10398
104- let classes
99+ const scale = ( ( ) => {
100+ return Array . isArray ( code ) && code . length > 1 ? code [ 0 ] : '64 64'
101+ } ) ( )
105102
106- if ( customClasses ) {
107- classes = classNames (
108- customClasses
109- )
110- }
111- else
112- {
113- const computedSize = ( ( ) => {
114- const addCustom = ! size && ( rest [ 'width' ] || rest [ 'height' ] )
115- return size === 'custom' || addCustom ? 'custom-size' : size
103+ const viewBox = ( ( ) => {
104+ return rest [ 'viewBox' ] || `0 0 ${ scale } `
116105 } ) ( )
117- classes = classNames (
118- 'c-icon' ,
119- computedSize && `c-icon-${ computedSize } ` ,
120- className
121- )
122- }
123- //const classes = customClasses || computedClasses
124-
125- // let restImg: HTMLAttributes<HTMLImageElement> = {}
126- // if (src && !use) {
127- // restImg = rest as HTMLAttributes<HTMLImageElement>
128- // }
129-
130- return (
131- < React . Fragment >
132- { ! src && ! use &&
133- < svg
134- { ...rest }
135- xmlns = "http://www.w3.org/2000/svg"
136- viewBox = { viewBox }
137- className = { classes }
138- role = "img"
139- dangerouslySetInnerHTML = { { __html : titleCode + iconCode } }
140- />
141- }
142- { src && ! use &&
143- < img
144- { ...rest }
145- className = { className }
146- src = { src }
147- role = "img"
148- />
149- }
150- { ! src && use &&
151- < svg
152- { ...rest }
153- xmlns = "http://www.w3.org/2000/svg"
154- className = { classes }
155- role = "img"
156- >
157- < use href = { use } > </ use >
158- </ svg >
159- }
160- </ React . Fragment >
161- )
162106
107+ // render
108+
109+ const _className = customClassName
110+ ? classNames ( customClassName )
111+ : classNames (
112+ 'icon' ,
113+ {
114+ [ `icon-${ size } ` ] : size ,
115+ [ `icon-custom-size` ] : rest [ 'height' ] || rest [ 'width' ]
116+ } ,
117+ className ,
118+ )
119+
120+ colog ( '@coreui/icons-react: Please use default export since named exports are deprecated' )
121+ return use ? (
122+ < svg xmlns = "http://www.w3.org/2000/svg" className = { _className } role = "img" { ...rest } ref = { ref } >
123+ < use href = { use } > </ use >
124+ </ svg >
125+ ) : (
126+ < svg
127+ xmlns = "http://www.w3.org/2000/svg"
128+ viewBox = { viewBox }
129+ className = { _className }
130+ role = "img"
131+ dangerouslySetInnerHTML = { { __html : titleCode + iconCode } }
132+ { ...rest }
133+ ref = { ref }
134+ />
135+ )
136+ } ,
137+ )
138+
139+ CIcon . propTypes = {
140+ className : PropTypes . any ,
141+ content : PropTypes . any ,
142+ customClassName : PropTypes . any ,
143+ name : PropTypes . string ,
144+ size : PropTypes . oneOf ( [
145+ 'custom-size' ,
146+ 'sm' ,
147+ 'lg' ,
148+ 'xl' ,
149+ '2xl' ,
150+ '3xl' ,
151+ '4xl' ,
152+ '5xl' ,
153+ '6xl' ,
154+ '7xl' ,
155+ '8xl' ,
156+ '9xl' ,
157+ ] ) ,
158+ title : PropTypes . any ,
159+ use : PropTypes . any ,
163160}
164161
165- export default CIcon
166-
167- //
168-
169- export const CIconWarn : FC < CIconProps > = ( props ) => {
170- colog (
171- '@coreui/icons-react: Please use default export since named exports are deprecated'
172- )
173- return < CIcon { ...props } />
174- }
162+ CIcon . displayName = 'CIcon'
0 commit comments