Remix UI 模块 README 写作方法论:write-ui-module-readme Skill 实战解析
2026/9/10 15:25:58 网站建设 项目流程

Remix UI 模块 README 写作方法论:write-ui-module-readme Skill 实战解析

【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remix

本文基于 Remix 仓库中的 Agent 技能文档 write-ui-module-readme/SKILL.md,系统讲解如何为@remix-run/ui包内的一级 UI 原语(popover、button、menu 等)撰写“Agent 友好”的模块级 README。读完本文,你将掌握这套从源码确认行为、复用 demo 形态、到六段式结构编排的完整写作工作流,并能以仓库中 popover 模块 README 为样板,独立完成其他 UI 模块的文档编写。

一、这个 Skill 解决什么问题

SKILL.md 是一个面向 AI Agent 的工作技能定义。它的 YAML frontmatter 用两句话界定了触发场景:

  • name: write-ui-module-readme
  • description: 为packages/ui内的 UI 原语模块(如 popover、press 等第一方 UI 辅助模块)起草或修订 README,核心目标是让 Agent 能够正确、快速地采用模块,并用简短段落解释每个导出值。

它开篇即明确了四个优化目标,全部指向“快速正确的采用”(fast, correct adoption):

  1. 先展示规范用法(canonical usage)
  2. 逐个简短解释每个module.*导出值
  3. 记录重要的行为保证(behavior guarantees);
  4. 避免实现历史堆砌与内部类型走查

文档特别强调:这是UI 原语的模块级文档,不是包级 README——写作尺度应贴近单个模块,而不是复述整个 UI 包的介绍。

