资讯动态

Astryx Text 组件契约解读:多态文本、语义标题与条件截断 Tooltip 的职责边界

发布时间:2026/9/15 17:45:45 来源:尧图企业网站定制
Astryx Text 组件契约解读多态文本、语义标题与条件截断 Tooltip 的职责边界【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx导读本文围绕 Astryx 开源设计系统中 Text 组件契约文档Text.spec.md展开深入拆解Text与Heading两个核心排版组件在渲染什么、携带哪个 theming target、何时委托 Tooltip三方面的既定职责边界。你将掌握text/heading两个主题目标target的归属与映射规则、maxLines截断与条件 Tooltip 委托的完整触发条件、由测试与校验脚本锁定的组件不变式invariant以及如何在自定义主题中为 Text/Heading 扩展自定义type与color。文章中的事实与代码均来自仓库源码、测试与配置可放心作为实现与审查依据。一、契约文档定位一份只记录现状、不新增行为的组件契约Text.spec.md是 Astryx 组件契约体系kind: componentid: component:Text中用于固化 Text 组件行为边界的技术文档。它的性质与普通 README 或 API 参考不同其核心特征是只记录现状draft契约状态为authority: draft全部内容是对当前消费者可观察行为的事实记录明确声明does not change runtime behavior, styling, targets, or public API不改变运行时行为、样式、目标或公共 API兼容性声明Released default preserved: yes属于纯增量的文档性契约运行时、DOM、样式、目标与公共 API 均保持不变因此没有迁移决策Migration decision: none校验驱动契约头部的verified_by字段声明了其事实由 Text.test.tsx、Heading.test.tsx、themingTargets.test.ts 以及 check-knowledge.mjs 共同验证。理解这一定位很重要它回答的是系统今天实际是什么样、谁拥有什么而不是未来要变成什么样。它既是审查者核对实现的基准也是主题theme作者与消费者判断改动是否越界的参照物。二、所有权边界Text 拥有什么Tooltip 与调用方拥有什么契约用Owns / Does not own划出了清晰的职责分工这也是全文的骨架。2.1 Text 拥有的内容多态 Text 元素及其当前的texttheming targetText 负责渲染承载内容的根元素并负责将type、size、解析后的color映射到text目标上Heading 成员的语义标题元素及其当前的headingtheming targetHeading 是 Text 的被引用成员referenced member两者共享同一份权威文档与目标清单截断委托决策由 Text/Heading 根据当前截断状态决定是否将 Tooltip 组合到 Text 或 Heading 元素之上。2.2 不归 Text 拥有的内容截断 Tooltip 的表层、层级行为与tooltip目标一旦条件截断路径渲染该表层由 Tooltip 组件全权拥有Text/Heading 的 children 内容内容本身由调用方caller提供并负责独立的 Heading 组件契约Heading 不再单独编写一份 spec而是作为 Text 的引用成员统一登记在 Text 的权威文档与目标清单中任何新的排版/截断行为、语义、样式、目标或公共 API契约不引入新设计。一句话概括Text 拥有根元素与其目标Tooltip 拥有被委托的表层与其目标调用方拥有内容。这一边界在 Text.doc.mjs 的 anatomy 定义中亦有对应Heading被标记为required: false的引用成员Truncation tooltip被描述为Tooltip-owned surface。三、行为与布局契约五条核心不变式FR1–FR5契约以表格形式给出了五条候选不变式candidate invariant并标注了各自的验证依据Basis与审查状态。这五条是理解 Text/Heading 实现的宪法ID不变式内容验证依据FR1Text 渲染一个多态文本元素携带当前text目标当前源码、文档与测试FR2Heading 渲染一个语义h1–h6元素携带当前heading目标Heading 是 Text 的引用成员而非嵌套在 Text 内的元素当前源码、文档、测试与目标历史FR3仅当maxLines为正数、截断 Tooltip 被启用且测量报告内容确实被截断时Text/Heading 才组合 Tooltip否则截断 Tooltip 路径不渲染当前源码、测试与截断历史FR4条件截断路径渲染时Tooltip 拥有层级表层并应用tooltip目标Text/Heading 保留各自根目标不应用也不认领 Tooltip 的目标当前源码与所有者目标元数据FR5Text 在text上反映type、size与解析后的colorHeading 在heading上反映level、color与显式传入的type。显示模式、截断状态、语义元素选择与 Tooltip 开关状态不成为独立的解剖结构或 Text 自有目标当前源码、文档、测试与目标清单3.1 已观察的当前行为Observed current behavior契约明确指出这些观察只描述实现、不确立新意图Text 默认渲染span可通过as渲染其他受支持元素Heading 将level直接映射为h1–h6两个组件都将调用方内容直接渲染进带目标的根元素内部不创建额外带目标的内容包装层两个组件只在maxLines为正数时测量截断。当测量报告溢出且hasTruncateTooltip不为false时以兄弟锚点模式sibling-anchor mode惰性加载 TooltipTooltip 拥有自己的层级生命周期且只对自身渲染的层级应用tooltip。被截断的 Text/Heading 元素仍作为锚点且只保留自身目标Text 与 Heading 不再为截断路径添加原生title属性——组合出的 Tooltip 是唯一的工具提示呈现。这一点在 Text.test.tsx 的 truncated text shows one tooltip, not two 测试中有专门锁定该测试伪造scrollWidth offsetWidth的溢出场景断言渲染结果不带title属性防止浏览器在自有 Tooltip 之上再绘制一个无样式原生提示。3.2 允许的变化Allowed variationAV1 — Text 元素与内容Text 可以使用任意当前受支持的as元素两个成员都可包含调用方内容且不改变目标归属AV2 — 排版level、type、size、color、weight、换行wrapping、装饰decoration及主题/消费者样式均可在既有 API 与目标范围内变化AV3 — 条件 Tooltip内容恰好容纳、截断 Tooltip 被禁用、或未配置截断时委托的 Tooltip 路径不渲染。3.3 代表性状态Representative states契约给出了五类代表性状态及其强制不变式直接对应 AV3 的分支判断状态强制不变式允许变化无截断的 Text一个 Text 元素携带text无截断 Tooltip 路径渲染受支持的元素、内容与排版 props无截断的 Heading一个语义标题携带heading无text目标或截断 Tooltip 路径渲染标题级别、无障碍级别与 type配置截断但内容容纳得下拥有根 Text/Heading 保留无截断 Tooltip 路径渲染行数与可用宽度已截断但 Tooltip 禁用拥有根保持裁剪无截断 Tooltip 路径渲染Text 或 Heading 所有者已截断且 Tooltip 启用并打开拥有根锚定一个由 Tooltip 拥有、携带tooltip的表层放置位置与完整文本内容四、源码级实现印证text 目标与 heading 目标的真实载体契约的五条不变式并非抽象承诺Text.tsx 与 Heading.tsx 的实现逐条与之对应。4.1 Text 的目标映射对应 FR1、FR5在 Text.tsx 中themeProps(text, {type, size, color: resolvedColor})是text目标的挂载点它会同时输出稳定的astryx-text类名与data-type、data-size、data-color数据属性供主题 CSS 选择器精确定位。关键实现细节类型默认值type默认body颜色根据类型表回落例如supporting默认secondary其余默认primarydefaultColorByType自定义类型回落resolveStyleType将主题自定义类型回落到body的 StyleX 基线样式真实视觉来自主题 CSS 的.astryx-text.type覆盖自定义颜色回落resolveStyleColor将内置颜色映射到自身样式、自定义颜色回落到primary基线真实颜色同样来自主题 CSS.astryx-text.color。该函数被显式导出Heading 复用同一套回落逻辑display 的静默覆盖当maxLines 0或hasCapsize为真时display被强制为blockresolvedDisplay。themeProps的text/heading两个稳定类名会被 themingTargets.test.ts 这类全局测试扫描校验例如其中对themeProps(heading, {level, color, ...})调用的静态断言确保目标名与视觉属性清单不被误改。4.2 Heading 的目标映射对应 FR2、FR5Heading.tsx 中level → 标签levelToTag将 1–6 直接映射为h1–h6渲染出一个语义标题元素目标挂载themeProps(heading, {level, color, type, weight})携带astryx-heading类名与相应数据属性type 的显示覆盖当type是内建display-1/2/3时用展示级尺寸样式覆盖level的视觉样式但level仍然决定 HTML 元素保证视觉与语义解耦无障碍级别accessibilityLevel与level不同时输出aria-level使文档大纲与视觉层级解耦对应契约Headings native heading level and optionalaria-level。五、条件截断 TooltipFR3 / FR4 的完整触发链路这是契约中最具工程价值的部分——一个工具提示绝不出现两个。完整链路如下5.1 测量useTruncationuseTruncation.ts 是被 Text 与 Heading 共用的截断检测 hook共享 ResizeObserver 单例通过observeResize复用同一个 ResizeObserver 实例即使是成百上千个表格单元格也只创建一个观察器observeResize在注册时会立刻触发一次回调因此无需单独的初始检查单行检测比较scrollWidth offsetWidth多行检测使用Range.getBoundingClientRect()测量真实内容高度——因为在-webkit-line-clamp生效时浏览器可能报告scrollHeight offsetHeight被钳制的尺寸朴素判断会失效测量失败时如 jsdom 测试环境回落到scrollHeight比较。hook 返回ref附加到文本元素、isTruncated是否溢出与fullText供 Tooltip 显示的完整文本。5.2 组装Text/Heading 中的条件渲染在 Text.tsx 中启用条件为const tooltipEnabled maxLines 0 hasTruncateTooltip ! false truncation.isTruncated;当为真时通过Suspense惰性加载lazyTooltip将其挂到文本元素 reftextRef作为锚点以兄弟节点方式渲染并用truncation.fullText作为内容。hasTruncateTooltip支持布尔值与放置位置字符串传字符串时按above | below | start | end解析放置位置默认above。Heading.tsx 使用完全相同的模式headingRef作为锚点因此 FR3/FR4 对两个组件一致成立。5.3 单提示保证no 原生 title如 3.1 所述契约记录Text 和 Heading 不再为此路径添加原生title这与测试 Text.test.tsx 中的回归测试吻合历史上截断的 Text 会同时渲染自有 Tooltip 并设置同字符串的title导致浏览器绘制第二个无样式提示当前实现由组合出的 Tooltip 独占呈现。六、主题解剖结构text / heading / tooltip 三个目标的归属映射契约的 Theming anatomyanatomy-theming:v1给出了精确的目标映射 JSON{ Text: {target: text}, Heading: {target: heading}, Truncation tooltip: { delegatesTo: {owner: component:Tooltip, target: tooltip} } }解读要点text与heading是 Text 权威文档声明的两个本地目标local targets精确对应当前实现tooltip目标只在条件截断路径到达 Tooltip、且 Tooltip 渲染其层级时才应用它不是 Text 或 Heading 拥有的目标而是通过delegatesTo委托给component:Tooltip没有任何解剖部位需要none处置no anatomy part requires anonedisposition说明三者的归属清晰、无冲突。从文档侧看Text.doc.mjs 的theming.targets同样声明了两个目标astryx-heading视觉属性level/color/type/weight与astryx-text视觉属性type/size/color与契约 JSON 一一对应。七、家族与系统关系谁在治理目标归属契约明确了架构层面的治理链architecture:component-theming-surface 负责解剖结构资格认定、聚合的父/成员目标归属、精确目标映射与委托delegation规则的治理Text 是text与heading两个目标的权威文档与契约所有者Heading 保持为引用成员不另立 specTooltip 保留对其委托表层、交互行为与tooltip目标的拥有权。这一治理结构意味着任何修改 Text 根目标名、把tooltip表层搬进Text/Heading、或恢复原生title重复提示的改动都会违反契约并可能被全局校验与目标测试捕获。八、验证地图不变式如何被测试与脚本锁死契约的 Verification map 将五条不变式与具体验证手段一一对应可作为改代码前先看哪些测试会挂的索引契约验证载体代表性状态失败预期FR1、FR5Text.test.tsx与themingTargets.test.ts默认、多态、自定义 type/color、显式 size移除/重命名/改变 Text 目标能力会使聚焦或全局目标断言失败FR2、FR5Heading.test.tsx、themingTargets.test.ts与目标引入历史level 1–6、display type、自定义 color移除/重命名/改变 Heading 目标能力会使聚焦或全局断言失败FR3、FR4Text/Heading 源码检视、截断测试、Tooltip 目标元数据与修复历史容纳、溢出、禁用、启用将表层或目标移入 Text/Heading、或恢复原生重复提示违反现有证据主题解剖图scripts/check-knowledge.mjs权威解剖、两个本地目标、Tooltip 委托缺失、多余、带前缀、过期、多重分配或非法委托映射会使仓库校验失败其中值得注意的两点check-knowledge.mjs脚本是契约体系的总闸缺失、多余、带前缀、过期、多重分配或非法的委托映射都会让仓库校验失败——这也解释了为何本文前面引用的 anatomy JSON 必须与源码中的themeProps调用保持精确一致聚焦测试锁定目标名Text.test.tsx中断言元素类名包含astryx-text且带有data-type属性并专门断言截断时不带titleHeading.test.tsx则逐级断言h1–h6标签映射。九、向主题作者与消费者的实践提示9.1 为 Text/Heading 扩展自定义 type 与 colorText 与 Heading 支持主题通过TextColorMap与HeadingTypeMap的模块增广module augmentation扩展自定义值。以颜色为例index.ts 中的说明给出了增广写法declare module astryxdesign/core/Text { interface TextColorMap { brand: true; danger: true; } }其运行时行为与契约 FR5 的回落机制配套自定义color渲染时先使用primary基线样式真实颜色由主题 CSS 通过渲染出的data-colorbrand等选择器提供自定义type同理以body为 StyleX 基线、由.astryx-text.type覆盖视觉。astryx theme build检测到主题中 Text/Heading 组件覆盖里出现新的color:*值时会自动生成这些增广。9.2 推荐用法与禁忌来自 Text.doc.mjs推荐guidance: true优先使用语义typebody/label/supporting/large/code而不是手动设置size与weight由主题统一处理细节Heading 视觉级别与文档大纲不一致时设置accessibilityLevel让屏幕阅读器读到正确的层级长内容用maxLines截断悬停自动出现 Tooltip文本不丢失数字列开启hasTabularNumbers让数字在行间垂直对齐。禁忌guidance: false语义类型已匹配时仍叠加size/weight覆盖会与主题打架、换主题时破坏跳过标题级别h1 → h3应保持 h1 → h2 → h3 的顺序直接使用p、h1–h6、span裸标签代替 Text/Heading——后者会自动应用主题 token传variantpropText没有variant语义样式应使用type标题应使用Heading用 Text 充当标题标题请使用Heading并传level1–6。十、决策记录与开放问题契约明确记录Decision log 为空、Open questions 为空。因为这是一份记录既定事实、不引入组件本地设计、API、行为、无障碍或主题决策的契约文档。同时契约的 Content boundary 声明本文件不重复消费侧 props 表格/示例、排版 token 取值、截断测量机制细节、Tooltip 内部实现、实施步骤与系统级主题规则这些内容由各自的拥有方文档承担例如消费侧 API 参考见 Text.doc.mjs 与 Heading.doc.mjs。结语用契约思维审查 Text/Heading 改动Astryx 的Text.spec.md是一个现状契约的范本它用 FR1–FR5 五条不变式、三类允许变化、五种代表性状态与一张验证地图把 Text 与 Heading 的行为边界钉死同时用所有权声明Owns / Does not own把text、heading、tooltip三个主题目标的归属讲清楚。对组件维护者而言它是一份改动红线清单改渲染元素、改目标名、改截断委托路径都可能触发 Text.test.tsx、Heading.test.tsx、themingTargets.test.ts 与 check-knowledge.mjs 的联动校验对主题作者而言它是理解.astryx-text/.astryx-heading类名与data-*属性如何承载自定义 type/color 的入口对消费者而言它回答了截断时为什么只有一个 Tooltip、标题语义与视觉如何解耦、为什么没有variantprop等常见疑问。【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价