Jixoai UI v0.5:补上加载反馈,自带现成 loader
jixoai-ui v0.5 新增 spin 加载指示组件,名字即参数:59 名 cli-spinners 文字目录与编译期 svg 工件两条解析车道;等待动画全走 CSS 合成器,残影时长与形状可调。插件侧 spinners 特性与图标系统同构,随包附带 94+12 枚验证过的 loader,channel API 支持自定义命名空间。42 个提交,无破坏性变更。
$ git log v0.4.0..v0.5.1 --oneline | wc -l
42
jixoai-ui v0.5(2026-09-13,当前 0.5.1)收录 v0.4.0 以来的 42 个提交:7 feat / 14 fix / 15 docs,其余 6 个为 test、chore 与合并提交。主线是 spin 加载指示组件和插件侧的 spinners 特性(channel API 于 0.5.1 补齐),另有 tree-view 展开图标与 prototype 布局两处小特性。没有带 ! 标记的破坏性变更,升级无迁移动作。
加载指示按名字取
新增 <Spin> 组件。加载指示器以名字为参数,参照 ora 的用法:纯文本输出,没有 [ ] 包裹。spinner 属性按两条车道解析,svg 工件名优先,文字目录名其次。
<!-- svg 车道:编译期生成的工件名 -->
<Spin spinner="blocks-wave" />
<!-- 文字车道:59 名 cli-spinners 目录,帧逐字节取自 cli-spinners@2.9.2;不传时默认 dots -->
<Spin spinner="dots" />
名字是编译期联合类型,拼错在类型检查时报错;越过类型传入未知名时,运行期输出一次带缓存的警告并回落到 dots。不传 spinner 同样渲染 dots,这是 ora 自己的默认。blocks-wave 是另一处的默认:插件空配置 spinners: {} 生成的工件只含这一枚,与组件默认互不相干。
尺寸不引入独立单位。文字通道使用 var(--jx-text),svg 通道使用 var(--jx-icon),两者都是密度标尺变量,与 jixoai.com 的站点排版取同一组值。
无障碍是内建行为:裸姿态输出 role="status" 与 aria-label;包裹姿态给容器加 aria-busy、scrim 与指针拦截;prefers-reduced-motion 下文字通道停在第 0 帧,svg 通道暂停 SMIL 动画。调用方无需配置。
等待动画不靠 JS 计时
文字通道的全部帧一次性渲染进一个单格 grid,white-space: pre 保证每帧保持最宽帧的步进宽度,循环中盒子尺寸不变。JS 只写入动画参数:每个参数组合注入一条 @keyframes,每帧以负 animation-delay 定相到自己的时隙。
结果是帧切换不产生 DOM 变更;动画由合成器执行,主线程阻塞不影响节拍;DevTools 的 Animations 面板可以逐帧检查每个时隙与残影区间。
残影的时长与形状可调
残影参数命名为 linger:上一帧在交接后继续显示 linger 毫秒,线性淡出。淡出形状由 lingerType 决定,三档。
end(默认):完整显示当前时隙,尾段线性淡出start:淡入在交接边界前完成,下一帧接管时已完全显示both:两端渐变
'auto' 为逐名手调值,写在策展脚本里:dots 80/160;dots2 120/0;pipe 120/120;line 160/0;simpleDots 160/160(· 字形)。interval 与 linger 的类型都是 number | 'auto',显式传值的优先级为显式值 > Defaults 槽位 > 目录手调值。
细节:文字引擎修正过的两个动画问题
同百分比 keyframe 停点合并:
10%{opacity:1}10%{opacity:0}中后者覆盖前者,整段退化为线性过渡;离散隐藏需在停点上声明steps(1,start)。实心帧约束:linger ≥ interval 时,入场时长必须封顶在 interval/2,否则不透明度只在单一时间点达到峰值。
svg loader 直接可用
svg 车道执行动画工件自带的 SMIL,多实例、切换名字、动态插入三种场景都能起播,不需要调用方处理浏览器行为。94 枚 magecdn loader 经组件路径逐枚像素验证:83 枚直接通过,11 枚依赖激活处理;15 枚依赖外部上下文的动态 loader 带回执排除在 pack 外,原始工件仍可经自定义来源使用。颜色统一为 currentColor,跟随文字颜色,无需按主题配置。本文中的演示均为实际组件渲染,切换站点主题可直接验证暗色下的表现。
细节:svg 车道的三项组件处理
实例级 id 命名空间:SMIL 的 syncbase 引用(
begin="x.end"一类)跨整个文档解析,同名第二实例会把时间链挂到首实例早已过期的 begin 上;每个实例渲染时改写自己的 id 与引用,时间图自包含。切换时
{#key}整体重建:在常驻 svg 元素内替换 innerHTML,Chrome 的动画激活率为 1/12,整只新插入为 12/12;按数据对象 keyed 重建走永远可行的插入路径,prop 变化不重建节点。动态插入的激活处理:样式表文本重解析 +
setCurrentTime(0),仅在document.readyState === 'complete'时执行,避免水合期间重置运行中的动画。
自定义 loader 与图标共用管线
@jixoai/ui-vite-plugin 新增 spinners 特性(0.4.0 引入,channel API 于 0.5.1 补齐),接口与图标库一致。jixoai({ spinners }) 默认关闭,开启后才执行代码生成;来源支持内联 svg 字符串与 { file } 文件引用;RAW 安全闸门拒绝不可信形状;产物单写者,gen:spins 生成、verify:spins 校验,CI 中手改产物即失败。
该特性不走 svgo。convertShapeToPath 会把 <circle> 重写为 <path>,而 SMIL 的 <animate> 按形状元素类型定位目标,处理后动画目标丢失。loader 的 svg 按 RAW 语义处理,归一化仅限明确清单内的改写(移除 xml 声明、#fff → currentColor)。
自定义扩展对齐图标系统的 channel API(0.5.1)。channel 是一等实例:defineSpinnerChannel({ id, prefix, spinners, peerPackage?, defaultsNote? }),id 文法 /^[a-z][a-z0-9-]*$/,prefix 文法 /^[a-z][a-z0-9]*$/。
校验分两期:工厂期查形状与文法,配置期查唯一性(每个 id 一条、每个 prefix 一个 channel,两个 channel 共用 myco: 命名空间是命名启动错误)。channel 条目以 prefix:name 键并入工件,如 myco:pulse、magecdn:clock、sam:tail-spin;合并顺序为内置清单 → channel(注册序)→ flat 记录,同名全名键后者覆盖(图标覆盖法则)。
全名文法同时接受 flat 形式(/^[a-z0-9][a-z0-9-]*$/,数字开头合法,180-ring 这类站点 URL 名原样保留)与 prefix:name,因此 flat 记录也能以 myco:pulse 键显式覆盖 channel 条目。生成的 SpinName 联合随工件收口,拼错名字是编译错误;组件零改动,带命名空间的名字是联合中的普通字符串。
import { jixoai, defineSpinnerChannel } from '@jixoai/ui-vite-plugin';
import { magecdn } from '@jixoai/ui-vite-plugin/spinners/magecdn';
import { sam } from '@jixoai/ui-vite-plugin/spinners/svg-loaders';
export default defineConfig({
plugins: [
jixoai({
spinners: {
channels: [
// 自有 channel:条目以 myco:… 并入
defineSpinnerChannel({
id: 'myco',
prefix: 'myco',
spinners: {
cadence: '<svg …>…</svg>', // 内联字面量
'wave-loader': { file: './src/loaders/wave.svg' }, // {file} 引用
},
}),
// pack 的 channel 形式:pick 为过滤器(94 枚中选取)
magecdn({ pick: ['clock', 'bars-scale'] }),
// SamHerbert 的 12 枚,sam: 前缀
sam(),
],
spinners: {
'flat-loader': { file: './src/loaders/flat.svg' }, // flat 车道照旧
'myco:cadence': '<svg …>…</svg>', // 同全名覆盖 channel 条目
},
},
}),
],
});
// 重新生成产物:npm run gen:spins
// <Spin spinner="myco:cadence" />、<Spin spinner="magecdn:clock" />、
// <Spin spinner="sam:tail-spin" /> 均进入类型联合
随包提供两个 pack 子入口:@jixoai/ui-vite-plugin/spinners/magecdn(94 枚,逐枚验证)与 @jixoai/ui-vite-plugin/spinners/svg-loaders(SamHerbert 的 12 枚,MIT)。
每个子入口两种接法:spread 车道(magecdnSpinners Record,按名展开、同名按展开顺序覆盖,0.4.0 起不变)与 channel 工厂(magecdn({ pick? }) / sam({ pick? }),pick 为过滤器)。本站文档页的 docs:cadence 即经 channel 车道接入的实渲染示例。

其他变更
图标基线:a0a512e9(2026-09-08)新增 gripVertical 为第 39 枚内置图标时未更新冻结期望,main 遗留 14 个测试失败。本版本重录全部相关期望,插件套件首次全绿(0.5.0 为 489/489,0.5.1 加入 channel 电池后 510/510)。
游乐场控件:新增 PlayTiming(auto/custom 分段控件加门控数字输入);PlaySegmented 补充
bind:通道;PlayNumber 改为事件驱动提交,修复输入值被陈旧重同步回退的问题(输入 32 被回退为 16)。tree-view 展开图标:展开图标列改由调用方持有(caret snippet,含 www 镜像补齐,design-studio #35)。
prototype 布局三件套:prototype-flex / prototype-grid / prototype-waterfall 作为首批 meta.alpha 组件进入 registry,零依赖,任意宿主可用。
CI 与部署:deploy 在组合门禁前先构建 betlang wasm,npm 镜像不再依赖本地产物;ghostty wasm 资源 pin 追平上游重发的资产;standards 门禁不再清点被 gitignore 的本地路由镜像。其余 8 个 fix 均为 spin 组件走查轮次的修复。
升级
无破坏性变更:
npx jixoai-ui@latest add spin
已有工程执行 npx jixoai-ui@latest upgrade。
致谢
文字目录的语料来自 cli-spinners(ora 的 spinner 语料,MIT);svg pack 的上游是 SamHerbert 的 SVG-Loaders(MIT),经 shubhamjain/svg-spinners 聚合、magecdn 收录分发。
链接
Changelog:GitHub Release v0.5.0 · GitHub Release v0.5.1 · compare v0.4.0...v0.5.1
文档与 registry:ui.jixoai.com · spin 文档页 · README
本站系列:Jixoai UI v0.4.0 · Jixoai UI v0.3.0
English version: /blog/2026-09-13-ui-0-5-0/
