You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.9 KiB
117 lines
2.9 KiB
import IconAll, { ALL_ICON_KEYS, IconType as ParkIconType, IIconAllProps } from '@icon-park/react/es/all'
|
|
import React, { Fragment } from 'react'
|
|
import * as AntIcons from '@ant-design/icons/es/icons'
|
|
|
|
import IconItem from './picker/IconRender.tsx'
|
|
import { IconUnit } from './types.ts'
|
|
import { createStyles } from '@/theme'
|
|
|
|
|
|
type Prefix = 'antd:' | 'park:';
|
|
type IconType = `${Prefix}${string}`;
|
|
|
|
const useStyles = createStyles(({ css, cx }, props: any) => {
|
|
|
|
const keyframes = css`
|
|
@keyframes rotating {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
`
|
|
|
|
const container = css`
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
`
|
|
|
|
const size = props.size ? css`
|
|
height: ${props.size}px;
|
|
width: ${props.size}px;
|
|
line-height: ${props.size}px;
|
|
` : ''
|
|
|
|
const isLoading = css`
|
|
animation: rotating 2s linear infinite;
|
|
`
|
|
return {
|
|
container: cx( container, size, props.className),
|
|
isLoading: cx(keyframes, size, isLoading)
|
|
}
|
|
})
|
|
|
|
interface IconProps extends Pick<IconUnit, 'type'> {
|
|
type: IconType | IconUnit['type']
|
|
isLoading?: boolean
|
|
|
|
[key: string]: any
|
|
}
|
|
|
|
function isAntdOrParkIcon(value: string): value is IconType {
|
|
return value.startsWith('antd:') || value.startsWith('park:')
|
|
}
|
|
|
|
export function Icon(props: IconProps) {
|
|
|
|
const { styles, cx } = useStyles(props)
|
|
|
|
const { type, isLoading, ...other } = props
|
|
if (type && isAntdOrParkIcon(type)) {
|
|
const [ t, c ] = type.split(':')
|
|
return <IconItem {...other as any} type={t} componentName={c}/>
|
|
}
|
|
|
|
const AntIcon = AntIcons[type as keyof typeof AntIcons]
|
|
if (AntIcon) {
|
|
return <AntIcon {...other}/>
|
|
}
|
|
|
|
//如果是http或https链接,直接返回图片
|
|
if (type && (type.startsWith('http') || type.startsWith('https') || type.startsWith('data:image'))) {
|
|
// @ts-ignore 没有办法把所有的属性都传递给img
|
|
return <img src={type} alt="icon" width={16} height={16} {...other}/>
|
|
}
|
|
|
|
if (ALL_ICON_KEYS.indexOf(type as ParkIconType) < 0) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<Fragment>
|
|
<IconAll type={type as IconType}
|
|
className={cx(styles.container, {
|
|
[styles.isLoading]: isLoading,
|
|
})}
|
|
theme="outline"
|
|
size={other.size ?? 20}
|
|
// fill="#868686"
|
|
strokeWidth={3}
|
|
{...other}/>
|
|
</Fragment>
|
|
)
|
|
}
|
|
|
|
// eslint-disable-next-line react-refresh/only-export-components
|
|
export const getIcon = (type: string, props?: Partial<IIconAllProps>) => {
|
|
|
|
if (React.isValidElement(type)) {
|
|
return type
|
|
}
|
|
//判断是否为json格式
|
|
if (type && type.startsWith('{') && type.endsWith('}')) {
|
|
try {
|
|
const obj = JSON.parse(type)
|
|
type = obj.type
|
|
props = obj
|
|
} catch (e) { /* empty */
|
|
}
|
|
}
|
|
|
|
return <Icon type={type} {...props}/>
|
|
}
|
|
|
|
export default Icon
|