news 2026/9/15 16:23:43

Astryx TextArea 组件契约解析:多行输入域的解剖学所有权与主题化表面

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Astryx TextArea 组件契约解析:多行输入域的解剖学所有权与主题化表面

Astryx TextArea 组件契约解析:多行输入域的解剖学所有权与主题化表面

【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx

导读

本文基于 Astryx 设计系统仓库中的packages/core/src/TextArea/TextArea.spec.md组件契约文档,深入解析 TextArea(多行文本输入域)的消费者解剖结构、组件所有权边界,以及各部分与公共主题化 API 之间的映射关系。你将理解 Astryx 如何用「Theming anatomy」机制把"哪个可见部件归谁画"用机器可读的结构固化下来,学会如何依据 FR1–FR4 不变式、delegatesTo/inherits/none四种处置来审计一个组件的主题化表面,并掌握对应源码、文档与测试文件的验证路径。


一、组件契约(Component Contract)是什么

Astryx 的每个核心组件都配有.spec.md知识文档,它记录的不是消费者如何用组件(那属于TextArea.doc.mjs),而是组件在系统中的"解剖学契约":组件渲染了哪些可见部件、每个部件分别由谁拥有其外观语义、这些部件与公共主题化 target 的映射关系,以及维持这些关系的可验证不变式。

TextArea 契约当前处于draft(草案)状态,它记录的是现状事实:TextArea 通过 Field、FieldStatus、Icon、Spinner 等共享组件组合出带标签的多行输入域,并对text-areatext-area-controltext-area-counter三个主题 target 拥有所有权。该草案不改变任何运行时行为或公共 API——这一点在"兼容性与迁移"一节被明确声明:

  • 发布默认保持:yes
  • 兼容性类别:仅增量文档;运行时、DOM、样式、target、别名与公共 API 均不变
  • 受控/非受控行为不变:TextArea 保持受控组件
  • 迁移决策:无

消费者侧的迁移指引属于消费者文档与发布说明的职责,不写入本契约。

二、所有权边界:TextArea 画什么、不画什么

契约通过「Owns / Does not own」清单精确划定职责,这是整个主题化表面正确性的前提。

TextArea 拥有(Owns)

  • 绘制出的输入容器(painted input container)
  • 原生文本域(native text area)
  • 字符计数器(character counter)

三者分别对应现有text-areatext-area-controltext-area-counter主题 target。从实现看,TextArea.tsx 中这三处themeProps()调用(themeProps('text-area', {...})themeProps('text-area-control')themeProps('text-area-counter'))正是契约所述结构的落地。

TextArea 不拥有(Does not own / non-goals)

部件归属
标签、附加/分离式校验消息的呈现component:Fieldcomponent:FieldStatus
工具提示变体的状态表面component:Tooltip
标准起始图标与共享的场内状态图标component:Iconcomponent:Field
加载指示器呈现component:Spinner
调用方提供的自定义起始内容不在 TextArea 公共主题化所有权内
已废弃的textarea别名仅作为兼容性证据,不视为独立解剖部件

源码印证:TextArea 渲染时外层使用Field承载 label/status/width(TextArea.tsx),忙态时在 end slot 中渲染<Spinner size="sm" />与状态图标(TextArea.tsx),起始图标通过renderIconSlot(startIcon, {size: 'sm', color: 'secondary'})渲染(TextArea.tsx),状态图标经useInputStatusIcon取得——该 hook 也被 DateInput、DateRangeInput、DateTimeInput 等输入族成员复用。

三、行为与布局契约(FR1–FR4)

契约以"候选不变式"表格的形式固化了四条必须维持的行为事实:

