@serenis/icons

中文文档
2.62.0发布于 2026/11/02SEE LICENSE IN LICENSETypeScriptESM + CJS

用于Serenis设计系统的图标组件库。包装自定义SVG图标并从iconoir-react重新导出。

中文使用文档
文档目录25 节
  1. 安装
  2. 快速启动
  3. 目录结构
  4. 体系结构
  5. 两个图标源
  6. 这个 Icon 包装器
  7. 双重出口模式
  8. 类型系统
  9. 尺度
  10. 使用模式
  11. 直接渲染
  12. 将图标作为道具传递
  13. 活动/不活动模式
  14. 名称冲突时的别名
  15. 从父代继承颜色
  16. 可访问性
  17. 带有文本的图标(不需要额外的ARIA)
  18. 只需要图标控件 aria-label
  19. 为什么 Icon 包装器没有ARIA属性
  20. ESLint执法
  21. 如何添加新图标
  22. 构建
  23. 消费者
  24. 文档
  25. 许可证

@serenis /图标

用于Serenis设计系统的图标组件库。包装自定义SVG图标并从iconoir-react重新导出。

安装

npm install @serenis/icons

快速启动

# Build
yarn workspace @serenis/icons build

# Dev (watch mode)
yarn workspace @serenis/icons dev

# Typecheck
yarn workspace @serenis/icons typecheck
import { Icon, Home, IconHome } from '@serenis/icons'
import { type IconElement, type IconCommonProps, type IconSize } from '@serenis/icons'

// Option A: Icon wrapper with raw SVG component (dynamic / slotted usage)
<Icon Svg={Home} colorName="primary" size={24} />

// Option B: Pre-wrapped shorthand (fixed icon usage)
<IconHome colorName="primary" size={24} />

目录结构

libraries/icons/
├── src/
│   ├── components/           # One .tsx file per icon + Icon.tsx wrapper
│   │   ├── Icon.tsx          # Design-token-aware wrapper
│   │   ├── Home.tsx          # Example: exports Home + IconHome
│   │   ├── Agenda.tsx
│   │   └── ...               # custom icon files
│   ├── stories/
│   │   ├── Overview.mdx      # Storybook documentation page
│   │   ├── Playground.stories.tsx # Storybook playground for all icons
│   │   └── ...
│   ├── types.ts              # Shared TypeScript types
│   └── index.ts              # Public API (re-exports everything)
├── dist/                     # Built output (gitignored)
├── tsup.config.ts            # Bundle config
└── package.json

体系结构

两个图标源

该库通过一个公共API从两个来源发送图标:

