拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Astryx 图标解析与组件槽架构:如何用 `componentIcons` 让主题按组件角色换图标

Astryx 图标解析与组件槽架构如何用componentIcons让主题按组件角色换图标【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx导读本文基于 Astryx 架构记录 icon-resolution-and-component-slots.md 展开讲解这套开源设计系统中“共享图标名称shared icon name”与“组件语义槽component slot”如何分层协作主题作者可以只改某个组件角色如 Selector 的已选项标记使用的图标而不影响全系统其他使用同一共享图标的地方。读完本文你将掌握IconName共享注册表、componentIcons主题映射、三级解析优先级、undefined/null语义以及扩展包的槽位增强方式并看到对应的源码与测试证据。为什么需要“两个独立的选择”Astryx 的图标体系要解决一个实际问题一个主题作者应该能修改某个组件角色role所用的图标而不必改动该共享图标被引用的每一个地方。为此系统需要两个彼此分离的选择组件角色使用哪个共享图标名称由组件声明主题可覆盖当前主题为这个共享图标名称绘制什么图形由主题决定全局注册。把这两者分开可以避免“每个组件细节都变成一个全局图标名”的膨胀问题。换句话说check这个共享语义图标可以被几十个组件引用但只有当某个组件把“已选中的选项”这个角色映射到success时主题才需要为success单独提供图形。当前基线共享注册表 命名空间扩展键在main分支上Astryx 已经存在一套共享的IconName注册表同时也支持带命名空间的扩展键extension keys。部分组件自有的图形直接使用这些扩展键。该架构记录不否定、不要求迁移这套已发布的行为——已发布的扩展键在单独的兼容性决策改变它们之前持续有效。共享语义名称IconNameIconName是共享语义图标名称的封闭集合例如check、close、chevronDown。在 packages/core/src/Icon/globalIconRegistry.tsx 中可以看到完整的类型定义export type IconName | close | chevronDown | chevronLeft | chevronRight | chevronsLeft | chevronsRight | check | success | error | warning | info | calendar | clock | externalLink | menu | moreHorizontal | search | arrowUp | arrowDown | arrowsUpDown | funnel | eyeSlash | viewColumns | copy | checkDouble | wrench | stop | microphone;这些名称代表的是功能用途而不是某种具体视觉形态——主题负责提供真正的图标组件。命名空间扩展键NamespacedIconName与封闭的IconName并存的是namespace:name形式的扩展键它属于“某个组件或库”而非全系统例如richtext:bold、numberInput:stepperDown。其类型定义为export type NamespacedIconName ${string}:${string};扩展键可以出现在任何内置名称出现的地方包括Icon icon因此命名空间的图形同样可以获得size、color、xstyle等处理。theme 通过registerIcons或defineTheme({icons})按 key 覆盖它方式与覆盖内置名称完全一致。runtime 判断命名空间键的方式是检查字符串是否包含:见isNamespacedKeyglobalIconRegistry.tsx。注册与解析入口registerIcons()模块级注册服务端与客户端环境均可使用建议在应用初始化如 root layout调用一次适用于无法访问 React Context 的 SSR 渲染场景。getIconRegistry()返回注册表快照仅暴露内置IconName键命名空间键被有意排除在类型化快照之外便于工具链推导可用的语义图标名。getIcon()/getExtendedIcon()按名称解析图形后者支持调用方提供 fallback。useIcon()客户端 hook从最近的 Theme 解析语义图标packages/core/src/Icon/useIcon.ts。系统模型一共享图标的三级解析通用解析器general resolver选择图形的顺序是当前激活主题的icons[name]条目进程级的registerIcons()条目defaultIcons中匹配的条目。这正是 globalIconRegistry.tsx 中getIcon的实现逻辑export function getIcon(name: ExtendedIconName, source?: IconRegistrySource): ReactNode { const themeIcons getThemeIconOverrides(source); return ( themeIcons?.[name as IconName] ?? globalRegistry[name] ?? defaultIcons[name as IconName] ); }getThemeIconOverrides接受一个已定义的 theme 对象或 theme 名称字符串此时从getRegisteredTheme(name)读取其icons因此同一解析逻辑同时服务于 React Context 内的激活主题与按名称的 SSR 友好查询。该记录不改变通用解析器接受的共享键与扩展键集合。主题如何被选中active-theme selection归architecture:theme-application所有icons如何归一化与继承归 theme-authoring 所有Icon 组件的公开 source 模式、渲染、尺寸、颜色与无障碍归 Icon 组件契约所有。这套职责划分在源码中同样可见globalIconRegistry.tsx是无use client指令的纯模块级状态模块可从 RSC 导入而 Icon.tsx 是客户端组件同时支持“组件模式”直接传入 SVG 组件与“字符串模式”按语义名从注册表解析。系统模型二类型化的组件槽typed component slots一个组件图标槽component icon slot命名的是某个组件内部一个稳定的用途而不是某个图形。因此槽与图形是两种不同的类型。公共子路径拥有可增强映射公开的astryxdesign/core/Icon子路径拥有一个可被外部包增强的映射类型// Public astryxdesign/core/Icon module export interface ComponentIconSlotMap { selector-selected-option: true; } export type ComponentIconSlotName keyof ComponentIconSlotMap string; export type ComponentIconMap Partial RecordComponentIconSlotName, IconName | null ;这里有一个关键的 TypeScript 约束接口必须声明在消费者要增强的公共模块中。如果接口只声明在实现文件里、再从公共子路径 re-export消费者端的类型不会变宽。runtime 的解析器代码需要从其公共属主处导入这张 map。槽命名约定与外部包增强外部组件包通过增强同一个公共astryxdesign/core/Icon模块来添加自己的槽declare module astryxdesign/core/Icon { interface ComponentIconSlotMap { richtext-bold: true; // component-kebab-semantic-role } }槽名格式为component-kebab-semantic-role其中的 role 描述的是图标存在的原因而不是它当前的外形或方向。例如selector-selected-option表示“Selector 中已选中选项”这一用途与具体画成勾、画成对勾还是别的图形无关。defineTheme({componentIcons})与defineTheme({icons})分离defineTheme({componentIcons})把一个组件槽映射到共享IconName或null它与defineTheme({icons})是两套独立配置defineTheme({ name: brand, componentIcons: { selector-selected-option: success, }, icons: { success: BrandSuccessIcon /, }, });**槽映射slot map**回答“组件角色使用哪个共享含义”**图标映射icon map**回答“该共享含义由哪个图形绘制”。这套目标模型为未来的组件角色增加了一条规则新的语义组件槽统一使用componentIcons。已发布的扩展键仍被支持直到单独的兼容性决策改变它们本记录不为任何现存组件做出裁决。组件槽优先级三级稳定顺序组件解析一个带图标角色时按以下顺序消费者提供的实例 prop当组件暴露该 prop 时最近的激活主题的componentIcons[slot]条目组件声明的 fallbackIconName | null。其中两个关键值的语义undefined表示“使用下一个 fallback”null表示“不渲染图标”被映射到的IconName会继续走共享图标解析流程。共享解析模块在不同环境一致地应用这一顺序getComponentIconName(slot, fallback, source)把槽解析为共享IconName | nullgetComponentIcon(slot, fallback, source)把共享名称解析为具体图形客户端 hook从激活主题解析同一槽与 fallback。组件应使用这些解析器而不是直接读取componentIcons。同时解析器不拥有组件的槽名、fallback 或渲染规则——这些仍属于组件自身。这些函数由 globalIconRegistry.tsx 拥有见记录中的 Owning code 一节目前作为已批准的架构目标随ComponentIconSlotMap模型一并落地。已知偏差NumberInput 步进图标当前有一个明确记录的偏差NumberInput stepper icon现有NumberInput通过通用扩展键而非componentIcons解析其步进图标。Ownercomponent:NumberInput该组件契约建立后归属。退出条件一个单独评审过的迁移在保留已发布调用方与主题覆盖的前提下改用组件槽模型或走明确批准的破坏性变更路径。该记录不选择迁移设计与时间线。这一“已发布行为继续支持”的原则在测试中有直接证据NumberInput.test.tsx 验证了通过registerIcons({ numberInput:stepperDown: ... })注册扩展键后两个步进按钮都渲染该扩展图标而不会回退到通用chevronDown。同时 globalIconRegistry.test.tsx 中也有“为 NumberInput stepper 提供独立默认值”“注册的图标覆盖默认值”“扩展键注册与解析”等一系列测试锁定该行为。边界与不变量INV1–INV10架构记录用十条不变量约束整套模型它们是评审与测试的共同依据不变量含义INV1共享名称与组件角色分离IconName拥有共享语义含义ComponentIconSlotName拥有组件特定用途INV2槽是类型化且由属主声明的每个 Core 槽都在ComponentIconSlotMap中列出外部包增强该 map而不是往 Core 里添加无主字符串INV3槽映射到共享含义componentIcons的值是IconName或null绝不直接指向具体图形INV4null抑制槽componentIcons[slot] null有意不渲染图标缺省映射则使用组件 fallbackINV5每个槽都声明 fallback属主组件声明一个IconName \| null主题无需重复默认值INV6解析顺序稳定实例内容 主题槽映射槽映射先选出共享名称共享注册表再选图形INV7组件槽不扩大共享名称集合新增槽不会加宽IconNameINV8组件行为留在组件内状态变化、变换、放置、尺寸、颜色与无障碍由渲染该槽的组件拥有INV9主题生命周期单一属主本记录只定义componentIcons条目的含义归一化与继承归 theme-authoring激活主题选择归 theme-applicationINV10已有关键共存已发布的槽与扩展键持续支持直到单独的兼容性决策改变它们新的 Core 槽使用ComponentIconSlotMap与componentIcons同时本记录明确不拥有以下内容DefineThemeInput、主题归一化与extends归 theme-authoring-contract.md激活主题选择归 theme-applicationIcon 的公开 source 模式、渲染、视觉解剖、尺寸、颜色与可访问名称 API归 Icon 组件契约消费者经公共组件 props 传入的图标内容图标 paint/state 的 CSS 主题目标有状态指示器渲染器的替换以及组件所选字形的视觉设计。组件本地文档要求架构记录拥有共享规则而每个槽的本地语义由组件属主在组件内记录。具体而言组件的.doc.mjstheming 条目记录槽名、fallbackIconName | null、对该角色的一段简短描述、以及null是否允许隐藏它组件 spec 记录主题作者必须理解的行为状态依赖渲染、放置、无障碍归属、兼容性要求但不复制通用解析算法消费者的 icon prop 仍作为组件 API 文档除非组件同时承诺一个独立的、稳定的主题级角色否则不列入componentIcons槽。作为实例Selector.doc.mjs 中的 “Icon-rendered start icon”“Status icon”“Indicator icon”“Search icon” 等条目以及 Selector.spec.md 中的顺序规则 ORD2startIcon优先于选中项图标共同构成槽的本地文档CLI 与 docsite 工具负责暴露这些属主声明的槽元数据而不会发明新的槽语义。变更耦合改动一个槽要动哪些地方由于槽、fallback、主题映射与组件行为分布在多个属主之间任何变更都有明确的连带范围新增 Core 槽更新公共astryxdesign/core/Icon模块中的ComponentIconSlotMap、属主组件源码、本地文档、解析器测试与组件测试新增包自有槽从该包增强公共astryxdesign/core/Icon模块并补充同样的属主本地文档与测试修改槽 fallback 或优先级属于兼容性变更主题可能省略该槽并依赖旧结果重命名/删除/重新解释已发布槽或扩展键需要显式兼容性计划必要时走获准的破坏性变更路径修改componentIcons的 authoring 形状、归一化或继承更新 theme-authoring 记录及其测试修改构建输出则更新 theme-compilation 记录与 parity 测试修改激活主题选择更新 theme-application 记录及其测试修改 Icon 的公开 source 模式或渲染更新 Icon 组件契约及其测试直接向通用 Icon API 添加组件专属 key需要架构评审这不是新增组件槽的默认方式。验证矩阵架构记录要求每一条不变量都有测试证据表格如下不变量证据失败信号INV1, INV3, INV6注册表解析器测试 一个渲染的组件 fixture组件槽直接解析出具体图形或跳过了共享图标解析INV2, INV5类型测试 组件.doc.mjs元数据检查Core 槽是无类型字符串或缺少属主/fallbackINV4使用componentIcons[slot] null的解析器与组件测试null 映射仍穿透并渲染了图标INV7共享名称类型与注册表快照测试新增组件槽加宽了IconNameINV8代表性 Selector 与组件属主测试主题必须了解组件渲染细节才能替换图形INV9theme-authoring、application、compilation 属主测试本记录发明了第二条归一化或激活主题路径INV10已发布键兼容性 fixtures 新槽负向测试已发布键在未做兼容性决策时失效文档组件元数据与生成的 CLI/docsite fixtures可主题化槽无法连带属主、fallback 与用途被发现小结Astryx 的图标体系用“共享语义名称 组件槽 主题映射”三层模型把**“组件角色用什么语义”与“语义用什么图形”**彻底解耦主题作者通过defineTheme({componentIcons})精确定位某个组件角色通过defineTheme({icons})或registerIcons()覆盖图形而组件通过稳定的解析顺序实例 prop → 主题槽映射 → 组件 fallback收敛结果。已发布的扩展键继续共存新的组件槽则一律走类型化、属主声明的ComponentIconSlotMap路线——这套既有兼容性、又有类型安全的模型正是保证设计系统在“全系统可定制”的同时保持可维护、可发现的关键。【免费下载链接】astryxAn open source design system thats fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门