ID候选不变式依据草案评审状态
FR1当前渲染将原生文本域置于其绘制输入容器内部当前源码、文档与聚焦测试已验证当前行为;无新行为决策
FR2输入容器、原生控件与条件性字符计数器携带三个当前本地 target当前源码与公共文档已验证当前行为;无 target 变更
FR3标签、标准起始图标、加载指示器、状态图标与状态表面继续使用其共享的 Field、Icon、Spinner、FieldStatus、Tooltip 所有者当前源码已验证条件组合边界
FR4占位文本仍属于原生控件;超限字形仍属于字符计数器当前源码、文档与聚焦测试已验证当前分组

这些不变式在 TextArea.test.tsx 中有对应断言:

  • FR1/FR4 的 DOM 结构:renders the counter inside the input container断言 counter 与 textarea 具有相同父级(同为容器内兄弟覆盖层),placeholderrows系列用例验证占位与行数属于原生控件;
  • FR2 的 target 输出:TextArea theme target names用例断言根元素同时携带当前类astryx-text-area与兼容类astryx-textarea(TextArea.test.tsx);disabled theme statereadonly theme state用例验证根 target 以data-disabled/data-readonly反映状态(TextArea.test.tsx);
  • FR3 的组合边界:status prop系列与statusVariant forwarding系列验证附加/分离变体是否渲染场内状态图标、是否预留尾部空间(TextArea.test.tsx)。

此外themingTargets.test.ts(themingTargets.test.ts)作为源码/元数据守门人,核对themeProps()真实调用点与.doc.mjs中声明的theming.targets是否漂移。

允许变化(Allowed variation)

  • value、placeholder、行数(rows)、尺寸(size)、状态(status)、禁用/只读状态与可选插槽仍是现有能力,而非独立的 target 名称;
  • 起始图标内容可以是 Icon 支持的值,也可以是调用方提供的 ReactNode。

代表性状态

状态必需不变式允许变化
默认可编辑标签、输入容器、原生文本域渲染value、placeholder、rows、size
带字符限制字符计数器渲染在输入容器内计数与超限状态
忙态或状态共享 Spinner 或状态呈现渲染在当前位置状态变体与消息存在性

转换与优先级顺序

未引入新的 value、布局、状态或样式优先级规则。

性能与资源

未引入新的性能或资源规则。值得注意的是,源码中字符计数的分段(characterCount)仅在有maxLength时才执行,并通过useMemo缓存(TextArea.tsx),这印证了"不引入新规则"且对无计数器场景零额外开销的实现选择。

四、无障碍契约

该草案不改变或扩展 TextArea 现有的标签、描述、状态、计数器、忙态、禁用/只读状态或播报行为。但实现细节值得一提:当disabledMessage存在时,textarea 以aria-disabled+readOnly替代原生disabled,保持键盘可聚焦以便发现禁用原因(TextArea.tsx);字符计数区段(under/near/over)只在跨区时通过useAnnounce播报,超限用 assertive、接近上限用 polite(TextArea.tsx)。测试announces remaining characters politelyannounces over-limit assertively直接验证了这一行为(TextArea.test.tsx)。

五、设计关系与 Theming Anatomy 映射

解剖学-需求对照

解剖部件或状态设计要求呈现权威层级角色组件契约
输入容器呈现当前绘制字段边界当前源码与公共文档支撑FR1, FR2
文本域呈现并编辑当前多行值当前源码与公共文档突出FR1, FR2
字符计数器呈现当前与最大字符数当前源码与公共文档支撑FR2, FR4
共享字段反馈呈现当前标签、标准图标、状态与加载内容共享组件源码支撑FR3

Theming anatomy 机器可读映射(原文档核心数据)

这是契约文档的核心资产——每个消费者可见解剖部件到主题化处置的精确映射。必须原样保留

