图标系统

SlexKit 的 icon system 为组件提供统一 icon 解析链:先查自定义注册,再查内置 Phosphor icon,最后可选走 Iconify fallback。

解析链路

当组件收到 icon 字段时,同步解析和异步加载按顺序使用:

  1. getRegisteredIcon(name, state):用户注册的 icon。
  2. 内置 Phosphor icon。
  3. loadIcon(name, state):当前两步没有命中时,按 resolveIconifyIcon()iconifySvgUrl() 走 Iconify async fallback。

同步 getIcon() 只返回已注册或内置 SVG string;不会发起网络请求。需要外部 Iconify fallback 的组件会调用 async loadIcon()

公开 API

注册

registerIcon(name, svg, options?)

注册单个 SVG icon。

import { registerIcon } from "slexkit";

registerIcon("brand-logo", "<svg viewBox=\"0 0 24 24\">...</svg>");

name 会 normalize 成 kebab-case。options 可用于声明 state/weight 等元信息。

registerIcons(icons, options?)

批量注册 icons:

registerIcons({
  "brand-logo": "<svg viewBox=\"0 0 24 24\">...</svg>",
  "brand-mark": "<svg viewBox=\"0 0 24 24\">...</svg>"
});

clearRegisteredIcons()

清空自定义注册表。主要用于测试或宿主热重载。

读取

getIcon(name, state?)

同步获取自定义注册或内置 Phosphor icon。

getRegisteredIcon(name, state?)

只从用户注册表获取 icon。

loadIcon(name, state?)

加载 icon,必要时可触发 async fallback。

名称和 weight 工具

normalizeIconName(name)

把 icon name 归一化为 kebab-case:

normalizeIconName("BookOpenText"); // "book-open-text"
normalizeIconName("book_open_text"); // "book-open-text"

resolveIconWeight(state?)

根据组件 state 解析 Phosphor weight。常见状态包括默认、hover、active、selected、disabled。

resolveIconifyIcon(name, state?)

解析 Iconify icon id 与 state。

iconifySvgUrl(name, state?)

生成 Iconify SVG URL。

iconCacheKey(name, state?)

生成用于缓存的 key,避免不同 state 或 weight 互相覆盖。

内置 Phosphor 图标

SlexKit 内置一组 Phosphor 风格 icons,覆盖常见 UI 动作与状态,例如:

实际可用列表由 icon registry 决定。

图标命名约定

Slex expressions 使用 kebab-case 引用 icons:

{
  layout: {
    "button:save": {
      icon: "floppy-disk",
      label: "Save"
    }
  }
}

避免在 source 中混用 PascalCase、snake_case 和 provider-specific 前缀。自定义 icon 也应注册成语义名称,而不是文件名。

Iconify fallback

Iconify fallback 用于宿主希望按需加载外部 icon 集合的场景。由于它可能产生网络请求或依赖外部资源,secure runtime 中是否可用取决于 host policy 和宿主实现。

生产宿主应优先注册必要 icons 或使用内置 Phosphor set,减少运行时外部依赖。

组件中使用

大多数组件通过 icon 字段使用 icon:

"button:next": {
  icon: "arrow-right",
  label: "Next"
}

Icon-only 按钮仍必须提供可访问 label:

"button:settings": {
  icon: "gear-six",
  iconOnly: true,
  label: "Settings"
}

Icon 是语义辅助,不应替代必要文本。状态色、hover、selected 等视觉状态应由主题 tokens 和组件状态控制,而不是注册多套硬编码颜色的 SVG。