来源他们住在哪里Icon* 速记?
自定义塞雷尼src/components/*.tsx (内联SVG)是的。 Home + IconHome
Iconoir再出口的 iconoir-react无使用通道 <Icon Svg={...} />

自定义图标是手工维护的内联SVG React组件,专门为Serenis产品设计。Iconoir图标填补了不需要自定义艺术品的通用UI符号(箭头,导航chrome,实用程序操作)的空白。

这个 Icon 包装器

Icon 是原始SVG组件和设计令牌系统之间的桥梁。它接受任何 IconElement 并应用基于设计标记的颜色和大小:

const Icon = ({ Svg, colorName, fillColorName, size }: IconProps): JSX.Element | null => {
  if (Svg == null) {
    return null
  }

  return (
    <Svg
      color={colorName ? cssvarColor(colorName) : 'currentColor'}
      fill={fillColorName ? cssvarColor(fillColorName) : 'none'}
      height={size}
      width={size}
    />
  )
}
  • colorName -映射到 color (中风)通过 cssvarColor() 从 @serenis/design-tokens。省略默认为 currentColor,从父文本颜色继承。
  • fillColorName -映射到 fill 通过 cssvarColor()。省略默认为 none。很少使用(星号,一些导航图标)。
  • size -适用于两者 width 和 height.

双重出口模式

每个自定义图标文件导出两件事:

// Home.tsx
export const Home = ({ color, height, width }: IconElementProps) => (
  <svg ...>...</svg>
)

export const IconHome = (props: IconCommonProps) => <Icon Svg={Home} {...props} />
  1. Home -原始SVG组件。的引用传递时使用 Icon 封装器或类型为的组件道具 IconElement (例如按钮的 IconStart)。
  2. IconHome -预包装简写。当你不需要传递图标作为参考时,使用直接渲染。

Iconoir图标只能导出为原始组件(没有 Icon* 速记)。

类型系统

所有类型都是从包的根目录导出的:

import {
  type IconElement,
  type IconElementProps,
  type IconCommonProps,
  type IconProps,
  type IconSize,
} from '@serenis/icons'
类型目的
IconSize12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 120
IconElementPropsSVG组件的底层契约: { color, fill, height, width }
IconElement任何接受 IconElementProps -用于接受图标引用的道具
IconCommonProps基于符号的API: { colorName?, fillColorName?, size }
IconPropsIconCommonProps & { Svg?: IconElement } - - - Icon 包装道具

尺度

大小
12
16
20.
24 (默认)
32
40
48
56
64
72
80
120

使用模式

直接渲染

// Pre-wrapped shorthand (custom icons only)
<IconHome colorName="primary" size={24} />

// Icon wrapper (both custom and Iconoir)
<Icon Svg={Home} colorName="primary" size={24} />
<Icon Svg={ArrowLeft} colorName="neutral-80" size={24} />

将图标作为道具传递

许多 @serenis/ui 组件接受 IconElement 作为道具:

// Button with start icon
<Button IconStart={Home} kind="primary">Go home</Button>

// Tile with required icon
<Tile Icon={Shield} title="Security" action={<Button>Configure</Button>} />

// SideBarItem with active/inactive variants
<SideBarItem Icon={Agenda} IconActive={AgendaSolid} label="Agenda" active={isActive} />

活动/不活动模式

许多自定义图标对于活动状态都有Solid变体:

<Icon Svg={active ? AgendaSolid : Agenda} colorName={active ? 'primary-50' : 'neutral-110'} size={24} />

可用双: Agenda/AgendaSolid, Calendar/CalendarSolid, Chat/ChatSolid, Clock/ClockSolid, Codes/CodesSolid, Delete/DeleteSolid, Diary/DiarySolid, Home/HomeSolid, Menu/MenuSolid, Patients/PatientsSolid, Paths/PathsSolid等等 Path*/Path*Solid 治疗路径图标。

名称冲突时的别名

一些图标名称与通用标识符冲突。输入时的别名:

import { Card as IconCard, Link as IconLink } from '@serenis/icons'

从父代继承颜色

省略 colorName 使用 currentColor -图标继承父元素的文本颜色:

<span className={cx('text-primary')}>
  <Icon Svg={Home} size={24} /> {/* stroke is primary */}
</span>

可访问性

控件呈现的图标 Icon 包装是 默认是装饰性的 -它们没有可访问的名称或角色。含义应该来自相邻的文本或父控件的标签。

带有文本的图标(不需要额外的ARIA)

当图标出现在可见文本旁边时,文本提供了可访问的名称。图标上不需要额外的属性:

<Button IconStart={Home} kind="primary">Go home</Button>

<div className={cx('flex', 'items-center', 'gap-xs')}>
  <Icon Svg={Info} size={24} />
  <span>Important information</span>
</div>

只需要图标控件 aria-label

当一个图标是 唯一的内容 对于可单击控件,父元素必须提供一个可访问的名称 aria-label 或者 aria-labelledby:

<Button IconStart={Delete} kind="tertiary" aria-label="Delete item" />

<Pressable aria-label="Close" onClick={onClose}>
  <Icon Svg={ActionCloseLine} size={24} />
</Pressable>

为什么 Icon 包装器没有ARIA属性

