# @serenis/icons 中文文档

规范地址：https://npmcn.com/package/%40serenis/icons/

版本：2\.62\.0
npm 元数据更新时间：2026-11-02T10:54:29.349Z
中文译文更新时间：2026-11-02T11:08:52.612Z
软件包许可：SEE LICENSE IN LICENSE

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40serenis/icons
原文对照：https://npmcn.com/package/%40serenis/icons/?lang=original
项目主页：https://github.com/serenis-health/app-web#readme
源码仓库：https://github.com/serenis-health/app-web

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1.8 MB，869 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=22
- 运行依赖：1 个
- peer 依赖：react \>=19\.0\.0，@types/react \>=19\.0\.0，@serenis/design-tokens \*
- 首次发布：2026-07-03T11:39:02.943Z
- 最新版本发布：2026-11-02T10:54:29.118Z
- 已发布版本数：21（近 12 个月 21 个）

## 中文简介

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

## 安装

```sh
npm install @serenis/icons
```

也可以使用：`pnpm add @serenis/icons`、`yarn add @serenis/icons`、`bun add @serenis/icons`

## README

# @serenis /图标

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

## 安装

```bash
npm install @serenis/icons
```

## 快速启动

```bash
# Build
yarn workspace @serenis/icons build

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

# Typecheck
yarn workspace @serenis/icons typecheck
```

```tsx
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} />
```

## 目录结构

```text
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` 并应用基于设计标记的颜色和大小：

```tsx
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`.

### 双重出口模式

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

```tsx
// 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*` 速记)。

## 类型系统

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

```tsx
import {
  type IconElement,
  type IconElementProps,
  type IconCommonProps,
  type IconProps,
  type IconSize,
} from '@serenis/icons'
```

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

### 尺度

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

## 使用模式

### 直接渲染

```tsx
// 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` 作为道具：

```tsx
// 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变体：

```tsx
<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` 治疗路径图标。

### 名称冲突时的别名

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

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

### 从父代继承颜色

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

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

## 可访问性

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

### 带有文本的图标（不需要额外的ARIA）

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

```tsx
<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`：

```tsx
<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——这确保了一致的大小、加载状态处理和可访问的标记：

```tsx
// 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`：

```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`** （按字母顺序排列）：

```tsx
export { IconMyIcon, MyIcon } from './components/MyIcon'
```

1.  **构建和类型检查**：

```bash
yarn workspace @serenis/icons build
yarn workspace @serenis/icons typecheck
```

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

## 构建

这个包裹是捆绑的 [tsup](https://tsup.egoist.dev/) 转化为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](https://npmcn.com/package/%40serenis/icons/AGENTS.md)

## 许可证

自定义Serenis SVG图标：CC BY-NC-ND 4.0 -见 [许可证](https://npmcn.com/package/%40serenis/icons/LICENSE) 查看全文。Iconoir再出口保留其上游MIT许可证。

## 常见问题

### @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 和提交记录判断。