{ "Label": { "delegatesTo": {"owner": "component:Field", "target": "field-label"} }, "Description": { "none": { "reason": "unsettled: No current public target reaches the stable Description; future exposure still needs an owner decision" } }, "Input container": {"target": "text-area"}, "Text area": {"target": "text-area-control"}, "Placeholder": {"inherits": "text-area-control"}, "Start icon": { "delegatesTo": {"owner": "component:Icon", "target": "icon"} }, "Custom start content": { "none": { "reason": "intentional: Custom start content is caller-provided ReactNode content outside TextArea's public theming ownership" } }, "Spinner": { "delegatesTo": {"owner": "component:Spinner", "target": "spinner"} }, "Status icon": { "delegatesTo": { "owner": "component:Field", "target": "input-status-icon" } }, "Character counter": {"target": "text-area-counter"}, "Field status message": { "delegatesTo": { "owner": "component:FieldStatus", "target": "field-status" } }, "Tooltip status message": { "delegatesTo": {"owner": "component:Tooltip", "target": "tooltip"} } }

如何读懂这张映射

依据 component-theming-surface.md 定义的系统模型,每条解剖条目对应四种处置之一:

  1. target—— 本组件为可见部件承诺一个稳定公共 target,如text-areatext-area-controltext-area-counter
  2. inherits—— 部件无独立 target,继承父 target 的样式,如 Placeholder 继承text-area-control
  3. delegatesTo—— 由其他 Astryx 组件拥有该部件及其 target,如 Label 委托给Field/field-label、Status icon 委托给Field/input-status-icon、Field status message 委托给FieldStatus/field-status、Tooltip status message 委托给Tooltip/tooltip
  4. none+ 分类原因—— 当前无公共 target 可达该部件,原因必须精确分类:intentional:(刻意边界)、reachability-gap:(应达未达)、unsettled:(待决策)。

TextArea 映射中的两处none正是分类用法的范例:Custom start content是调用方自带的 ReactNode,属于刻意排除(intentional);Description虽然语义稳定但尚无公共 target 可达,属待决策(unsettled)。契约明确指出:已废弃的textarea别名仅是兼容性证据,不进入映射——它与text-area的迁移关系见 component-theming-surface.md 的 0.7.0 废弃表面移除窗口表格(textarea → text-area)。

对应的.doc.mjs元数据(TextArea.doc.mjs)声明了四个 target:astryx-text-area(visualProps: size/status,states: disabled/readonly)、astryx-text-area-controlastryx-text-area-counter,以及保留的兼容类astryx-textareadeprecatedFor: 'text-area');同时声明了私有变量--_textarea-inline-padding(默认var(--spacing-2)private: true)及其 derived 展开(paddingInline替换)。实现中该私有变量用于让文本内边距、起始图标、状态/Spinner 与字符计数器对齐(TextArea.tsx)。

六、家族与系统关系

  • architecture:component-theming-surface拥有解剖学资质、事实性none处置、保持组合的所有权与别名排除规则;
  • Field、FieldStatus、Icon、Spinner、Tooltip 在被 TextArea 组合时,保留各自现有的公共 target 契约。

TextArea 是family:input-fields(输入字段家族)的成员之一(input-fields.md)。家族契约记录:TextArea 采用 Field、FormLayout、size、width、isLoadingchangeAction、status 与 disabled reason,并支持块轴增长;不兼容 InputGroup(input-fields.md)。家族不变式对 TextArea 的具体约束包括:

  • FR1:普通状态切换(占位变值、忙态/状态出现)不得改变外部可用行内尺寸;
  • FR2:已渲染的端部控件(Spinner、状态控件)必须拥有不重叠的空间,且不存在的控件不得留下陈旧预留;
  • FR6changeAction路径必须先onChange、乐观呈现受控值、在 transition 中执行 Action 并共享同一忙态呈现——TextArea 中useOptimistic(value)+startTransition正是此规则的实现(TextArea.tsx)。

七、验证映射:契约如何被守住

契约的verified_by元数据声明了三类验证锚点:TextArea.test.tsx、themingTargets.test.ts、check-knowledge.mjs。逐条不变式的验证策略:

