|
|
|
|
|
|
|
import React from 'react'; |
|
import * as iconsMap from './icons'; |
|
import './index.css'; |
|
|
|
const alias = {}; |
|
type AliasKeys = keyof typeof alias; |
|
const localIcons = ["github","google"] as const; |
|
type LocalIconsKeys = typeof localIcons[number]; |
|
|
|
type IconCollections = 'academicons' | |
|
'akar-icons' | |
|
'ant-design' | |
|
'arcticons' | |
|
'basil' | |
|
'bi' | |
|
'bpmn' | |
|
'brandico' | |
|
'bx' | |
|
'bxl' | |
|
'bxs' | |
|
'bytesize' | |
|
'carbon' | |
|
'charm' | |
|
'ci' | |
|
'cib' | |
|
'cif' | |
|
'cil' | |
|
'circle-flags' | |
|
'circum' | |
|
'clarity' | |
|
'codicon' | |
|
'cryptocurrency-color' | |
|
'cryptocurrency' | |
|
'dashicons' | |
|
'ei' | |
|
'el' | |
|
'emblemicons' | |
|
'emojione-monotone' | |
|
'emojione-v1' | |
|
'emojione' | |
|
'entypo-social' | |
|
'entypo' | |
|
'eos-icons' | |
|
'ep' | |
|
'et' | |
|
'eva' | |
|
'fa-brands' | |
|
'fa-regular' | |
|
'fa-solid' | |
|
'fa' | |
|
'fa6-brands' | |
|
'fa6-regular' | |
|
'fa6-solid' | |
|
'fad' | |
|
'fe' | |
|
'feather' | |
|
'file-icons' | |
|
'flag' | |
|
'flagpack' | |
|
'flat-color-icons' | |
|
'flat-ui' | |
|
'fluent-emoji-flat' | |
|
'fluent-emoji-high-contrast' | |
|
'fluent-emoji' | |
|
'fluent-mdl2' | |
|
'fluent' | |
|
'fontelico' | |
|
'fontisto' | |
|
'foundation' | |
|
'fxemoji' | |
|
'gala' | |
|
'game-icons' | |
|
'geo' | |
|
'gg' | |
|
'gis' | |
|
'gridicons' | |
|
'grommet-icons' | |
|
'healthicons' | |
|
'heroicons-outline' | |
|
'heroicons-solid' | |
|
'heroicons' | |
|
'humbleicons' | |
|
'ic' | |
|
'icomoon-free' | |
|
'icon-park-outline' | |
|
'icon-park-solid' | |
|
'icon-park-twotone' | |
|
'icon-park' | |
|
'iconoir' | |
|
'icons8' | |
|
'il' | |
|
'ion' | |
|
'iwwa' | |
|
'jam' | |
|
'la' | |
|
'line-md' | |
|
'logos' | |
|
'ls' | |
|
'lucide' | |
|
'majesticons' | |
|
'maki' | |
|
'map' | |
|
'material-symbols' | |
|
'mdi-light' | |
|
'mdi' | |
|
'medical-icon' | |
|
'memory' | |
|
'mi' | |
|
'mingcute' | |
|
'mono-icons' | |
|
'nimbus' | |
|
'nonicons' | |
|
'noto-v1' | |
|
'noto' | |
|
'octicon' | |
|
'oi' | |
|
'ooui' | |
|
'openmoji' | |
|
'pajamas' | |
|
'pepicons-pop' | |
|
'pepicons-print' | |
|
'pepicons' | |
|
'ph' | |
|
'pixelarticons' | |
|
'prime' | |
|
'ps' | |
|
'quill' | |
|
'radix-icons' | |
|
'raphael' | |
|
'ri' | |
|
'si-glyph' | |
|
'simple-icons' | |
|
'simple-line-icons' | |
|
'skill-icons' | |
|
'subway' | |
|
'svg-spinners' | |
|
'system-uicons' | |
|
'tabler' | |
|
'teenyicons' | |
|
'topcoat' | |
|
'twemoji' | |
|
'typcn' | |
|
'uil' | |
|
'uim' | |
|
'uis' | |
|
'uit' | |
|
'uiw' | |
|
'vaadin' | |
|
'vs' | |
|
'vscode-icons' | |
|
'websymbol' | |
|
'whh' | |
|
'wi' | |
|
'wpf' | |
|
'zmdi' | |
|
'zondicons'; |
|
type Icon = `${IconCollections}:${string}`; |
|
|
|
interface IUmiIconProps extends React.SVGAttributes<SVGElement> { |
|
icon: AliasKeys | Icon | `local:${LocalIconsKeys}`; |
|
hover?: AliasKeys | string; |
|
className?: string; |
|
viewBox?: string; |
|
width?: string; |
|
height?: string; |
|
style?: any; |
|
spin?: boolean; |
|
rotate?: number | string; |
|
flip?: 'vertical' | 'horizontal' | 'horizontal,vertical' | 'vertical,horizontal'; |
|
} |
|
|
|
export const Icon = React.forwardRef<HTMLSpanElement, IUmiIconProps>((props, ref) => { |
|
const { icon, hover, style, className = '' , rotate, spin, flip, ...extraProps } = props; |
|
const iconName = normalizeIconName(alias[icon] || icon); |
|
const Component = iconsMap[iconName]; |
|
if (!Component) { |
|
|
|
return null; |
|
} |
|
const HoverComponent = hover ? iconsMap[normalizeIconName(alias[hover] || hover)] : null; |
|
const cls = spin ? 'umiIconLoadingCircle' : undefined; |
|
const svgStyle = {}; |
|
const transform: string[] = []; |
|
if (rotate) { |
|
const rotateDeg = normalizeRotate(rotate); |
|
transform.push(`rotate(${rotateDeg}deg)`); |
|
} |
|
if (flip) { |
|
const flipMap = flip.split(',').reduce((memo, item) => { |
|
memo[item] = 1; |
|
return memo; |
|
}, {}); |
|
if (flipMap.vertical) { |
|
transform.push(`rotateY(180deg)`); |
|
} |
|
if (flipMap.horizontal) { |
|
transform.push(`rotateX(180deg)`); |
|
} |
|
} |
|
if (transform.length) { |
|
const transformStr = transform.join(''); |
|
svgStyle.msTransform = transformStr; |
|
svgStyle.transform = transformStr; |
|
} |
|
|
|
const spanClassName = HoverComponent ? 'umiIconDoNotUseThis ' : '' + className; |
|
const spanClass = spanClassName ? { className: spanClassName } : {}; |
|
|
|
return ( |
|
<span role="img" ref={ref} {...spanClass} style={style}> |
|
<Component {...extraProps} className={cls} style={svgStyle} /> |
|
{ |
|
HoverComponent ? <HoverComponent {...extraProps} className={'umiIconDoNotUseThisHover ' + cls} style={svgStyle} /> : null |
|
} |
|
</span> |
|
); |
|
}); |
|
|
|
function normalizeRotate(rotate: number | string) { |
|
if (typeof rotate === 'number') { |
|
return rotate * 90; |
|
} |
|
if (typeof rotate === 'string') { |
|
if (rotate.endsWith('deg')) { |
|
return parseInt(rotate, 10); |
|
} |
|
if (rotate.endsWith('%')) { |
|
return parseInt(rotate, 10) / 100 * 360; |
|
} |
|
return 0; |
|
} |
|
} |
|
|
|
function camelCase(str: string) { |
|
return str.replace(/\//g, '-').replace(/-([a-zA-Z]|[1-9])/g, (g) => g[1].toUpperCase()); |
|
} |
|
|
|
function normalizeIconName(name: string) { |
|
return camelCase(name.replace(':', '-')); |
|
} |
|
|