npm package: @ksai/theme
Description: 基于 Emotion 的主题包，提供“全局层 → 语义层 → 组件层”的三层 Design Token 体系，服务于金山AI官网、后台与组件库的一致设计风格与主题切换能力。
Latest version: 0.1.5

## @kai/theme — 金山AI 主题包（三层 Design Token 体系）

基于 Emotion 的主题包，提供“全局层 → 语义层 → 组件层”的三层 Design Token 体系，服务于金山AI官网、后台与组件库的一致设计风格与主题切换能力。

- **适配场景**: 网站与后台界面、`@kai/design` 组件库
- **核心能力**: 三层 Token、类型安全、多主题（亮/暗）、集中治理、与组件库直连

---

### 特性

- **三层 Token 架构**: Global（基础值）→ Semantic（语义映射）→ Component（组件专用）
- **类型安全**: 完整的 TypeScript 类型，使用时具备自动补全与校验
- **多主题**: 内置 `lightComponentTheme` 与 `darkComponentTheme`，可扩展更多品牌/业务主题
- **零硬编码**: 组件与页面不直接写颜色/尺寸，统一由 Token 决策
- **易协作**: 与设计规范一致，更新 Token 即全局生效
- **模块化设计**: 语义层独立导出，可供多个项目复用

---

## 安装

确保已配置公司内部 NPM 源（可在工程 `.npmrc` 中设置）：

```bash
npm config set registry https://npm.kingsoft-ai.com/
```

安装依赖：

```bash
pnpm add @kai/theme @emotion/react @emotion/styled
# 或
npm i @kai/theme @emotion/react @emotion/styled
```

本包对 `react`/`react-dom` 要求版本 >= 18（为 peerDependencies）。

---

## 快速开始

使用 `CustomThemeProvider` 注入主题（默认亮色主题）：

```tsx
import { CustomThemeProvider } from '@kai/theme'

export default function App() {
  return (
    <CustomThemeProvider>
      {/* 你的应用 */}
    </CustomThemeProvider>
  )
}
```

搭配 `@kai/design` 组件库：

```tsx
import { CustomThemeProvider } from '@kai/theme'
import { Button } from '@kai/design'

export default function App() {
  return (
    <CustomThemeProvider>
      <Button variant="primary" size="md">开始使用</Button>
    </CustomThemeProvider>
  )
}
```

---

### 主题切换

```tsx
import { CustomThemeProvider, lightComponentTheme, darkComponentTheme } from '@kai/theme'

export default function App({ isDark }: { isDark: boolean }) {
  return (
    <CustomThemeProvider theme={isDark ? darkComponentTheme : lightComponentTheme}>
      {/* ... */}
    </CustomThemeProvider>
  )
}
```

---

### 在组件中消费 Token

优先使用“组件层” Token，确保一致与可维护：

```tsx
import styled from '@emotion/styled'

const PrimaryAction = styled('button')(({ theme }) => ({
  background: theme.components.button.primary.background.default,
  color: theme.components.button.primary.text.default,
  borderRadius: theme.components.button.borderRadius,
  '&:hover': { background: theme.components.button.primary.background.hover },
}))
```

页面/容器等通用样式可使用“语义层” Token：

```tsx
const Page = styled('div')(({ theme }) => ({
  background: theme.semantic.colors.background.surface,
  color: theme.semantic.colors.text.primary,
}))
```

如需特指原子值（谨慎使用），可访问“全局层” Token：

```tsx
const AccentBorder = styled('div')(({ theme }) => ({
  borderColor: theme.global.colors.blue[500],
}))
```

---

## 导出 API

- **组件主题**: `lightComponentTheme`, `darkComponentTheme`
- **语义层**: `lightSemantic`, `darkSemantic` （可供其他项目引用）
- **主题提供者**: `CustomThemeProvider`, `CustomThemeProviderProps`
- **全局层 Token**: `globalColors`, `globalSpacing`, `globalRadii`, `globalTypography`, `globalShadows`, `globalGradients`
- **类型**: `Theme`（= `AppTheme`）、`ComponentTheme`、以及 `types/` 目录中的各细分类型

---

## 目录结构（核心）

```
packages/theme/src/
├── types/                    # 类型定义目录
│   ├── tokens.types.ts      # Tier 1: 全局层类型
│   ├── semantic.types.ts    # Tier 2: 语义层类型
│   ├── components.types.ts  # Tier 3: 组件层类型
│   └── index.ts             # 类型汇总导出
├── tokens.ts                # Tier 1: 全局层 Token（色板/间距/圆角/排版/阴影/渐变）
├── semantic.ts              # Tier 2: 语义层（亮/暗色语义映射，可独立引用）
├── themes/                  # 主题目录
│   └── components.ts        # 设计组件主题（完整的三层 Token）
├── CustomThemeProvider.tsx  # 主题注入（基于 Emotion ThemeProvider）
└── index.ts                 # 对外导出入口
```

---

## 语义层独立使用

语义层（Semantic Layer）现已独立导出，其他项目可以直接引用语义层而不必引入完整的组件主题：

```tsx
import { lightSemantic, darkSemantic, globalColors, globalSpacing } from '@kai/theme'

// 创建自定义主题，复用语义层
const customTheme = {
  semantic: lightSemantic,
  global: {
    colors: globalColors,
    spacing: globalSpacing,
    // ...
  },
  components: {
    // 你的自定义组件 Token
  }
}
```

这样设计的好处：
- **可复用**: 多个项目可以共享相同的语义层规则
- **灵活性**: 每个项目可以基于相同的语义层定制自己的组件层
- **一致性**: 保证不同项目的设计语言一致

---

## 开发与构建

```bash
# 构建（生成 dist/）
pnpm build:lib

# 清理构建产物
pnpm clean
```

---

## 设计与使用规范

- **优先组件层**：组件样式应使用 `theme.components.*`
- **其次语义层**：页面/布局使用 `theme.semantic.*`
- **避免硬编码**：不在代码中直接写 `#RRGGBB`/`px` 等魔法值
- **单一数据源**：变更 Token 即全局生效，便于治理与回溯

深入阅读：`docs/kingsoft-ai-design-token-system.md`

---

## 常见问题（FAQ）

- **如何新增主题？** 复制 `lightComponentTheme`/`darkComponentTheme` 的结构，按需映射语义层，再导出即可。
- **语义层和组件主题有什么区别？** 语义层定义设计规则（如品牌色、文本色），组件主题将这些规则应用到具体组件。语义层可以独立使用，组件主题包含完整的三层 Token。
- **组件没有对应的组件层 Token 怎么办？** 在 `types/components.types.ts` 增加接口定义，并在 `themes/components.ts` 的 `components.*` 补齐实现。
- **能直接用全局层吗？** 仅在表达"必须是该原始值"且不破坏语义一致性的前提下使用。