@xwink/ui

写作约定

demo 单一事实源(D7)

预览与源码都来自 app/examples/**/*.vue 同一个文件——DemoBlockimport.meta.glob 双取(组件 + ?raw 源码),不存在「预览一份、贴代码一份」的漂移。

  • 文件路径即 demo 名app/examples/button/basic.vue::demo{name="button/basic"}
  • 每个 demo 自包含:自己 import 用到的 @xwink/ui 组件与 vue API,不依赖页面上下文。
  • 组件页配 2-3 个 demo:一个基础、一个交互、一个边界(disabled / 错误态 / 空态)。

SSR 安全(I8)

示例会 SSR 直出并进 SSG 全站预渲染,构建期与运行期的输出必须一致

  • 禁止随机值(Math.random)、时间戳(Date.now)、不稳定的 v-for key。
  • 初始状态必须确定:交互状态一律从确定值出发(如 v-model 初始空串、loading 初始 false)。
  • 「运行期才有的东西」(命令式弹窗、toast)用触发按钮承载,不在初始化时执行。
  • 违反会出现 hydration mismatch 或 generate 产物漂移,dev 控制台与 generate 都能抓到。

两级 demo 形式

L0:内联 MDC

props / slot 一览无余的组件(Button / Icon / Input 这类)直接写在正文里:

md
::x-button{variant="primary"}
点我
::

解析链:MDC 标签 → components/content/ 里同名包装组件(转发 attrs/slot)→ @xwink/ui 组件。带脚本上下文的组件(Dialog / Select / Table)不推荐 L0——状态在正文里表达不了。

L1:DemoBlock

需要脚本上下文(v-model 状态、列表数据、事件组合)的演示写进 app/examples/

md
::demo{name="button/basic" title="按钮变体"}
::

DemoBlock 自带「源码」折叠与「复制」,预览区 SSR 直出——文档站本身就是组件库的 SSR 金丝雀(roadmap I5),个别确认无法直出的场景用 ClientOnly 局部降级并给库记 todo,不顺手改库。

图标登记

demo 里用到的 ph:* 图标必须已在 scripts/gen-docs-icons.mts 的清单里登记(注册表保证离线 SSR 直出)。新增图标:加名字 → pnpm -F @apps/ui-docs gen:docs-icons → 提交生成物。