@xwink/ui

    写作约定

    demo 单一事实源(D7)

    预览与源码都来自 app/examples/**/*.vue 同一个文件——DemoBlock 用 import.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 里用到的组件库子集外图标必须登记在 nuxt.config.ts 的 xwinkUi.icons 里(构建期抽取、两端注册,保证离线 SSR 直出)。新增图标只加名字,没有生成物要提交。