跳到主要内容

图标

手绘 24×24 描边 SVG。所有图标遵守同一组绘制规则。无 icon font、无 Unicode 承载 UI、无装饰 emoji。

按业务语义分 15 类堆栈展示,顶部搜索框 ⌘K 聚焦,点击 cell 复制图标语义名。

图标库 · 102

点击 cell 复制语义名 · ⌘K 聚焦搜索

方向

9Direction

菜单

3Menu

状态

7Status

编辑操作

8Edit & CRUD

传输操作

8Transfer

对象

14Objects

控件

13Controls

输入

5Input

AI 智能

4AI

业务

9Business

店面

5Storefront

仪表盘

2Dashboard

文档·检索

7Documents & Search

容器·财务

6Containers & Finance

反馈·占位

2Feedback & Placeholder

在 RN 中使用

import { Icon } from '@unif/react-native-design';
import { useColors } from '@unif/react-native-design';

function Demo() {
const c = useColors();
return (
<>
<Icon name="send" size={20} />
<Icon name="check" size={18} color={c.success} />
<Icon name="close" size={14} color={c.foregroundSubtle} strokeWidth={2} />
</>
);
}

name 是 TypeScript 字面量联合类型——所有图标名都有自动补全;IconNamesrc/icons/data.ts 生成(该文件 AUTO-GENERATED,请勿手改)。

<Icon> props

来源:src/components/ui/Icon/types.tsIcon.tsx

PropType默认说明
nameIconName图标语义名(字面量联合类型,自动补全)
sizenumber?r(18)(随设备宽度缩放)宽高(正方形);传入值应已经过 r() 缩放
colorstring?c.foregroundMuted传给 SVG stroke(及 fill="currentColor" 元素)
strokeWidthnumber?每图标自带值(多数 1.75check2覆盖描边宽度
styleStyleProp<ViewStyle>?外层 <View> 样式
testIDstring?E2E / 测试定位(挂在外层 <View>

未知 name 不抛错:打 warn 并渲染一个等尺寸空 <View> 占位(同样对 SR 隐藏)。

绘制规则

每个新图标必须满足:

属性
viewBox0 0 24 24
stroke-width1.75(加粗变体 2,仅 check
stroke-linecapround
stroke-linejoinround
fillnone(实心填充用 fill="currentColor"
color<Icon>color prop → stroke,默认 c.foregroundMuted(不传 color 时)
组件默认 sizer(18)(随设备宽度缩放);调用方传值应包 r(),如 size={r(20)}

添加新图标

  1. src/icons/svg/<name>.svg 加新文件,遵守上面的绘制规则(只用 <path> / <rect> / <circle>;polyline / polygon 先转 path)
  2. 运行 node scripts/build-icons.js,脚本扫 src/icons/svg/*.svg 重新生成 src/icons/data.ts(纯 regex 抽属性,无第三方依赖)。不要手改 data.ts —— 它是生成产物({ strokeWidth, elements }),改 SVG 再跑脚本
  3. 文档站走的 website/src/components/iconsCatalog.ts 是从 @unif/react-native-design barrel re-export 的薄壳(ICONS / ICON_NAMES / IconName),自动同步,无需再生成
  4. IconName TypeScript 字面量类型自动包含新名字,IDE 立即给出补全
  5. 若新图标属于某个语义类别,把它加进 website/src/components/IconCatalog.tsxCATEGORIES 数组对应组里;若它是某个 appId 的图标,补 APP_MAPPINGS

实现细节

src/components/ui/Icon/Icon.tsxreact-native-svg 渲染——<Svg> + <Path> / <Circle> / <Rect>,路径数据来自 src/assets/icons/data.tscolor prop 传给 strokestrokeWidth 走每图标默认值或可覆盖。

// 摘录
import Svg, { Circle, Path, Rect } from 'react-native-svg';
import { ICONS } from '@unif/react-native-design';

<Svg width={size} height={size} viewBox="0 0 24 24"
fill="none" stroke={color}
strokeWidth={def.strokeWidth}
strokeLinecap="round" strokeLinejoin="round">
{def.elements.map((el, i) => /* path/circle/rect */)}
</Svg>

无障碍(a11y)

来源:src/components/ui/Icon/Icon.tsxtypes.ts

<Icon> 是纯视觉图元,源码刻意把它对 SR 隐藏:外层 <View>(正常路径与未知图标 fallback 路径都)显式设 accessibilityElementsHidden + importantForAccessibility="no-hide-descendants"。它accessibilityRole / accessibilityLabel,也没有可传的 a11y prop(仅 name / size / color / strokeWidth / style / testID)。

这是有意为之:图标的语义应由承载它的可交互父组件提供朗读文案 —— 如 IconButton 的必填 accessibilityLabelButtonlabel。独立装饰用 <Icon> 即可,无需也不应给它单独挂 a11y。

头像

头像不是图标,是实体。所有头像都是单字符 monogram / AI / 客户首字母)放在彩色圆盘上。绝不在头像里放图片或多于 1 个字符。

详见 Avatar 组件