/** * 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