/**
* Icon Component - Lynx 版 MUI Icon
*
* 由于 Lynx 不支持直接渲染 SVG,本组件提供多种图标显示方案:
*
* 1. **SVG 文件** - 使用 image 元素加载 SVG 文件
* 2. **字体图标** - 使用 text 元素 + icon font
* 3. **Unicode/Emoji** - 直接显示 emoji 或 unicode 字符
* 4. **Base64** - 支持 base64 编码的图标
*
* 使用示例:
* ```tsx
* // SVG 文件
*
*
* // 字体图标 (需要加载对应字体)
*
*
* // Emoji
* 🏠
*
* // Unicode
*
* ```
*/
import './Icon.css'
// =============================================
// Icon 类型定义
// =============================================
export type IconFontSize = 'inherit' | 'small' | 'medium' | 'large'
export type IconColor =
| 'inherit'
| 'action'
| 'disabled'
| 'primary'
| 'secondary'
| 'error'
| 'info'
| 'success'
| 'warning'
export interface IconProps {
/** SVG 图标文件路径 */
src?: string
/** 字体图标名称 (用于 icon font) */
fontIcon?: string
/** Unicode 字符 */
unicode?: string
/** 字体族 (用于 icon font) */
fontFamily?: string
/** 子元素 (emoji 或文字) */
children?: any
/** 自定义类名 */
className?: string
/** 内联样式 */
style?: Record
/** 颜色 */
color?: IconColor | string
/** 字体大小 */
fontSize?: IconFontSize | string | number
/** 宽度 */
width?: number | string
/** 高度 */
height?: number | string
/** sx 属性 */
sx?: Record
/** 点击事件 */
bindtap?: () => void
}
// =============================================
// 颜色映射
// =============================================
const colorMap: Record = {
inherit: 'inherit',
action: 'rgba(255, 255, 255, 0.56)',
disabled: 'rgba(255, 255, 255, 0.3)',
primary: '#90caf9',
secondary: '#ce93d8',
error: '#f44336',
info: '#42a5f5',
success: '#66bb6a',
warning: '#ffa726',
}
// =============================================
// 字体大小映射
// =============================================
const fontSizeMap: Record = {
inherit: 0, // 特殊处理
small: 20,
medium: 24,
large: 35,
}
// =============================================
// Icon 组件实现
// =============================================
export function Icon(props: IconProps) {
const {
src,
fontIcon,
unicode,
fontFamily,
children,
className,
style,
color = 'inherit',
fontSize = 'medium',
width,
height,
sx,
...other
} = props
// 获取颜色值
const colorValue = colorMap[color] || color
// 获取字体大小
let fontSizeValue: number | string
if (typeof fontSize === 'number') {
fontSizeValue = fontSize
} else if (fontSizeMap[fontSize as IconFontSize] !== undefined) {
fontSizeValue = fontSizeMap[fontSize as IconFontSize] || 'inherit'
} else {
fontSizeValue = fontSize
}
// 计算尺寸
const sizeValue = typeof fontSizeValue === 'number' ? fontSizeValue : 24
const iconWidth = width || sizeValue
const iconHeight = height || sizeValue
// 构建类名
const classes = [
'MuiIcon-root',
`MuiIcon-fontSize${capitalize(String(fontSize))}`,
color !== 'inherit' && `MuiIcon-color${capitalize(color)}`,
className,
].filter(Boolean).join(' ')
// 基础样式
const baseStyle: Record = {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: iconWidth,
height: iconHeight,
color: colorValue,
...sx,
...style,
}
// 1. SVG 文件方式
if (src) {
return (
)
}
// 2. 字体图标方式
if (fontIcon || unicode) {
const textStyle: Record = {
fontFamily: fontFamily || 'Material Icons',
fontSize: fontSizeValue,
color: colorValue,
}
return (
{fontIcon || unicode}
)
}
// 3. Children 方式 (emoji/text)
return (
{typeof children === 'string' ? (
{children}
) : (
children
)}
)
}
// 辅助函数
function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1)
}
export default Icon