契约验证方式代表性状态变异或失败预期
FR1, FR4TextArea.test.tsx结构与计数器套件默认、占位、计数、超限移除或重组稳定部件会破坏现有 role、content 或 DOM 断言
FR2TextArea.test.tsx根 target 套件与themingTargets.test.ts当前与废弃根名;当前 target移除根兼容类会失败聚焦覆盖;源码/文档漂移会触发 target 守门人
FR3TextArea.test.tsxuseInputStatusIcon.test.tsxrenderIconSlot源码检查标准/自定义起始内容;Spinner;附加/分离/工具提示状态移除或改道组合内容会破坏现有 icon、spinner、tooltip、message 或关联断言
Theming anatomy 映射scripts/check-knowledge.mjs规范解剖与当前本地 target规范键漂移、非法处置或 target 拼写、别名支撑的本地声明、未认领的当前本地 target 均验证失败

契约同时诚实记录了验证空白:TextArea 聚焦套件钉住了当前与废弃根类,但未单独断言text-area-controltext-area-counter的精确类放置——该覆盖由源码/元数据 target 守门人承担;且当前仓库没有检查会解析delegatesTo的 owner/target 配对,本草案中的配对是手工核验的,语义委托漂移仍是验证空白

八、决策日志、开放问题与内容边界

  • 决策日志:无。本草案仅记录现状事实,未引入组件本地设计或 API 决策。
  • 开放问题:无。
  • 内容边界:本文件不重复消费者 prop 表、示例、实现步骤或共享组件契约,而是链接到其所有者——prop 与 usage 详见 TextArea.doc.mjs,实现详见 TextArea.tsx,行为验证详见 TextArea.test.tsx。

结语

TextArea 组件契约是 Astryx"可主题化表面"治理的最小但完整范例:它用一张机器可读的解剖映射,把"输入容器归本组件、标签归 Field、消息归 FieldStatus、占位继承控件"这类所有权事实固化为可校验的规范,再以 FR1–FR4 不变式、themingTargets.test.tscheck-knowledge.mjs形成源码-元数据-测试的三方守门。理解这份契约,等于掌握了阅读 Astryx 任意核心组件 spec 的方法:先读解剖清单,再看处置映射,最后对照验证映射确认每一项都有可执行证据——这也是为组件编写新主题或扩展目标前必须完成的前置审计。

【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 16:23:40

SmartDNS 本地DNS落地实践:按家庭角色拆分上游

SmartDNS 本地DNS落地实践&#xff1a;按家庭角色拆分上游 【免费下载链接】smartdns A local DNS server to obtain the fastest website IP for the best Internet experience, support DoT, DoH, DoQ. 一个本地DNS服务器&#xff0c;获取最快的网站IP&#xff0c;获得最佳上…

作者头像 李华
网站建设 2026/9/15 16:23:39

ActiveX调用MATLAB在CVI和LabVIEW中的混合编程实践

简介&#xff1a;面向需要在Matlab与LabWindows/CVI、LabVIEW之间实现双向数据交互的工程师与科研人员&#xff0c;资源围绕ActiveX技术提供了可运行的完整工程示例&#xff0c;帮助解决跨软件调用测试程序、传递采集数据等常见集成需求。压缩包共21个文件&#xff0c;以C语言源…

作者头像 李华
网站建设 2026/9/15 16:22:54

用Python和Pygame实现围棋小游戏:规则建模、提子判定与AI对战

简介&#xff1a;用 Python 与 Pygame 编写的围棋小游戏完整源码项目&#xff0c;适合想通过实战入门游戏开发的 Python 初学者、Pygame 学习者&#xff0c;以及想了解围棋规则与简单 AI 算法的开发者。整体代码量精简、模块划分清楚&#xff0c;可直接运行体验&#xff0c;也适…

作者头像 李华
网站建设 2026/9/15 16:20:18

Haystack 集成指南:使用 YouComWebSearch 组件接入 You.com 搜索 API

Haystack 集成指南&#xff1a;使用 YouComWebSearch 组件接入 You.com 搜索 API 【免费下载链接】haystack Open-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows wit…

作者头像 李华