一个值得注意的细节:Skill 中引用的模块路径写作packages/ui/src/lib/*,而从当前仓库的实际目录结构看,各原语直接位于packages/ui/src/<module>/下(如 packages/ui/src/popover/、packages/ui/src/menu/packages/ui/src/tabs/等),每个模块目录内同时包含源码、测试、demo 与 README,这正是该 Skill 工作流第 2 步“就近读取测试与 demo”得以成立的仓库布局。

二、四步写作工作流

Skill 给出的 Workflow 是严格有序的,核心思想是**“证据先行,文档在后”**:

  1. 先读模块源码
    • 识别真正的公开导出及其角色;
    • 从代码而非记忆中确认行为(Confirm the behavior from code, not memory)。
  2. 再读就近的测试与 demo
    • 从测试中提炼行为说明(behavior notes);
    • 当 demo 存在时,复用其中最贴近真实场景的示例形态(the most realistic example shape from a demo)。
  3. 只记录模块“今天的样子”
    • 不描述计划中的 API;
    • 除非属于公开契约,否则不写内部协调器(internal coordinators)、私有状态或 workaround 历史。
  4. 保持 README 短小且可扫读
    • 偏好短段落和扁平列表;
    • 一个强有力的规范示例,胜过多个薄弱片段(one strong canonical example instead of multiple weak snippets)。

这四步在仓库中得到了完整印证:以 popover 模块为例,目录内 index.ts 是导出清单的唯一事实来源,popover.demo.tsx 提供真实示例形态,index.test.tsx 与 scroll-lock.test.tsx 提供可引用的行为保证——README 的三块内容(用法、导出参考、行为说明)恰好分别来自这三类证据源。

三、推荐结构:六段式编排

Skill 给出的默认结构如下(除非模块需要更具体的定制):

  1. # ModuleName
  2. 一两句话:它是什么、用来做什么、不适合做什么
  3. ## Usage
  4. ## \module.*`` 或等价的导出参考节
  5. ## Behavior Notes
  6. 当该原语位于更高级组件之下时,追加## When To Use Something Else

对照 popover/README.md,可以逐条映射出该结构的落地形态:

Skill 规定结构popover README 实际落地
# ModuleName# popover
一两句定位“low-level primitive for anchored, dismissible floating panels”,并明确 menu/select/combobox 应在其之上构建而非直接暴露popover.*混入
## Usage## Primitive Usage,给出完整的ViewOptions组件示例
导出参考节## remix/ui/popover,逐一说明popover.Contextpopover.anchor(options)popover.surface({ open, onHide, ... })popover.focusOnShow()popover.focusOnHide()及四个原语类型
## Behavior Notes五条行为保证:打开时锚定并锁定滚动、onHidereason取值、焦点注册优先级、closeOnAnchorClick: false的适用场景等

这一对照说明该 Skill 不是空泛的模板,而是仓库中已有模块文档的共同母版。

四、Usage 节怎么写:一个可复制的规范示例

Skill 对 Usage 节的要求是:以一个可复制粘贴、反映真实用法形态的示例开场,并给出四条具体标准:

  • 偏好生产形态的 UI,而非玩具片段;
  • 使用真实的导出 API 名称
  • 展示正确使用该原语所需的最小周边结构
  • 若模块与其他第一方 UI 辅助组合使用,展示这种组合

对于 popup 风格的原语,示例通常需要覆盖四要素:

  • trigger(触发器)
  • surface/root(浮层根节点)
  • 一两个有实际意义的内部控制
  • 关闭或完成路径(dismissal or completion path)

仓库中的 popover/demo 就是这四要素的完整示范:button()触发器 +popover.anchor({ placement: 'bottom-start', offset: 8 })锚定 + 面板内的Close按钮(popover.focusOnShow()接收初始焦点)+onHide()完成关闭回写状态。而 popover/README.md 的示例在此基础上精简为最小骨架,并额外演示了触发器上挂popover.focusOnHide()(关闭后焦点归还)与面板内挂popover.focusOnShow()(打开时接收焦点)这对焦点往返组合——这正是 Skill 要求的“当模块与其他第一方辅助组合时,展示组合”。

需要注意命名事实:README 示例中导入写作from 'remix/ui'from 'remix/ui/popover',而仓库内的 demo 实际使用from '@remix-run/ui'from '@remix-run/ui/popover'(见 popover.demo.tsx 第 1-3 行)。以仓库源码为准,本地开发时应以后者为准。

五、导出参考节:每个module.*值说清楚四件事

Skill 要求示例之后逐个解释重要导出值,并给出了通用示例清单:

  • module.context:提供什么共享协调;
  • module.button(...):注册或激活了什么;
  • module.surface():把宿主节点变成了什么;
  • module.dismiss():如何关闭或收尾;
  • module.change:发出什么事件、哪些事件字段有用。

每一段解释聚焦四个问题:做什么、应用在哪里、关键参数或选项、可观察行为,并明确警告“不要把它变成完整的 API dump”。

以 popover 模块为例,index.ts 末尾的实际导出是:

export const Context = PopoverProvider // 共享协调:hideFocusTarget / showFocusTarget / surface / anchor export const anchor = anchorMixin // 注册宿主为当前 surface 的锚点 export const surface = surfaceMixin // 把宿主变成受控 popover surface export const focusOnHide = focusOnHideMixin // 注册关闭时应重新聚焦的元素 export const focusOnShow = focusOnShowMixin // 注册打开时应聚焦的元素

同时导出四个类型:PopoverContextPopoverPropsPopoverSurfaceOptionsPopoverHideRequest。README 的导出参考节恰好一一对应这些导出值,且每个只用三五行说明——例如popover.surface(...)一条就覆盖了四个要点:

  • 做了什么:接入popover="manual"与原生的showPopover()/hidePopover()行为(对应 index.ts 中attrs({ popover: 'manual' })beforetoggle监听);
  • 应用在哪:应用到真正的浮层根节点,而不是嵌套子节点
  • 关键选项:closeOnAnchorClick: false(锚点需在打开期间保持可交互时使用);
  • 可观察行为:对Escape与外部点击回调onHide并携带PopoverHideRequest,除非restoreFocusOnHide: false,否则把焦点还原到已注册的 hide target。

PopoverHideRequest的形状(reason: 'escape-key' | 'outside-click',可选target)在 index.ts 第 49-52 行 有明确定义,README 的 Behavior Notes 中{ reason: 'escape-key' | 'outside-click', target? }与之完全一致——这就是“行为来自代码而非记忆”的落地效果。

六、Behavior Notes:替读者回答“然后会发生什么”

Skill 对 Behavior Notes 节的要求是记录组合使用时真正重要的行为,列举了六个检查面:

  • 焦点移动(focus movement)
  • 关闭规则(dismissal rules)
  • 锚定规则(anchoring rules)
  • 键盘行为(keyboard behavior)
  • 多触发器行为(multi-trigger behavior)
  • 模块测试套件中验证过的任何重要保证

其目的被表述得非常直白:让读者不必打开实现代码就能回答“……时会发生什么”(save a reader from opening the implementation just to answer "what happens when...?")。

popover 模块的五条行为说明恰好对应这些检查面,且每条都能在实现中找到出处:

  1. “打开时把 surface 锚定到已注册 anchor 并锁定页面滚动,直到关闭” —— 出自 index.ts 中beforetoggle里调用positionAnchor(...)lockScroll(),以及关闭时执行cleanupAnchor()/unlockScroll()
  2. onHide接收{ reason: 'escape-key' | 'outside-click', target? }” —— 出自keydown监听(Escape 分支)与onOutsideClick接线;
  3. focusOnShow()在打开时存在即生效” —— 出自toggle事件中context.showFocusTarget?.focus()
  4. focusOnHide()默认在关闭且启用焦点还原时使用” —— 出自restoreFocusOnHide !== false的判定;
  5. closeOnAnchorClick: false让锚点点击留在当前会话内,适合 combobox 这类输入驱动型 popover” —— 对应 outside-click.ts 中isInsideTarget匹配器对anchorContains的放行逻辑。

其中滚动锁定的实现细节(引用计数、保存并恢复overflow/scrollbarGutter/ 滚动位置、scrollbarGutter: 'stable'防布局抖动)见 scroll-lock.ts;外部点击判定采用 document 级capture: true监听并默认stopPropagationstopOutsideClickPropagation选项,对应 surface 选项stopOutsideClickPropagation),见 outside-click.ts 与 index.ts 第 132-140 行。

七、范围规则与写作风格约束

Skill 的 Scope Rules 与 Good Patterns 共同界定了“写什么、怎么写”的边界:

范围规则

  • 主要受众是想正确使用原语的 Agent 或开发者
  • 用法指导优先于架构解释;
  • 可以命名公开事件与有用的事件字段,但避免深入事件类内部实现(除非确有必要);
  • 不写私有类、内部协调器或辅助 mixin(除非该 README 就是为那个 helper 写的);
  • 不要用 Agent 已经知道的通用无障碍理论或 popover 理论去注水

推荐的表述模式(原文四条示例,可直接作为写作范式):

  • “Usepopoverdirectly for custom floating panels like filters or view options.”(用途定性)
  • “Wrap triggers and the surface inpopover.context.”(结构要求)
  • “The opener that started the current session controls anchoring and focus return.”(行为归因)
  • “Do not use this as the final consumer-facing primitive for menus or comboboxes.”(边界声明)

对照 popover README 的第二段“Higher-level widgets like menu, select, and combobox should build on top of it instead of exposing rawpopover.*mixins directly”,正是第四条模式的实例化。

八、交付前 Checklist

Skill 末尾提供了一份自检清单,六问对应工作流各环节的收口:

  • 是否先读了模块源码?
  • 是否从测试或 demo 中确认了行为?
  • README 是否以一个真实感的用法示例开场?
  • 是否简短地解释了每个重要的导出值?
  • 是否包含实践中重要的行为说明?
  • 是否避免了内部实现细节与历史调试背景?
  • 一个 Agent 能否在不打开源码的情况下正确使用该原语?

最后一条是整套方法论的验收标准:README 的服务对象首先是机器消费者,写作质量以“Agent 能否据此正确组合出可运行的用法”来度量。

九、小结:把这套方法用于其他 UI 模块

若要为仓库中其他模块(packages/ui/src/下的 accordion、anchor、animation、breadcrumbs、button、checkbox、combobox、input、listbox、menu、radio、select、tabs、toggle 等)按此 Skill 撰写 README,可直接套用本文流程:

  1. 打开该模块的index.ts,列出全部export,逐一对应“做什么/应用在哪/关键参数/可观察行为”;
  2. 读取同目录*.test.**.demo.tsx,把测试断言转写成行为说明,把 demo 形态转写成规范示例;
  3. 按六段式结构落稿,定位段必须同时说明“适合做什么”与“不适合做什么”;
  4. 用 Checklist 收口,尤其确认示例可复制运行、行为说明有源码依据、无内部实现注水。

这套 Skill 与 popover/README.md 的互证表明:Remix 仓库的 UI 模块文档已按“Agent 可执行、开发者可扫读”的标准模板化,新模块文档只要遵循同一证据链(源码 → 测试/demo → 结构编排),即可保持一致的信息密度与采用友好度。

【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remix

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询