/** * SvgIcon Component - Lynx 版 MUI SvgIcon * 一比一对应 MUI SvgIcon API * * 注意:由于 Lynx 不支持 SVG 元素,本组件使用以下替代方案: * - 使用 text 元素显示 emoji 或 Unicode 图标 * - 使用 image 元素加载图标图片 * - 提供 children 作为自定义内容 * * 支持的功能: * - fontSize: inherit, small, medium, large * - color: inherit, action, disabled, primary, secondary, error, info, success, warning */ import './SvgIcon.css' // ============================================= // SvgIcon 类型定义 // ============================================= export type SvgIconFontSize = 'inherit' | 'small' | 'medium' | 'large' export type SvgIconColor = | 'inherit' | 'action' | 'disabled' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' export interface SvgIconProps { /** 子元素 (图标内容,如 emoji 或文字) */ children?: any /** 自定义类名 */ className?: string /** 内联样式 */ style?: Record /** 颜色 */ color?: SvgIconColor | string /** 字体大小 */ fontSize?: SvgIconFontSize | string /** HTML 颜色属性 */ htmlColor?: string /** 是否继承 viewBox */ inheritViewBox?: boolean /** viewBox */ viewBox?: string /** 无障碍标题 */ titleAccess?: string /** sx 属性 */ sx?: Record /** 点击事件 */ bindtap?: () => void } // ============================================= // SvgIcon 类名 // ============================================= export const svgIconClasses = { root: 'MuiSvgIcon-root', colorPrimary: 'MuiSvgIcon-colorPrimary', colorSecondary: 'MuiSvgIcon-colorSecondary', colorAction: 'MuiSvgIcon-colorAction', colorError: 'MuiSvgIcon-colorError', colorDisabled: 'MuiSvgIcon-colorDisabled', fontSizeInherit: 'MuiSvgIcon-fontSizeInherit', fontSizeSmall: 'MuiSvgIcon-fontSizeSmall', fontSizeMedium: 'MuiSvgIcon-fontSizeMedium', fontSizeLarge: 'MuiSvgIcon-fontSizeLarge', } // ============================================= // 颜色映射 // ============================================= const colorMap: Record = { inherit: 'inherit', action: 'rgba(255, 255, 255, 0.56)', disabled: 'rgba(255, 255, 255, 0.3)', primary: '#90caf9', // blue[200] for dark mode secondary: '#ce93d8', // purple[200] error: '#f44336', // red[500] info: '#42a5f5', // blue[400] success: '#66bb6a', // green[400] warning: '#ffa726', // orange[400] } // ============================================= // 字体大小映射 // ============================================= const fontSizeMap: Record = { inherit: 'inherit', small: 20, medium: 24, large: 35, } // ============================================= // SvgIcon 组件实现 // ============================================= export function SvgIcon(props: SvgIconProps) { const { children, className, style, color = 'inherit', fontSize = 'medium', htmlColor, titleAccess, sx, ...other } = props // 获取颜色值 const colorValue = htmlColor || colorMap[color] || color // 获取字体大小 const fontSizeValue = fontSizeMap[fontSize as SvgIconFontSize] || fontSize // 构建类名 const classes = [ svgIconClasses.root, color !== 'inherit' && `MuiSvgIcon-color${capitalize(color)}`, `MuiSvgIcon-fontSize${capitalize(fontSize as string)}`, className, ].filter(Boolean).join(' ') // 计算样式 - 对应 MUI SvgIconRoot 样式 const computedStyle: Record = { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, width: typeof fontSizeValue === 'number' ? fontSizeValue : undefined, height: typeof fontSizeValue === 'number' ? fontSizeValue : undefined, fontSize: fontSizeValue, color: colorValue, ...sx, ...style, } return ( {children} {titleAccess && {titleAccess}} ) } // 辅助函数 function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1) } // 设置组件名称 (与 MUI 一致) SvgIcon.muiName = 'SvgIcon' export default SvgIcon