这个 Icon 组件故意不设置 aria-hidden, role,或任何ARIA属性。图标是装饰性的还是有意义的取决于使用上下文,只有调用者知道。调用者应该:

  • 添加 aria-label 当图标是唯一的内容时,调用父控件
  • 当相邻的文本已经传达了意思时什么都不做
  • 避免增加 aria-hidden="true" 显示在文本旁边的图标(文本已经提供了名称)

ESLint执法

自定义ESLint规则 serenis/no-icon-inside-button (活跃 warn 在 libraries/ui, apps/web, apps/blog, apps/website, apps/nutrition-blog)防止嵌套 Icon 或者 Icon* 的子组件 Button。使用 IconStart / IconEnd Props——这确保了一致的大小、加载状态处理和可访问的标记:

// Correct
<Button IconStart={Home} kind="primary">Go home</Button>

// Incorrect — caught by ESLint
<Button><Icon Svg={Home} size={24} />Go home</Button>

如何添加新图标

没有代码生成管道-图标是手工维护的TSX文件。

  1. 创建组件文件 在 src/components/MyIcon.tsx:
import { type IconCommonProps, type IconElementProps } from '../types'
import Icon from './Icon'

type Props = IconElementProps

export const MyIcon = ({ color, height, width }: Props) => (
  <svg fill="none" height={height} viewBox="0 0 24 24" width={width} xmlns="http://www.w3.org/2000/svg">
    {/* Paste SVG paths here, use color={color} for strokes */}
  </svg>
)

export const IconMyIcon = (props: IconCommonProps) => <Icon Svg={MyIcon} {...props} />
  1. 出口的 src/index.ts (按字母顺序排列):
export { IconMyIcon, MyIcon } from './components/MyIcon'
  1. 构建和类型检查:
yarn workspace @serenis/icons build
yarn workspace @serenis/icons typecheck

新图标将自动出现在Storybook Playground故事中。

构建

这个包裹是捆绑的 tsup 转化为ESM + CJS + TypeScript声明。工作区依赖项(@serenis/design-tokens, iconoir-react, react)是外化的。

消费者

  • 应用程序: apps/web (主要客户) apps/blog, apps/nutrition-blog, apps/website
  • 库: libraries/ui (@serenis/ui -按钮,模态,手风琴,面包屑,FileUploadField等), libraries/shared-components (@serenis/shared-components - Nav)

文档

  • 故事书:概览页面和交互式游乐场中 apps/design-system
  • AGENTS.md:面向代理的API参考和规则-参见 AGENTS.md

许可证

自定义Serenis SVG图标:CC BY-NC-ND 4.0 -见 许可证 查看全文。Iconoir再出口保留其上游MIT许可证。

版本与发布记录

@serenis/icons 共发布 21 个版本,首次发布于 2026/07/03;过去 12 个月发布了 21 个版本。

版本发布日期距今
2.62.0latest2026/11/021 天前
2.61.02026/10/285 天前
2.60.02026/10/268 天前
2.59.02026/10/2310 天前
2.58.02026/10/2311 天前
2.57.02026/10/2212 天前

关于 @serenis/icons 的常见问题

@serenis/icons 是什么?

用于Serenis设计系统的图标组件库。包装自定义SVG图标并从iconoir-react重新导出。

如何安装 @serenis/icons?

在项目目录运行 npm install @serenis/icons,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=19.0.0)、@serenis/design-tokens(*)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@serenis/icons 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@serenis/icons 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@serenis/icons 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@serenis/icons 可以商用吗?

@serenis/icons 使用 SEE LICENSE IN LICENSE 许可。许可条款写在包内的独立文件中,请阅读该文件确认可否商用。以上为概括,不构成法律意见,请以许可原文为准。

@serenis/icons 还在维护吗?

最新版本 2.62.0 发布于 2026/11/02(1 天前);至今共发布 21 个版本,其中过去 12 个月发布了 21 个;首次发布于 2026/07/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。