# Pika 组件库结构优化分析 > 基于当前代码库(`src/components` 约 77 个组件目录、80 个组件 TSX、74 个测试文件)的静态分析。 > 生成日期:2026-05-30 --- ## 目录 1. [现状概览](#1-现状概览) 2. [目录与命名规范](#2-目录与命名规范) 3. [重复代码与可抽取的公共层](#3-重复代码与可抽取的公共层) 4. [ConfigProvider 与主题系统](#4-configprovider-与主题系统) 5. [CSS 与 Design Token 策略](#5-css-与-design-token-策略) 6. [类型系统](#6-类型系统) 7. [Props 诚实性(接口 vs 实现)](#7-props-诚实性接口-vs-实现) 8. [共享 Hooks 与工具](#8-共享-hooks-与工具) 9. [测试覆盖](#9-测试覆盖) 10. [文档与 DX](#10-文档与-dx) 11. [构建与导出](#11-构建与导出) 12. [优先级路线图](#12-优先级路线图) 13. [附录:文件清单速查](#13-附录文件清单速查) --- ## 1. 现状概览 ### 1.1 分层结构(已成型,方向正确) ``` src/ ├── components/ │ ├── common/ # 基础通用(Button、ConfigProvider、Icon…) │ ├── layout/ # 布局(Layout、Flex、Grid、Space…) │ ├── nav/ # 导航(Menu、Tabs、Breadcrumb…) │ ├── entry/ # 数据录入(Input、Select、Form…) │ ├── feedback/ # 反馈(Modal、Message、Alert…) │ ├── display/ # 数据展示(Table、Card、Tooltip…) │ └── shared/ # 内部共享(hooks、types、utils) ├── theme/ # JS Token 定义 └── global.css # CSS 变量(--nv-*) ``` 六大分类与 Ant Design 的组件分区思路一致,有利于 AI 生成代码时的语义检索。`shared/` 作为内部基础设施层也已建立。 ### 1.2 做得好的地方 | 方面 | 说明 | |------|------| | **组件粒度** | 每个组件独立目录,含 `*.tsx` + `*.module.css` + `index.ts` + `*.test.tsx`,结构清晰 | | **Barrel 导出** | 分类 `index.ts` → 根 `components/index.ts` → `src/index.ts`,对外 API 集中 | | **测试基线** | 主组件几乎都有 Vitest + Testing Library 测试(74 个 test 文件) | | **forwardRef** | 布局/表单类组件普遍支持 ref 透传 | | **data-* 属性** | 组件用 `data-*` 标记状态,利于测试与 CSS 选择器 | | **共享 Hooks** | `useClickOutside`、`useScrollListener` 等已在 overlay 类组件中复用 | ### 1.3 主要问题摘要 | 类别 | 严重度 | 一句话描述 | |------|--------|-----------| | 遗留重复路径 | 🔴 高 | `src/components/Button/` 与 `common/Button/` 并存 | | ConfigProvider 未接线 | 🔴 高 | 实现了 context,但业务组件几乎不消费 | | Token 三套并行 | 🔴 高 | JS tokens / CSS `--nv-*` / 组件 `--_*` 混用 | | Overlay 重复实现 | 🟠 中 | Tooltip 与 Popover 各 ~360 行,逻辑高度相似 | | 类型别名泛滥 | 🟠 中 | `PikaSize` 几乎无人用,各组件自建 `*Size` | | Props 接口超前 | 🟠 中 | 多个 prop 在类型里声明但实现缺失 | | 文档空白 | 🟠 中 | 80 个组件仅 1 个 `index.md` | | 构建 subpath 可能无效 | 🟡 低 | `package.json exports "./*"` 与源码结构不匹配 | --- ## 2. 目录与命名规范 ### 2.1 文件夹命名两套并存 | 风格 | 示例 | 数量 | |------|------|------| | **PascalCase** | `common/Button/`、`common/ConfigProvider/` | ~10 个 | | **kebab-case** | `display/avatar/`、`entry/tree-select/` | ~67 个 | **建议:** 统一为 **kebab-case 目录 + PascalCase 文件名**,与绝大多数组件一致: ``` display/avatar/Avatar.tsx ✅ 推荐 common/Button/Button.tsx ⚠️ 目录应改为 common/button/ ``` 迁移成本:仅 `common/` 下 10 个目录,可一次性批量 rename + 更新 import。 ### 2.2 导出模式不一致 **现状:** ```ts // 组件文件 — 普遍 default export export default Button // barrel — named export export { Button } from './Button' ``` **建议:** 组件 TSX 改为 **named export only**,与 barrel 和 tree-shaking 更一致: ```ts // Button.tsx export const Button = forwardRef(...) export type { ButtonProps } ``` ### 2.3 复合组件组织方式不统一 | 模式 | 示例 | |------|------| | 同目录多文件 | `display/avatar/Avatar.tsx` + `AvatarGroup.tsx` | | 单目录聚合 | `entry/choice/Checkbox.tsx` + `Radio.tsx` + `Switch.tsx` | | Object.assign | `Layout.Header`、`Card.Meta` | **建议:** 制定简单规则写入 `CONVENTIONS.md`(当前已删除): - 强关联子组件 → 同目录 + `Object.assign` 或 compound export - 独立可选组件 → 同目录分文件 - 录入类「形态变体」→ 可聚合(如 choice) ### 2.4 遗留路径:Button 双份 | 路径 | 状态 | |------|------| | `src/components/common/Button/` | ✅ 现行源码,根 index 导出 | | `src/components/Button/` | ⚠️ Git 索引中仍存在,含 `index.md`、测试 | **行动:** 删除 `src/components/Button/`,文档迁移至 `common/Button/index.md`(或 `docs/components/button.md`)。 --- ## 3. 重复代码与可抽取的公共层 ### 3.1 Tooltip / Popover — 最高优先级抽取 两者共享: - `GAP`、`PLACEMENT_POSITION_MAP`、`FLIP_MAP` 常量 - Portal 渲染 + 定位计算 - `useScrollListener` + `useClickOutside` - 显隐状态机 ``` shared/overlay/ ├── Overlay.tsx # 定位 + portal + 显隐 ├── placement.ts # PLACEMENT_MAP, FLIP_MAP ├── useOverlay.ts # open/close/trigger 逻辑 └── Overlay.module.css ``` 预估可减少 **~300 行**重复代码,后续 Popconfirm、Dropdown 也可复用。 ### 3.2 `getSemantic` 内联重复(22 处) 以下组件各自定义相同模式的 `getSemantic` helper: ``` common/Button/Button.tsx display/badge/Badge.tsx display/card/Card.tsx display/table/Table.tsx display/tooltip/Tooltip.tsx … 等 22 个文件 ``` **建议:** 抽到 `shared/utils/semantic.ts`: ```ts export function getSemanticClass( styles: Record, semantic?: Record, part: string, ): string | undefined ``` ### 3.3 Portal 工具已写但未用 `shared/utils/portal.ts` 提供 `getPortalContainer` / `renderPortal`,**零引用**。 Tooltip、Popover、Tour、Modal 均直接 `createPortal(..., document.body)`。 **建议:** overlay 重构时统一接入,并读取 ConfigProvider 的 `getPopupContainer`。 ### 3.4 Table 内联分页 vs nav/Pagination `display/table/Table.tsx` 内置 `PaginationInline`,功能仅为 prev/next + 页码,不支持: - `showSizeChanger` - `showQuickJumper` - `pageSizeOptions` **建议:** Table 直接组合 `nav/pagination/Pagination`,或抽取 `shared/PaginationMini`。 ### 3.5 className 拼接模式重复 大量组件使用: ```ts [className, styles.root].filter(Boolean).join(' ') ``` **建议:** `shared/utils/classNames.ts`(或引入轻量 `clsx` 依赖): ```ts export function cn(...parts: (string | false | undefined | null)[]): string ``` --- ## 4. ConfigProvider 与主题系统 ### 4.1 现状:基础设施已建,消费方缺失 `ConfigProvider` 提供: | Context 字段 | 是否被组件消费 | |-------------|---------------| | `prefixCls` | ❌ CSS 硬编码 `nv-*` | | `iconPrefixCls` | ❌ Icon 用全局 `.nv-icon` | | `colorPrimary` / `theme.token` | ⚠️ 仅注入 wrapper inline style | | `theme.components` | ❌ 接口存在,从未应用 | | `locale` | ❌ 无组件读取 | | `zIndex` | ❌ Modal/Drawer 各自硬编码 | | `getPopupContainer` | ❌ 仅 prop 级,不读 context | `useConfig()` 仅出现在 `ConfigProvider.tsx` 及其测试中。 ### 4.2 建议接线顺序 **Phase 1 — 最小可用全局配置:** 1. 创建 `shared/hooks/usePikaContext.ts`,封装 `useConfig()` + 默认值合并 2. Overlay 组件(Tooltip、Popover、Dropdown、Modal)读取 `getPopupContainer`、`zIndex` 3. 所有 portal 组件 z-index 从 context 叠加(base + offset) **Phase 2 — 前缀与国际化:** 4. CSS Module 改为 `[data-nv-prefix]` 或 runtime class prefix(成本较高,可延后) 5. `locale` 接入 DatePicker、Pagination、Modal 按钮文案 **Phase 3 — 组件级主题:** 6. 实现 `theme.components.Button` 等 token 覆盖 ### 4.3 Token 源统一 当前三套 token 并行: ``` ┌─────────────────────────────────────────────────────────┐ │ theme/tokens.ts (JS 对象) │ │ → entry/tokens/index.ts → inline style 注入 │ ├─────────────────────────────────────────────────────────┤ │ global.css (:root --nv-*) │ │ → feedback 组件 CSS var fallback │ ├─────────────────────────────────────────────────────────┤ │ 组件私有 --_* (TSX inline style → CSS Module) │ │ → Button, Layout, Progress 等 │ └─────────────────────────────────────────────────────────┘ ``` **问题:** - `theme/tokens.ts` 的 `color.primary = '#6C5CE7'` 与 `global.css` 暗色模式值可能不同步 - Entry 组件 inline style **不响应** ConfigProvider 运行时改色 - `global.css` 首行 `@import './theme/dumi.css'` 把文档站样式耦合进库 **建议目标架构:** ``` theme/ ├── tokens.css # 唯一 token 源(--nv-*) ├── tokens.ts # 从 CSS 变量读取或生成类型(可选) ├── dark.css └── compact.css 组件 CSS:只用 var(--nv-*),组件级 --_* 仅用于 prop 驱动的动态值(width、height) ConfigProvider:通过 style 覆盖 --nv-color-primary 等根变量 ``` --- ## 5. CSS 与 Design Token 策略 ### 5.1 当前模式评估 | 模式 | 用途 | 评价 | |------|------|------| | `*.module.css` | 组件样式隔离 | ✅ 主流,正确 | | `--nv-*` + fallback | 设计 token | ✅ 正确方向,但 fallback 硬编码过多 | | `--_*` inline 注入 | prop 驱动动态值 | ✅ 适合 Layout/Button 的高度、宽度 | | 全局 `Icon/style.css` | 图标字体 | ⚠️ 应改为 CSS Module 或 CSS-in-JS | | inline style 色值 | Entry 组件 | ❌ 应迁移到 CSS var | ### 5.2 硬编码色值示例(需逐步清理) 以下文件存在与 token 并行的硬编码: - `display/popover/Popover.module.css` — `#fff`、`rgba(0,0,0,0.85)` - `display/collapse/Collapse.module.css` — 边框/背景硬编码 - `entry/tokens/index.ts` — 直接从 JS 对象读色,不经过 CSS 变量 ### 5.3 CSS 变量命名规范建议 | 层级 | 前缀 | 示例 | 谁设置 | |------|------|------|--------| | 全局设计 token | `--nv-` | `--nv-color-primary` | global.css / ConfigProvider | | 组件内部变量 | `--_{part}-` | `--_height`、`--_padding` | 组件 TSX inline style | | 语义 DOM | `data-*` | `data-collapsed`、`data-size` | 组件 TSX | 避免 `--_*` 与 `--nv-*` 语义混淆:前者是**实例级**动态值,后者是**主题级**静态 token。 --- ## 6. 类型系统 ### 6.1 重复 Size / Status 类型 `shared/types/common.ts` 已定义: ```ts export type PikaSize = 'small' | 'middle' | 'large' export type PikaStatus = 'default' | 'success' | 'warning' | 'error' | 'info' ``` 但 **几乎无组件引用**。各模块自建: | 类型 | 位置 | |------|------| | `DataEntrySize` | `entry/common.ts` | | `ButtonSize` | `common/Button/Button.tsx` | | `AvatarSizeType` | `display/avatar/Avatar.tsx` | | `TagSize`, `CardSize`, `TableSize`, `BadgeSize`… | 各 display 组件 | **建议:** ```ts // shared/types/common.ts — canonical types export type PikaSize = 'small' | 'middle' | 'large' export type PikaStatus = 'default' | 'success' | 'warning' | 'error' | 'info' // entry/common.ts import type { PikaSize, PikaStatus } from '../../shared/types' export type DataEntrySize = PikaSize export type DataEntryStatus = PikaStatus // 组件 props export interface ButtonProps { size?: PikaSize } ``` ### 6.2 公共 Props 基类利用不足 `entry/common.ts` 定义了良好的基类: - `DataEntryBaseProps` - `DataEntryInputProps` - `DataEntryTextualProps` - `DataEntrySelectableProps` **建议:** display / feedback 组件也建立类似基类: ```ts // shared/types/component.ts export interface PikaComponentProps { className?: string style?: CSSProperties } export interface PikaInteractiveProps extends PikaComponentProps { disabled?: boolean } ``` ### 6.3 `CSSCustomProperties` 使用率低 `shared/types/css.ts` 仅 5 个组件 import,其余用 `Record` 或无类型。 **建议:** 统一 cssVars 类型: ```ts type CSSVars = CSSProperties & Record<`--${string}`, string> ``` --- ## 7. Props 诚实性(接口 vs 实现) > 接口声明了但实现缺失的 prop,会误导 AI 和使用者。应 **实现** 或 **从类型中移除**(或标注 `@deprecated` / 文档说明「即将支持」)。 ### 7.1 已确认未实现的 Props | 组件 | Prop | 现状 | |------|------|------| | **Layout.Sider** | `onBreakpoint` | 有 `breakpoint` data 属性,无 resize 监听 | | **DatePicker** | `mode`, `format` | 固定 date 模式 + `YYYY-MM-DD` | | **TimePicker** | `format`, `hourStep` | 固定格式与步进 | | **Slider** | `range` | 仅单值滑块 | | **TextArea** | `autoSize`, `onResize` | 未实现自动高度 | | **Upload** | `directory`, `onPreview` | 未实现文件夹上传与预览 | | **Popconfirm** | `okType` | 确认按钮未区分 danger/primary | | **TreeSelect** | `treeCheckable` | 解构为 `_treeCheckable` 或未使用 | | **Form** | `labelCol`, `wrapperCol` | 无栅格布局 | | **Table** | `filters`, `filteredValue`, `filterMultiple` | Column 类型完整,无 filter UI | | **Table** | `showSizeChanger`, `showQuickJumper` | PaginationConfig 有类型,内联分页未支持 | | **Mention** | `showSearch`, `showClear` | 继承自基类但未解构 | ### 7.2 处理策略 ``` 优先级 A — 高频 API(Ant Design 对标) → 补实现:DatePicker.format、Slider.range、Layout.onBreakpoint 优先级 B — 低频 / 复杂 → 从类型移除,CHANGELOG 记录,待迭代再加 优先级 C — 计划内 → 保留类型,组件 JSDoc 标注 @experimental ``` ### 7.3 类型笔误 `TooltipPlacement` 含 `'rightRight'`,疑似应为 `'rightBottom'`(`Tooltip.tsx`)。`FLIP_MAP` 映射也需核对。 --- ## 8. 共享 Hooks 与工具 ### 8.1 已有 Hooks 使用情况 | Hook | 路径 | 已使用 | 应使用未使用 | |------|------|--------|-------------| | `useClickOutside` | `shared/hooks/` | Select, Dropdown, Tooltip, Popover, Popconfirm, AutoComplete, RangePicker | **Cascader, DatePicker, TimePicker, TreeSelect, Mention** | | `useScrollListener` | 同上 | Affix, Anchor, BackTop, Tooltip, Popover, Tour | — | | `useEscapeKey` | 同上 | Modal, Drawer, Tour, Image | — | | `useMatchMedia` | 同上 | Grid | **Layout.Sider**(breakpoint) | ### 8.2 重复实现需清理 | 组件 | 问题 | 建议 | |------|------|------| | `FloatButton` | 自定义 `document.addEventListener('click')` | 改用 `useClickOutside` | | `Image` | `useEscapeKey` + 额外 `keydown` 监听 | 合并为单一 hook | | `Tour` | `useEscapeKey` + 额外 `keydown` 处理方向键 | 扩展 hook 或统一 handler | ### 8.3 建议新增 Hooks | Hook | 用途 | |------|------| | `useControllableState` | 统一 controlled/uncontrolled 模式(大量组件重复 `isControlled` 逻辑) | | `useBreakpoint` | Layout.Sider、Grid 共用 responsive 逻辑 | | `useMergedRef` | forwardRef + 内部 ref 合并 | `useControllableState` 示例 — 当前 Layout、Sider、Modal、Tabs 等均有类似代码: ```ts const isControlled = value !== undefined const current = isControlled ? value : internal ``` --- ## 9. 测试覆盖 ### 9.1 覆盖率概况 - **主组件:** 几乎每个一级目录都有 `*.test.tsx` ✅ - **子组件:** 以下 **7 个** 无独立测试: | 子组件 | 路径 | 风险 | |--------|------|------| | `AvatarGroup` | `display/avatar/` | maxCount、overflow 逻辑 | | `BadgeRibbon` | `display/badge/` | 定位、颜色 | | `CardGrid` / `CardMeta` | `display/card/` | 栅格布局 | | `ImagePreviewGroup` | `display/image/` | 多图预览切换 | | `StatisticTimer` | `display/statistic/` | 倒计时逻辑 | | `CheckableTag` | `display/tag/` | 选中态 | ### 9.2 测试质量建议 | 方向 | 说明 | |------|------| | **行为测试优先** | 少测 class 名,多测交互(open/close、keyboard、form submit) | | **未实现 prop 不测** | 避免测试「接口存在但行为不存在」造成 false positive | | **ConfigProvider 集成测试** | 验证 theme/locale 注入后组件行为变化 | | **a11y 基线** | overlay 组件补充 aria 属性断言 | ### 9.3 重复测试 `src/components/Button/Button.test.tsx` 与 `common/Button/Button.test.tsx` 可能重复 — 随遗留目录一并清理。 --- ## 10. 文档与 DX ### 10.1 文档现状 | 类型 | 数量 | 路径 | |------|------|------| | 组件 co-located `index.md` | **1** | `components/Button/index.md`(遗留) | | Dumi 指南 | 3 | `docs/index.md`, `getting-started.md`, `components/index.md` | | 逐组件 API 文档 | **0** | — | | 设计规范 | 1 | `DESIGN_SPEC.md`(完整) | | 开发约定 | 0 | `CONVENTIONS.md` 已删除 | ### 10.2 文档建设建议 **短期(可脚本化):** 1. 为每个组件目录生成 `index.md` 模板(frontmatter + 基础 demo + Props 表占位) 2. Dumi 配置 `resolve.atomDirs` 指向 `src/components` **中期:** 3. 从 TS 类型自动生成 Props 表(dumi-theme-Pika 或 typedoc) 4. 每个组件至少 3 个 demo:基础用法、受控模式、禁用/错误态 **长期:** 5. AI 示例库 — 与 `DESIGN_SPEC.md` 的 AI-First 原则对齐,每组件提供「AI 友好」单行示例 ### 10.3 开发者体验 | 改进项 | 说明 | |--------|------| | 恢复 `CONVENTIONS.md` | 目录命名、export 规范、CSS 约定、测试要求 | | `npm run lint:fix` | 已有 lint-staged,可加 CI workflow | | Storybook vs Dumi | 当前 Dumi 足够,保持单文档方案 | | 组件生成 CLI | `pnpm gen component Button --category common` 脚手架 | --- ## 11. 构建与导出 ### 11.1 当前构建链 ``` father build → dist/cjs + dist/esm src/index.ts → export * from './components' + tokens ``` ### 11.2 问题 | 问题 | 详情 | |------|------| | **Subpath exports 可能无效** | `package.json` 声明 `"./*" → dist/esm/*/index.js`,但源码无对应分包 | | **CSS 未作为包入口** | 消费者需自行引入 token CSS;`global.css` 未 export | | **global.css 耦合 dumi** | `@import './theme/dumi.css'` 不应出现在库运行时入口 | | **shared 不对外** | 第三方无法复用 hooks/utils | | **手动维护导出面** | 新组件需改 3 处 index | ### 11.3 建议 **package.json exports 修正:** ```json { "exports": { ".": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js" }, "./styles": "./dist/styles/global.css", "./tokens": "./dist/esm/theme/tokens.js" } } ``` **CSS 构建:** - 将 `global.css` 拆为 `styles/tokens.css`(纯 token)+ `styles/dumi.css`(文档专用) - father 配置 `extraBabelPlugins` 或 postcss 复制 CSS 到 dist **按需加载(可选):** - 若需要 `@Pika/ui/button`,需 father 多 entry 配置 + 每组件独立 package path --- ## 12. 优先级路线图 ### P0 — 基础一致性(1–2 周) | # | 任务 | 影响 | |---|------|------| | 1 | 删除 `src/components/Button/` 遗留,统一至 `common/Button/` | 消除混淆 | | 2 | 统一 `common/` 目录为 kebab-case | 命名一致 | | 3 | Props 诚实性清理:移除或标注未实现 prop | AI 生成准确 | | 4 | `global.css` 与 dumi.css 解耦 | 库可独立使用 | | 5 | 新增 `shared/utils/classNames.ts` | 减少重复 | ### P1 — 架构增强(2–4 周) | # | 任务 | 影响 | |---|------|------| | 6 | 抽取 `shared/overlay/` primitives | Tooltip/Popover 减 300+ 行 | | 7 | 抽取 `getSemantic` → `shared/utils/semantic.ts` | 22 处重复消除 | | 8 | ConfigProvider Phase 1 接线(zIndex、getPopupContainer) | 全局配置可用 | | 9 | 统一 Size/Status 类型为 `PikaSize` / `PikaStatus` | 类型一致 | | 10 | Cascader/DatePicker/TreeSelect 接入 `useClickOutside` | 交互完整 | | 11 | 新增 `useControllableState` hook | 减少状态逻辑重复 | ### P2 — 体验完善(4–8 周) | # | 任务 | 影响 | |---|------|------| | 12 | Token 统一为 CSS `--nv-*` 单源 | 主题可运行时切换 | | 13 | 补全 7 个子组件测试 | 测试完整 | | 14 | 每组件 `index.md` + 基础 demo | 文档可用 | | 15 | 恢复并完善 `CONVENTIONS.md` | 贡献者友好 | | 16 | 实现高频未实现 prop(DatePicker.format、Slider.range) | API 完整 | | 17 | package.json exports + CSS 入口修正 | 发布可用 | ### P3 — 长期演进 | # | 任务 | |---|------| | 18 | 组件级 theme override(`theme.components`) | | 19 | 按需 subpath import 分包构建 | | 20 | 组件生成 CLI | | 21 | a11y 审计与 WCAG 基线 | | 22 | 可视化组件(AntV)与 UI 组件 Token 统一 | --- ## 13. 附录:文件清单速查 ### 13.1 应删除/迁移 ``` src/components/Button/ → 删除,保留 common/Button/ src/components/Button/index.md → 迁移至 docs 或 common/Button/ ``` ### 13.2 应统一命名(common/ PascalCase → kebab-case) ``` common/Button/ → common/button/ common/ConfigProvider/ → common/config-provider/ common/FloatButton/ → common/float-button/ common/BackTop/ → common/back-top/ … (共 10 个) ``` ### 13.3 共享层待建设 ``` shared/overlay/Overlay.tsx shared/utils/classNames.ts shared/utils/semantic.ts shared/hooks/useControllableState.ts shared/hooks/useBreakpoint.ts shared/hooks/usePikaContext.ts ``` ### 13.4 应对接 ConfigProvider 的组件(优先) ``` display/tooltip/Tooltip.tsx display/popover/Popover.tsx nav/dropdown/Dropdown.tsx feedback/modal/Modal.tsx feedback/drawer/Drawer.tsx feedback/message/Message.tsx feedback/notification/Notification.tsx display/tour/Tour.tsx entry/select/Select.tsx entry/date-picker/DatePicker.tsx ``` ### 13.5 统计 | 指标 | 数量 | |------|------| | 组件目录 | ~77 | | 组件 TSX(不含测试) | ~80 | | 测试文件 | ~74 | | 无独立测试的子组件 | 7 | | getSemantic 重复 | 22 处 | | 未实现 prop 的组件 | ~12 | | co-located 文档 | 1 | --- ## 总结 Pika 的 **六大分类 + 单组件目录结构** 已经是一个健康的基础,测试覆盖和 forwardRef 等实践也到位。当前主要短板集中在: 1. **一致性** — 命名、导出、类型、token 三套并行 2. **诚实性** — 接口超前于实现,对 AI-First 目标伤害最大 3. **基础设施未接线** — ConfigProvider、shared utils 写了但没用起来 4. **重复** — Overlay、getSemantic、className 拼接、受控状态 按 P0 → P1 → P2 推进,可以在不推翻现有结构的前提下,显著提升可维护性和 AI 代码生成准确率。