跳转到内容

架构总览 ​

XiHan.UI 是一个 pnpm + turbo 的 monorepo。它的组织方式服务于一个目标:让组件的行为独立于渲染它的框架存在。

一个组件的五份产物 ​

以对话框为例,dialog 这个组件在仓库里落成五处:

产物位置内容
无头内核packages/engine/headless/src/dialog/解剖、状态机、键盘规格表、connect
Vue 组件packages/adapters/vue/src/components/dialog/XhDialogRoot 等一组 defineComponent
React 组件packages/adapters/react/src/components/dialog/XhDialogRoot 等函数组件与 hooks
自定义元素packages/adapters/web-components/src/elements/dialog.ts<xh-dialog>,Light-DOM 行为宿主
皮肤packages/design/styles/css/dialog.css纯 CSS,按 data-* 选中

组件行为由无头内核定义;三个适配器分别将属性与事件接到 Vue、React 和作者的 DOM,皮肤决定这些状态的外观。

分层与依赖矩阵 ​

层级越低越基础,只能向下依赖。拓扑写在 tooling/eslint-config/src/layers.json,由 dependency-cruiser 在 pnpm boundaries 时强制执行。

层包可依赖
1coremotion
1motion—
1tokens—
1icons—
1pointer—
1viz—
2positioncore
2code-highlightcore
2chat-streamcore
2markdowncore
2soundcore
2animationscore motion
3headlesscore tokens motion pointer viz
3styles—(纯 CSS,不得依赖任何 JS 包)
3backgroundscore motion
4vuecore headless position code-highlight tokens backgrounds sound motion pointer
4reactcore headless position code-highlight tokens backgrounds sound motion pointer
4web-componentscore headless position code-highlight tokens backgrounds motion pointer

除分层外还有三条硬规则,同样由门禁执行:

  • 库包的运行时代码不引入第三方依赖。登记在案的例外只有适配器的宿主框架(vue、react 与 react-dom)。
  • styles 是纯 CSS。它不依赖任何 JS 包,可以脱离整个 JS 层单独使用。
  • 依赖版本只从 workspace catalog 取。包内一律使用 catalog: 或 workspace: 协议引用,不内联版本号。

一次交互经过哪些层 ​

以点击对话框的触发器为例:

用户点击
   │
   ▼
适配器把 DOM 事件交给 connect 产出的 onClick        (vue / react / web-components)
   │
   ▼
service.send({ type: 'TRIGGER.CLICK' })            (core)
   │
   ▼
状态机转移 closed → open,执行 entry 动作           (core)
   │
   ├─► 行为原语接管:锁滚动、建焦点域、压入层栈      (core)
   ├─► 浮层族还会请定位引擎算坐标                    (position)
   │
   ▼
适配器重新读 connect,把新的 aria-* / data-* 铺到部件上
   │
   ▼
皮肤按 [data-state='open'] 命中新规则,动画播放      (styles)

中间三步与框架无关,Vue、React 与 Web Components 适配器各自负责首尾两步。

包一览 ​

按职责分四组。详细依赖关系见包与依赖关系。

内核与原语

包职责
@xihan-ui/core运行时底座:解剖、mergeProps、normalizeProps、Scope、层栈、诊断通道;薄状态机运行时(createMachine、解释器契约、受控值绑定);交互行为原语(消隐层、焦点域、滚动锁、进出场、集合导航、typeahead)
@xihan-ui/motion动效原语:缓动单一真源、纯补间、帧循环、减弱动效偏好、解析解弹簧
@xihan-ui/position浮层定位引擎,自研,零第三方依赖
@xihan-ui/pointer指针会话:一根指针从按下到抬起的跟手、过滤与收尾,自研,零依赖
@xihan-ui/viz图表引擎:比例尺、刻度、形状、坐标轴布局、拾取与降采样,全部是纯函数,自研,零依赖

组件与适配器

包职责
@xihan-ui/headless136 个组件的解剖 + 状态机 + connect,无样式、无框架
@xihan-ui/vueVue 3 适配器
@xihan-ui/reactReact 19 适配器
@xihan-ui/web-componentsWeb Components 适配器,自研响应式基类

表现

包职责
@xihan-ui/tokens设计令牌(DTCG 源)与主题运行时(明暗 / 品牌 / 密度 / 对比度 / 书写方向)
@xihan-ui/styles默认皮肤,按 @layer 分层的纯 CSS
@xihan-ui/icons图标集

内容与效果

包职责
@xihan-ui/chat-streamAI 协议内核:SSE 读取 → 协议归一 → parts 归约 → 会话 store
@xihan-ui/markdown流式 Markdown 渲染内核,增量切块 + 稳定 key
@xihan-ui/code-highlight代码着色,自研粗粒度词法器;适配器的可选 peer,未安装时渲染纯文本
@xihan-ui/backgroundsWebGL2 背景效果与数据驱动粒子点云
@xihan-ui/sound纯 Web Audio 程序化 UI 音效,零音频文件
@xihan-ui/animations现成的进场与注意动效、错开起播、文字拆分

tooling/* 下的构建、lint、tsconfig、测试与门禁脚本等内部包一律不发布。

目录结构 ​

XiHan.UI/
├── ui/                      # 组件库工作区(pnpm workspace)
│   ├── packages/            # 对外发布的库包,按角色分四组
│   │   ├── adapters/        # vue · react · web-components,按宿主选择
│   │   ├── design/          # tokens · styles · icons,外观
│   │   ├── features/        # markdown · chat-stream · backgrounds · sound · animations · code-highlight,按需选用
│   │   └── engine/          # core · motion · pointer · position · viz · headless
│   └── tooling/             # 内部构建与质量工具
│       ├── build/           # 打包配置与 exports 回写
│       ├── eslint-config/   # lint 规则 + 分层拓扑事实源
│       ├── stylelint-config/
│       ├── testing/         # 一致性 / 无障碍 / 定位三套判据的运行时
│       └── scripts/         # 门禁脚本
└── docs/                    # 文档站(VitePress),通过 link: 引用上述库包

文档站提供 Vue、React 与自定义元素的真实组件示例;示例源文件在 docs/.vitepress/demos/<组件>/ 下。各框架覆盖由 check-demo-frameworks 核对,不适用项和缺席项分别登记。

技术选型 ​

位置选型
语言TypeScript,ESM only(不提供 CJS)
运行时要求(消费端)Node ≥ 18;浏览器为 2024 年常青版(皮肤用了 @layer、color-mix、oklch)
运行时要求(开发本仓)Node ≥ 24、pnpm ≥ 11
构建tsdown(库包)+ turbo(任务编排)
样式原生 CSS,@layer 分层,oklch 色彩空间,无预处理器
测试vitest(jsdom)+ Playwright(真实 Chromium)
发布changesets,全部库包同属一个 fixed 版本组

下一步 ​

Released under The MIT License