体系:跨组件共享行为的治理机制与实践指南)
Astryx 组件族契约Family Contract体系跨组件共享行为的治理机制与实践指南【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx导读组件族契约Family Contract是 Astryx 开源设计系统中用于跨组件共享行为治理的核心机制当一组兄弟组件需要共享输入框尺寸、末端操作位end lane、浮层关闭overlay dismissal或状态呈现等行为时家族契约负责拥有这些共享规则而单个组件规范component spec只需链接到所属家族不必复制共享规则。本文将以docs/families/README.md为骨架结合docs/templates/knowledge/family-contract.md模板、6 份已批准的家族契约记录以及packages/core中的真实源码与测试完整讲解家族契约的定位、生命周期、记录结构与六大实际家族按钮、输入字段、布局原语、布局区域、导航目标、浮层关闭帮助读者掌握这套知识契约体系的设计意图、读写规范与验证方式。一、什么是组件族契约在 Astryx 仓库中docs/families/README.md用三句话定义了家族契约的定位Family contracts own behavior shared by sibling components, such as input sizing, end lanes, overlay dismissal, or status presentation. A component spec links to its family instead of copying the shared rule.即家族契约拥有兄弟组件之间共享的行为典型如input sizing输入框尺寸如sm/md/lg的统一行高契约end lanes输入字段末端操作位如清除按钮、加载 Spinner、状态控件、展开按钮占用的非重叠空间overlay dismissal浮层关闭如 Escape 只关最上层浮层的单一栈规则status presentation状态呈现如校验状态的attached/detached/tooltip三种放置方式。这一设计直接服务于单一事实、单一属主one fact, one owner的仓库知识治理原则见 knowledge-contracts.md 中的 INV2组件规范只描述这个组件独立承诺的聚合行为凡是被多个兄弟组件共享的规则一律收敛到家族契约避免同一规则在多份组件文档中被复制、改写以致漂移。家族契约的生命周期非常明确新记录以draft草稿起步仅供评审参考不构成规则只有经过显式的属主owner批准后才升级为current当前生效评审与实现才可依赖被取代的记录转为archived归档保留上下文并说明为何不再治理。新记录的撰写必须使用 docs/templates/knowledge/family-contract.md 模板模板字段由 docs/schemas/knowledge/v3.json 定义并由 scripts/check-knowledge.mjs 校验模板、记录与审批元数据。二、家族契约记录的标准结构每一份家族契约都遵循统一的模板骨架理解这套骨架是读懂任何一份家族契约的前提。以 family-contract.md 为例记录由frontmatter 元数据与正文小节两部分组成。2.1 frontmatter记录的身份与权威信息字段含义schema_version/template_version当前采用的 schema 与模板版本kind固定为family与 component/module/design/theme/system 等知识记录种类区分id规范 ID格式为family:family-name作为其他记录链接的规范标识authoritydraft/current/archived三态之一archive_reason/superseded_by归档原因与取代它的记录 IDapproved_by/approved_at批准人owner与批准时间current的前提owners记录属主列表负责该家族后续评审与变更review_triggers触发评审的维度如behavior, layout, theming, accessibility, public-apiverified_by代表性验证锚点测试或检查如packages/core/src/Button/Button.test.tsxmembers家族成员组件列表格式为component:Namearchitecture/contributing关联的架构记录与贡献记录deciding_specs做出关键决策的规范引用如spec:AST-002/DEC-12.2 正文小节契约的九大组成部分模板正文规定了 9 个必备小节每份家族契约都必须覆盖Intent意图一段话说明用户构建者在使用这一族组件时应获得的一致体验Membership rule成员规则明确什么组件属于、什么组件是协作者Collaborators、什么组件被排除Excluded——成员资格依据公开职责而非是否 import 了某个组件或渲染了某个元素Shared owner共享属主指出某个共享概念由哪个原语、Hook 或接缝拥有如 Button 家族中 Button 拥有公共操作表面IconButton 是 Button 的纯图标投影Canonical concepts规范概念以表格列出共享概念及其取值/状态、默认语义与稳定性Cross-component invariants跨组件不变式以FR1、FR2……编号列出每个成员 MUST/MAY/MUST NOT 的硬性规则Allowed component variation允许的组件差异以AV1、AV2……编号列出成员被允许的刻意差异这正是族区别于单一组件的地方Representative matrix代表矩阵把成员 状态映射到共享不变式 刻意差异Adoption and exceptions采纳与例外逐组件记录当前采纳机制与已知缺口/例外并明确哪些是待关闭的实现缺口而非已批准的例外Verification map验证映射把每个 FR 映射到具体测试/浏览器证据、代表成员与状态以及何种变异会让它失败的失败预期。此外还有Decision links决策链接、Open questions开放问题与Content boundary内容边界三个收尾小节。其中 Content boundary 尤其重要它声明本文件只拥有跨组件家族行为不重复组件本地属性表、回调载荷类型、消费者文档、当前审计结果或系统规范依据——这正是 INV2一个事实只有一个属主在家族层级的落点。三、六大已生效家族契约详解截至本文写作时docs/families/下共有 6 份authority: current的家族契约它们共同覆盖了 Astryx 核心组件库packages/core的主要共享行为面。下面逐一拆解其核心内容。3.1 按钮家族family:buttons记录位置docs/families/buttons.md。批准人cixzhang批准于 2026-09-04。意图无论动作是有标签的、纯图标的、持久的、独立的还是分组的用户面对的都应当是一套连贯的按钮系统。成员共享相同的控件几何、可访问名称要求、交互反馈、异步动作模型与表面所有权同时各自拥有瞬时动作、导航目标、持久按下状态或分组的专属语义。成员MembersButton、IconButton、ToggleButton、ButtonGroup、ToggleButtonGroup。协作者CollaboratorsSpinner挂起反馈、Tooltip可见解释、LinkProviderButton 的导航渲染器、SizeContext继承的控件尺寸、DropdownMenu可向 ButtonGroup 提供按钮触发器。协作者不会因此成为按钮家族成员。排除ExcludedLink 的主职是导航而非按钮表面Switch、CheckboxInput、RadioList 表达设置或表单值而非按钮动作SegmentedControl 与 TabList 在各自的选区/导航契约下切换视图或目标。规范概念表节选核心行概念取值/状态默认语义稳定性激活模型瞬时动作 / 导航 / 持久按下Button 与 IconButton 激活一次ToggleButton 表达保留的按下状态已发布区分内容模式可见标签 / 自定义可见内容 / 纯图标每个控件必须有可访问的label纯图标时视觉隐藏已发布家族规则尺寸sm、md、lgmd显式成员尺寸优先于继承的组尺寸已发布家族轴视觉状态rest、hover、focus、active、disabled、loading按下处适用 pressed状态保持控件几何与可访问目的已发布家族规则异步动作无 / fire-once / 可中断持久动作普通动作在挂起期间去重持久切换保持可逆已发布家族区分高度elevationnone、low、med、highnone绘制可见表面的元素拥有阴影已发布家族轴分组独立 / 有间距集合 / 连接表面语义与绘制包含决定所有权家族规则12 条跨组件不变式FR1–FR12中最值得注意的几条FR1每个控件必须有非空的可访问label纯图标控件通过aria-label暴露标签图标不能替代程序化名称。源码中 Button.tsx 的isIconOnly映射与测试 Button.test.tsx 完全印证测试断言isIconOnly时label被映射到aria-labelmaps label to aria-label and keeps the icon when icon-only断言toHaveAttribute(aria-label, Settings)。FR2原生动作语义是默认——渲染可操作的按钮、键盘激活、focus-visible 反馈、typebuttonhref模式是显式导航变体同时遵循family:navigation-destinations。FR4挂起反馈必须设置aria-busy、保持控件尺寸稳定、呈现 Spinner 而不改变可访问目的。测试中多处断言 loading 时aria-busytrue同步设置sets aria-busy synchronously while clickAction is pending且链接模式渲染的按钮同样暴露aria-busy。FR7共享尺寸必须保持家族几何——sm/md/lg映射到同一控件高度契约纯图标成员在解析尺寸下为正方形标签字重、按下状态、加载或图标替换不得改变外部尺寸。FR8/FR9高度属于绘制的表面——独立成员拥有自己的静息高度连接组只拥有一份共享高度成员绘制none按下/hover/focus/loading 等交互状态不得改变高度的属主或层级。FR10公开属性、渲染的data-*状态与文档化主题视觉属性必须描述实际绘制的值wrapper 不得把被忽略的子值报告为有效输出。FR12连接组与有间距组保持区分——ButtonGroup 移除成员间隙、共享外边缘、拥有一个高度并使用文档化的 roving-focus 键盘模型当前 ToggleButtonGroup 保持独立子表面以间隙分隔。已验证缺口ToggleButton 的高度elevation采用是已批准的实现缺口——把已有可选elevation轴加回去即可恢复家族对等性且不改变无 prop 时的渲染。其透明 ghost 表面是已知视觉问题阴影可能提供浮动边界而非不透明填充或描边任何后续填充/描边方案都需要单独视觉评审。3.2 输入字段家族family:input-fields记录位置docs/families/input-fields.md。批准人cixzhang、imdreamrunner批准于 2026-09-09。这是成员最多的家族13 个成员也是决策记录最丰富的一份。意图用户面对一套连贯的输入系统状态显示、行为、外观与尺寸在成员间使用一致的处理与 API 契约同时每个组件保留其编辑值特有的交互模型。成员TextInput、TextArea、NumberInput、DateInput、DateRangeInput、DateTimeInput、TimeInput、FileInput、Selector、MultiSelector、ComplexSelector、Typeahead、Tokenizer。协作者Field 与 FieldStatus共享字段外壳、FormLayout字段排布、InputGroup显式采纳其能力契约的分组成员、InputClearButton、Spinner、Tooltip、BaseTypeahead。排除CheckboxInput、RadioList、Switch、Slider 使用带标签的控件模型但没有内容/末端通道几何PowerSearch 与 ChatComposer 是消费成员行为的更高级组合BaseTypeahead 是没有字段表面的 combobox 引擎。8 条跨组件不变式FR1–FR8的关键含义FR1 — 行内尺寸在普通字段状态间保持稳定占位符变成值、或出现 busy/status/clear 控件都不得仅因此改变字段外部可用行内尺寸。Selector是 DEC-1 批准的例外可跟随其显示内容。FR2 — 渲染的末端控件拥有非重叠空间文本、token、光标与选中内容不得绘制或接收指针事件于清除动作、Spinner、状态控件、展开按钮或组件自有末端内容之下。这是可观察需求不是对测量或共享通道原语的强制。FR3 — InputGroup 接纳要求完整的成组适配成员只有在显式采纳成组模式并证明从组解析兼容控件高度与尺寸、移除/抑制竞争的外层 Field/边框/圆角/表面几何、连贯地委托连接外边框/圆角/组级焦点呈现、通过组件自有截断/折叠/裁剪/溢出保持单行组几何、保留可访问名称与描述/值语义/键盘行为/焦点行为/编辑或选择模型后才可参与。这是能力契约而非永久白名单——家族成员身份或上下文消费本身不足够。FR4 — 禁用原因保持可达暴露disabledMessage的成员其非活动字段必须保持足够可聚焦以暴露原因同时编辑/选择/激活仍被阻止。FR5 — 输入加载描述的是值而非支撑数据isLoading表示字段值正在解析或保存不得使独立提供的选项不可用或改变数据源 prop 的契约。FR6 — 过渡动作changeAction保持即时反馈每条文档化的值变更路径先跑onChange、乐观呈现提议的受控值、在 React transition 中运行changeAction、并贡献到同一 busy 呈现直到受控值接受或替换它。FR8 — 状态放置跟随成员能力每个输入必须提供detached与tooltip只有直接控件不透明、有边框、固定高度且其属主根能可靠反映用于重叠的解析尺寸时成员才支持attached且支持时attached为默认。直接 FieldStatus 仍只支持 attached/detachedField 在渲染 FieldStatus 前消费tooltip。5 条决策DEC-1 ~ DEC-5是这份契约的独特价值记录于文档末尾DEC-12026-08-30独立 Selector 是行内尺寸例外可按显示的占位符/选中值伸缩但不解除 FormLayout、受支持的 InputGroup 或显式产品布局的约束DEC-22026-08-30isLoading描述值解析或保存不描述选项/支撑数据加载对应 AST-001/DEC-1、DEC-2 应用于 Selector/MultiSelector提供的选项保持可用、零选项是无选择状态、初始选项源挂起必须显式DEC-32026-08-30changeAction及其乐观/挂起行为属于输入家族契约DEC-42026-08-31attached 是条件能力而非通用几何并明确拒绝了从后代data-size推导通用 attached 重叠的方案DEC-52026-09-09InputGroup 接纳是能力制——拒绝永久硬编码白名单、Tokenzier 专属例外、无完整成组适配的上下文消费以及强制独立多行/多 token 输入进入单行呈现。Tokenizer 在该规则下被接纳成组默认使用组件自有单行溢出处理。3.3 布局原语家族family:layout-primitives记录位置docs/families/layout-primitives.md。批准于 2026-08-30。意图构建者应当能用同一套小词汇表在一维或二维中排布任意内容、居中它、调整其布局框尺寸并表达空间关系。选择 Stack、Grid 或 Center 改变的是排布模型而不是创造第二套间距刻度或共享 prop 名的新含义。成员Stack及其HStack/VStack便捷形式、StackItem、Grid、GridSpan、Center。成员资格遵循公开职责而非实现机制——仅仅因为源码用了 flexbox 或 grid 并不足以加入。共享属主SpacingStep拥有成员 gap/padding prop 使用的公开数字间距词汇SizeValue拥有数字即像素、字符串即 CSS 值的盒子尺寸契约architecture:container-padding拥有 bleed 几何——局部 padding 本身并不发布该协议。规范概念间距步长取值为0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10盒子尺寸为数字或 CSS 值字符串流动方向默认垂直gap 是排列项之间的空间而非容器内边距。9 条不变式FR1–FR9中值得一提的FR3 — Padding 优先级按边显式边值 轴值 统一padding且覆盖只改该边FR4 — Gap 与 padding 保持区分gap 分隔排列项padding 在成员自身盒内嵌入内容Grid 的rowGap/columnGap只在其轴向上覆盖统一 gapFR6 — 修饰组件要求其父模型StackItem 控制 Stack 中的参与GridSpan 控制 Grid 中的参与组件契约拥有在预期父级之外的行为FR8 — 局部 padding 不是 bleed 信号Stack 与 Center 当前应用 padding 而不发布容器内边几何后代只有在architecture:container-padding命名的发布者下才能依赖 bleed 补偿。验证现状诚实的缺口声明当前测试是组件本地的且多处只断言渲染成功或类变化并未证明跨成员的计算 gap、对齐、逻辑方向或对等性。验证映射逐条列出缺失证据列如 FR1/FR3 缺跨成员或双向书写方向的计算值浏览器矩阵、FR2 缺LTR 与 RTL 下的 padding 阶梯渲染测试、FR4 缺与 Stack 的步长对比。这正是家族契约体系的诚实性体现——已命名的验证缺口不会被宣称已修复。3.4 布局区域家族family:layout-regions记录位置docs/families/layout-regions.md。批准于 2026-08-31。意图页面或有界工作区在添加产品内容之前就应有可预测的结构区域。构建者可以使用通用 Section、五槽位 Layout 原语或语境化 Toolbar而不必让每个表面各自发明内边、边界、区域方向或内容所有权。AppShell 拥有组合这些低层区域与应用导航的页面外壳。成员SectionLayout及其Header、Content、Footer、Panel区域Toolbar。12 条不变式FR1–FR12的要点FR1 — 区域拥有结构而非产品含义成员建立空间边界并渲染调用方内容不采纳内容的语义/状态/组件契约FR3 — Layout 依据槽位在场选择几何Header/Content/Footer/Panel 在接触 Layout 边界处应用外内边在接触另一区域处应用内内边省略的槽位不留下区域 wrapperFR5 — 边界所有权在组合允许双属主时由调用方选择可调整大小的面板组合在相邻 ResizeHandle 拥有分隔线时必须设置LayoutPanel hasDivider{false}FR8 — 地标语义保持显式命名视觉位置不会自动分配banner/main/navigation/complementary/contentinfo调用方必须提供受支持的角色与标签FR10 — 调整大小所有权保持委托带resizable的 LayoutPanel 使用 Hook 提供的当前尺寸而非widthpropFR12 — contentWidth 把滚动条保持在开放内容边缘无面板时 LayoutContent 横跨可用中部区域并通过上下文感知行内内边对齐直接子级恰有一个面板时该面板保持对齐居中框而内容延伸过对面开放侧双侧面板或百分比/固有宽度/裸变量时整体保持约束calc(var(...))是显式的带长度值变量路径对应 DEC-3。3 条决策DEC-1 划定结构区域与组合原语分属两个家族DEC-2 确定 AppShell 拥有页面外壳而 Layout 是通用五槽位原语DEC-3 确定仅内容宽度对齐留在内容滚动口内。源码佐证Toolbar在 Toolbar.tsx 中把绘制表面、变体与选中分隔线边委托给 Section注释与import {Section} from ../Section/Section可见而 Section.tsx 提供variant与dividers{[top,bottom,start,end]}的选中分隔线 API——与契约中Toolbar delegates its painted surface, variant, and selected divider edges to Section完全对应。3.5 导航目标家族family:navigation-destinations记录位置docs/families/navigation-destinations.md。批准于 2026-08-31。意图用户应从每个接受或派生目标的 Astryx 组件获得相同的安全导航行为。组件的视觉角色、路由集成或放大的点击目标不得决定一个被阻止的目标能否执行。成员开放清单Avatar、BreadcrumbItem、Button链接模式、Citation、ClickableCard、Item、Link、ListItem、Markdown链接、NavHeadingMenuItem、SideNavHeading/SideNavItem、导航模式Tab、Token链接模式、TopNav系列、TreeListItem。排除Outline 的 Astryx 生成#id链接、AppShell 的固定 skip-to-content 片段、作为子级提供的任意链接、Markdown 插件输出、图片/媒体/资源 URL以及仅组合成员而不接受/派生其目标的组件。8 条不变式FR1–FR8FR1 — 每个调用方控制的导航目标在进入其 sink 之前先被决策任何成员不得在共享规则运行前把目标传给自定义路由或命令式浏览器 APIFR2/FR3 — 备选渲染与备选激活保持规则通过LinkProvider/as替换原生锚点、_blank/Cmd/Ctrl 点击/中键点击/同标签分配/委托表面点击产生相同的接受/阻止决策FR4 — 被阻止的 scheme 无法执行经过浏览器兼容的 scheme 归一化后javascript:、vbscript:、data:text/html不得成为导航FR6 — 两个自定义路由 prop 都是 sink提供的href与显式to被独立检查任一个都不能通过 prop 优先级或 rest-prop 顺序绕过规则FR7 — disabled 与 rejected 是两回事拒绝目标阻止导航但不发明禁用状态、标签或视觉处理。共享属主与当前采纳缺口useLinkComponent拥有目标向原生/自定义链接组件的交接路由侧的href/to接缝useClickableContainer拥有放大表面的命令式导航同标签/新标签/修饰点击/中键点击路径Markdown 拥有把不可信源解析为目标并在渲染边界保持共享导航策略。文档诚实记录了两处待关闭缺口当前main上useLinkComponent自定义 provider/as路径与useClickableContainer命令式路径仍在转发原始href/to被标记为采纳缺口而非已批准例外接受实现为 #5524落地后需把新测试加入verified_by。源码佐证useLinkComponent.ts 的解析顺序为per-componentasprop LinkProvidercontext nativea且当解析为自定义组件时用createLinkWithTo包装同时传递href与to{href}以兼容 React Router、TanStack Router 等to系路由——直接呼应 FR6两个 prop 都是 sink、独立检查。3.6 浮层关闭家族family:overlay-dismissal记录位置docs/families/overlay-dismissal.md。批准于 2026-08-30。这是最典型的单一共享栈治理案例。意图用户关闭分层 UI 时只应影响最相关的顶层表面。当逻辑深度或 DOM 包含建立了顺序时嵌套表面不得在同一次 Escape 或平台关闭请求中关闭其宿主。成员Dialog、AlertDialog、Popover、DropdownMenu、DropdownMenuSubMenu、MoreMenu、Tooltip、HoverCard、Lightbox、MobileNav、BottomSheet、BottomSheetSwitcher、CommandPalette、ContextMenu、PowerSearchEditPopover、Lab Drawer以及大量组件自有弹层输入类ChatComposerInput、ComplexSelector、DateInput、DateRangeInput、DateTimeInput、Selector、MultiSelector、PowerSearch、BaseTypeahead、Typeahead、Tokenizer其他BreadcrumbItem、SideNavHeading/Item、TabMenu、TopNav 系列、Table 过滤、Lab TourStep、Lab ChatEmojiPicker。成员资格是开放的——每个新上线的符合规则的表面都必须加入共享栈。共享属主useLayerDismissal注册活动表面并把浏览器发起的关闭请求适配到共享顶层检查layerStack拥有在场过滤、排序与唯一的 document 级 Escape 监听器LayerDepthProvider通过 React 树携带逻辑嵌套供提供给后代的成员使用useFocusTrap活动且收到onEscape回调时加入同一栈没有onEscape的焦点陷阱不是可关闭表面不注册。7 条不变式FR1–FR7FR1 — 每个可关闭的浮层表面都参与成员在场时必须加入共享关闭栈组件自有 Escape 监听器或注册表不满足此不变式FR2 — 一次请求影响一个表面未被认领的 Escape 被路由到恰好一个最顶层的已注册在场成员该成员要么调用其关闭回调要么阻止请求请求不会继续传递到其后成员FR3 — 平台关闭请求使用同一顶层规则只有是最顶层已注册在场成员时才关闭指向低层成员的请求被拒绝FR4 — 可用嵌套信号高于宿主放置提供LayerDepthProvider的成员其 React 树深度把后代层排在其之前即使两者在同一 commit 挂载DOM 包含可解析等深嵌套稳定注册顺序解析无关表面FR5 — 内容可先认领 Escape共享监听器运行在冒泡阶段当内容已处理事件时退让FR6 — 文本组合不是层关闭用于取消活动 IME 组合的 Escape 被消费而不关闭成员组合进行中平台关闭请求被拒绝FR7 — 注册不定义打开状态所有权栈调用被选成员的关闭回调是否立即关闭由成员组件契约与调用方拥有。采纳缺口诚实声明BottomSheet、CommandPalette、ContextMenu、DropdownMenuSubMenu、PowerSearchEditPopover、Lab Drawer 当前仍为仅本地local only必须从组件自有监听器/注册表迁移到共享属主Tooltip/HoverCard 是共享属主 DOM 在场报告但不为后代层提供嵌套深度。源码级印证useLayerDismissal.ts 的 JSDoc 直白地写道The layer does NOT attach a key listener — the stack owns one listener and routes each Escape press to the top-most REGISTERED layer, so one press dismisses exactly one of them并列出当前已注册家族与六个仍跑自有监听器的组件BottomSheet、CommandPalette、ContextMenu、DropdownMenuSubMenu、PowerSearchEditPopover、labDrawer与契约的采纳表逐字对应。layerStack.ts 中可看到document.addEventListener(keydown, dispatchLayerEscapeKeyDown)、compositionstart/compositionend捕获监听与event.defaultPrevented退让逻辑对应 FR5、FR6以及registerLayer/isTopmostLayer的导出。四、家族契约与仓库其他知识记录的关系家族契约不是孤立的文档而是 Astryx 分层知识体系的一层。knowledge-contracts.md 给出完整系统模型组件契约描述一个组件承诺的聚合行为模块契约描述由单个组件拥有的独立可契约公共 Hook/插件/工具/子系统家族契约描述兄弟组件共享的行为本文主题设计规范记录人工拥有的视觉与交互决策主题规范记录一个包级主题的意图、token/调色板映射、配对/状态、例外与测量收据系统规范记录跨组件/跨主题或改变架构的决策消费者文档解释 props、示例与用法审计记录持有当前证据与发现运营存储为 wikicomponent-scores.json。评审者从改动代码出发按最近当前组件/模块契约 → 相关家族或设计要求 → 仅在被引用时进入架构/系统决策 → 映射的测试与审计证据的路径查证见上文的链路图。关键不变量 INV2一个事实只有一个属主意味着组件记录不得复制家族内容家族记录也不得重复组件本地属性表INV9 规定当前记录之间没有隐式优先级——更新的、更窄的、更本地的当前记录不会静默覆盖另一条当前记录冲突时评审停止并在规范属主处解决。家族契约中大量出现的deciding_specs如spec:AST-002/DEC-1负责公共 API 准入正是决策归属权的显式链接。五、如何验证一份家族契约每份家族契约的 Verification map 都回答了三个问题这条 FR 由什么证据验证覆盖哪些代表成员与状态什么变异会让它失败以按钮家族为例契约验证代表成员与状态失败预期FR1–FR3role/name、键盘、回调、禁用、禁用原因测试文本 Button、IconButton、ToggleButton、链接模式、成员/组禁用成员丢失名称、键盘路径或在禁用时调用FR4–FR6Action 顺序、挂起、乐观、去重、可中断测试Button fire-once ActionToggleButton 快速按下/松开 Action尺寸或目的变化、Action 绕过回调取消、陈旧状态胜出FR7单元加真实浏览器几何检查全部尺寸文本/纯图标按下/未按下加载家族高度分歧、纯图标不再是正方形、状态改变外部尺寸FR8–FR10data 属性、主题元数据、计算阴影测试独立 Button/IconButton/ToggleButton连接与有间距组每个高度层级阴影落在错误的盒上、状态改变深度、公开/主题/渲染值不一致FR11–FR12组语义、传播、DOM、键盘、渲染表面测试连接 ButtonGroup有间距 ToggleButtonGroup水平/垂直禁用成员组缺名称、默认传播失败、间距/连接所有权混淆这些测试锚点真实存在于packages/core/src下Button/Button.test.tsx、IconButton/IconButton.test.tsx、ButtonGroup/ButtonGroup.test.tsx、ToggleButton/ToggleButton.test.tsx。输入字段家族的验证则要求真实 Chromium 下的行内尺寸前后测量、内容盒/控件盒重叠矩阵窄宽度 LTR/RTL、InputGroup 渲染尺寸/高度/表面焦点所有权检查等——许多条目明确标注当前缺失证据由 scripts/check-knowledge.mjs 与仓库 CI 门禁共同把守。六、结语从复制规则到拥有规则Astryx 的家族契约体系解决的是组件库规模增长后的经典难题兄弟组件共享的行为规则一旦散落各处就会在一次次局部修补中漂移。家族契约用一套可验证的治理机制给出了答案——共享规则只写一次、由规范属主拥有、以 draft/current/archived 三态管理权威性、以 FR/AV 表格承载不变式与允许差异、以验证映射绑定测试证据、以内容边界防止越界复制。对读者而言阅读任何一份家族契约都遵循同一套心智模型先看 Intent 与 Membership rule 确认这一族覆盖什么、谁属于、谁被排除再读 Canonical concepts 表格掌握共享词汇表随后用 Cross-component invariants 判断成员必须做什么用 Allowed component variation 判断成员可以怎么不同最后用 Adoption and exceptions 与 Verification map 核实现状缺口在哪里、证据是否到位。这套方法不仅适用于阅读本文介绍的六大家族也适用于 Astryx 后续新增的任何家族记录——它们都共享 family-contract.md 这一模板骨架。【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考