Changelog

更新日志

两个包独立发版:@hulianui/ui 提供组件,@hulianui/tokens 提供设计令牌 CSS。记录遵循语义化版本并由 changesets 生成。

当前版本

v0.60.0
npmGitHub Releases
  1. v0.60.0

    @hulianui/ui新功能修复

    AuthPanel 新增 contentAlign?: "start" | "center"#338)。

    面板原本是上块贴顶、下块贴底:分屏认证页右半边的表单按示例是 place-items-center 垂直居中,高一点的视口里左侧标语在 y≈128、表单从 y≈284 起,中间隔着一大段空白。消费方只能用 [&>div:first-child]:flex-1 猜内部 DOM 去撑,那不是契约。contentAlign="center" 时面板改为三行 grid 1fr auto 1fr:brand 仍贴顶、highlights / footer 仍贴底,中部(title / description / children)相对整块面板居中——上下两行等分剩余空间,品牌位与底部区高矮不同也不会把中部推偏(flex-1 + justify-center 会)。默认 start,现有页面 DOM 不变。

    5873b64

    QuestionCard 新增 figureAlt?: (index) => string:题干附图的 alt 由持有 locale 的上层传入(QuestionEditor 预览已接自己的 figureAlt),此前无论语言都落回中文「题目附图 N」,英文站示例页因此残留中文。

    Stat 标题行固定 32px 高,有无 icon 都一样(#339)。

    0.58.0 给角标图标加了 size-8 的底座之后,有 icon 的卡标题行 32px、没 icon 的只有 20px。同一排 KPI 卡只要一半传 icon、一半不传(常见于「右上角留给叠放的 Sparkline」的那两张),数值行起点就差 12px、卡片高矮不齐。现在标题行 min-h-8,「要么全有 icon 要么全没有」这条约束由组件保证,消费方不必记。

    034331f

    Upload 落区静止态改为主色淡边 + 淡底,悬停加深、拖入最重,三档递进。

    此前静止态是 border-border 虚线 + bg-surface:落区多半压在同色卡面上,全部边界只剩 1px 灰虚线,白底上对比度约 1.1:1,消费方实机反馈「边缘很模糊」,且悬停只换背景、与静止几乎无差。现在静止就与卡面差一档,悬停必须与静止不同,拖入态 bg-primary/10 也比原来重一档。

    4e8dccb

    QuestionAnswer 难度标记改用 text-muted-foreground:此前写的 text-muted 自 0.28.0 起是背景色 token,Tailwind 不生成对应文字色规则,标记静默继承正文色。

  2. v0.59.0

    @hulianui/ui新功能修复

    新增独立子路径 @hulianui/ui/math-fieldMathField(MathLive 驱动的可视化公式输入框,值为不带 $ 的 LaTeX,满足 MathFieldLikeProps,可直接注入 MathTextarea / QuestionEditor 的 visualEditor 与 QuestionAnswer 的 mathField;服务端与首帧渲染骨架,mathlive 在客户端动态加载,没装时显示安装提示而不是抛错;virtualKeyboard auto / manual / off、keyboardLayoutsreadOnlyplaceholder;MathLive 的 CSS 变量钉到本库 token)与 createCasComparator()(第 3 档等价判分,返回 Promise<(a, b) => boolean>,直接喂 gradeObjectiveequivalent;解析失败一律 false)。

    mathlive(>=0.110.0)与 @cortex-js/compute-engine(>=0.58.0,mathlive 钉死的依赖)作为 optional peerDependencies 加入:不装它们的消费方不受影响,主包与 @hulianui/ui/math 零 MathLive,@hulianui/ui/math-field 的 initial 实测 12.9KB(mathlive 221KB / compute-engine 294KB 走 import() 懒加载)。字体由消费方 import "mathlive/fonts.css"

    内置 demo「瀚学」新增题库(QuestionEditor + MathField)与练习(QuestionAnswer + 三档即时判分)两页,并补挂了此前缺失的 ToastProvider;新增 docs/consuming-math.md

    50f5f37

    @hulianui/ui/math 新增题目域的类型与纯函数:Question / QuestionType(七型枚举 single / multiple / judge / blank / short_answer / calculation / essay)/ QuestionAnswer,以及 validateQuestiondefaultShapenormalizeOptionsblankCountsplitStemFigurestoWireAnswer / fromWireanswerTextgradeObjective(客观题判分,默认档与消费方服务端逐字同口径,归一与容差 opt-in)。判分与切图各带一份跨语言契约 fixture(grade.contract.json / stem-figures.contract.json),供 Python 侧对账。

    QuestionCardkind(四型)弃用,改用 type(七型);旧值仍映射一个 minor 并在开发期告警。新增 answer / analysis / showAnswer(默认关)展示答案与解析;options 改为 { key, text },旧 { label, text } 仍接受一个 minor。题型标签与答案区文案接入 Locale(新增 question 词条)。

    9f2ed95

    @hulianui/ui/math 新增 MathTextarea:录题用的 LaTeX 输入框。模板插到光标处(选中 x 点分式得到 \frac{x}{} 且光标在分母)、选区一键包成 $…$ / $$…$$、提交前只查 $ 未闭合与 {} 不配对并报行列、KaTeX 解析错误换算回整串位置、实时预览与展示端同一个 FormulavisualEditor 可注入满足 MathFieldLikeProps 的可视化编辑器(阶段 5 的 MathField),给了才出「可视化输入」页签。文案走 Locale(新增 mathTextarea 词条,含内置模板名)。配套纯函数 applyFormulaTemplate / wrapSelectionInMath / isInsideMath / mathSpans / validateFormulaSyntax / textPosition / katexErrorAt 一并导出。

    体积:@hulianui/ui/mathexport * 上界从 95.6KB 升到 154.4KB(Popover / Tabs / 表单控件进入该入口),基线相应上调到 178KB;库 sideEffects:false,只用 Formula 的消费方经 tree-shaking 不受影响。

    257102d

    @hulianui/ui/math 新增 QuestionAnswer:学生端一道题的作答卡。按题型给对的控件(single → RadioGroup、multiple → CheckboxGroup、judge → 题型自带「正确 / 错误」两项且值为 "true" | "false"、blank → 每空一个输入框并标空号,blankCount 缺失按题干 ____ 数再不行按 1);选择题选项缺失明说「暂时没法作答」而不是摆一个空单选组;主观题只读并提示需教师批阅;未知题型按主观题处理并有开发期告警。canSubmit 门禁:多空每个空都填了才可交;onSubmit 给了才出提交按钮,参数是规范形(填空恒为数组,单空压平交给 encodeBlanks)。result 有值即锁定并显示正误、answerText 渲染的正确答案与解析;correctHint / reason / header 三个插槽;blankInput="math" + mathField 注入公式键盘(MathFieldLikeProps 新增可选 disabled)。题干与 QuestionCard 共用新抽出的 QuestionStemBlockresolveFigure 切图 + Formula)。消费方原型里三条曾静默让学生「答不了」的 bug(判断题空单选组 / 多空只有一个输入框 / 对象形 options 被滤空)各有回归测试。文案走 Locale(新增 questionAnswer 词条)。配套导出 canSubmit / answerKind / resolveBlankCount

    答案形状类型 QuestionAnswer 改名为 QuestionAnswerValue(把名字让给组件)。该类型只存在于未发布的 master,不构成破坏性变更。

    体积:@hulianui/ui/mathexport * 上界实测 184.5KB(新进入该入口的只有 Radio / RadioGroup / Input),仍在 208KB 基线内;库 sideEffects:false,只用 Formula / QuestionCard 的消费方经 tree-shaking 不受影响。

    8231de3

    @hulianui/ui/math 新增 QuestionEditor:一道数学题的结构化编辑器。七型切换时 options 与 answer 同时重置(有内容先确认,score 仍是旧默认分才换新默认分);题干输入框只见正文,题图以 ![](key) 块写回题干末尾,resolveFigure 解析、onUploadFigure 给了才出「插入图片」;选项增删上下移后正确答案跟着内容重映射;填空空数随题干 ____ 变化、不一致时提示并一键对齐、一空可加等价写法;计算 / 解答可切分步给分并显示合计;validateQuestion 就地挂 Field.error(默认只显示改过的字段,showAllIssues 提交时全开);复核条 issues / onResolveIssueextra 放消费方私有字段;右侧预览就是 QuestionCard。不带提交按钮。文案走 Locale(新增 questionEditor 词条,含 validateQuestion 机器码文案表)。配套导出 questionFormulaIssues / shapeIsDirty / switchType / optionCaption / stemBody / joinStemFigures

    QuestionCard 新增 resolveFigure:题干里的 ![](key) 先切图再排公式,图渲染在正文之后(编辑器预览与题库列表同一条路径)。

    体积:@hulianui/ui/mathexport * 上界从 154.4KB 升到 180.5KB(Field / Segmented / Checkbox / Switch / Rating / NumberField / Alert / AlertDialog / Image 进入该入口),基线相应上调到 208KB;库 sideEffects:false,只用 Formula / QuestionCard 的消费方经 tree-shaking 不受影响。

    519377c

    Brand 的徽章支持动图 / 视频 mark:GIF、APNG、动图 WebP 直接当 img 传就会动;包一层 <picture> 给开了「减弱动效」的用户一张静态回退,以及静音循环的 <video>、自绘的 <canvas>,现在都按「铺满徽章 + object-cover」处理。此前尺寸规则只认直接子级的 img,动图一加 <picture> 回退就掉出规则、按原图尺寸被裁掉半截。顺带修掉一个被方形素材掩盖的旧缺陷:徽章是 grid 容器,替换元素作为 grid 项时 height:100% 不解析,非方形图片此前只按宽度等比缩放、并没有真的被 object-cover 裁成方形;现在媒体子元素改走 absolute inset-0,任何比例的素材都铺满。

    AdminLayout 文档同步说明:品牌区直接放 Brand,动图 logo 的尺寸与减弱动效回退在 Brand 那边约定,logo 槽只负责摆位。

    381aeda

    修复:CheckboxGroup / RadioGroup 放进 Field 时,组内每个 Checkbox / Radio 的无障碍名都被 Field 标签吞掉(读屏念出 N 个同名项)。现在组内每项由自己的 label 命名,Field 标签命名整个组,description / error 仍到达每一项(内部用 Base UI Field.Item,只在「组内且 Field 内」才包)。不在组内的单个 Checkbox 仍由 Field 标签命名,行为不变。

    26132c0
  3. v0.58.0

    @hulianui/ui新功能修复

    中后台家族视觉升级:把「层级」从线改成高度,并修掉数字跳位。这是默认视觉变更,升级后界面当天就会不一样。

    改动集中在三处 —— 逐屏审计后,中后台真正「素」的就是这三处,其余(Table 表头、Descriptions 键值、NavMenu 分组标题、Skeleton、Empty)本来就已成立,刻意没动:

    • `Stat`:升到 border-hairline + shadow-sm(库内既定判据:有阴影 → 亮色去 border 改 hairline、暗色留 hairline,同 Cardelevated 档);数值 24px → 30px 并加 tracking-tight;label 加 font-medium;角标图标获得中性 bg-muted 底座;数值与趋势行加 tabular-nums。刻意不加 hover 抬升 —— Stat 本身不可点,给了就是骗用户这儿能点。
    • `SearchForm`:容器从纯 1px 平面对齐到 border-hairline + shadow-sm。此前同一个列表页里查询区是平的、下方 ProTable 容器带阴影,两块落在不同平面上,中间那道缝一眼可见。
    • `AdminLayout`:顶栏从 border-b border-border 改为 border-b border-hairline + shadow-sm,用高度而不是硬线与内容区分层。侧栏保持 border-r 不动 —— 竖直投影会往内容区糊一片灰,那不是分层是脏。

    外加两处等宽数字修复(可读性缺陷,不是审美偏好):ProTable 的「共 N 条」与 Pagination 的页码。位数一变,比例字距会让整行左右抽动,Pagination 里还会带偏滑块动画的落点。

    迁移:想保留旧的纯平面观感,对 Stat / SearchFormclassName="shadow-none border-border" 即可。Stat 的数值大了一档且仍是 truncate,窄卡(< 200px)里长数值会更早被截断,请给足宽度或改用 Statistic

    9124187

    修复 MetaBallscolor / cursorBallColor 完全不生效,以及 Sortable 拖拽时抓手光标持续闪烁。

    MetaBalls 之前用 /rgba?\(...\)/ 正则解析探针元素的计算色值,而本库的 oklch() token 经 Lightning CSS 降级后计算值是 lab(...) —— 正则永远不匹配,两个颜色 prop 全部静默落到兜底中性灰,文档站上「自定义配色」那个示例和默认示例渲染出来是同一片灰白球。改成与库内其它 30 余个 WebGL 件一致的离屏 1×1 画布换算(浏览器负责所有色彩空间转换)。顺带两处硬化:探针挂到组件自己的子树里,var() 因此吃就近主题岛的值而不是 :root 的;写错的字面量与未定义的 var(--typo) 现在回兜底色,而不是静默继承祖先文字色把球画成黑的。颜色只活在 shader uniform 里,DOM 查不到,typecheck / guard / 单测全都看不见这个缺陷,补了真实浏览器测试守着。

    Sortable 之前把抓握态写成 active:cursor-grabbing,即「光标取决于指针此刻压着谁」。拖拽期间指针底下的元素每帧都在换(被拖项的 transform 落后一帧、行间空隙归 ul、让位动画中的其他行、消费方行内的 input/button),:active 随之通断,浏览器每个输入事件重算一次光标,表现就是抓手图标持续闪烁。改为拖拽期间用与位置无关的常量:被拖行、其余行、uldocument.body 四处同时钉成 grabbing,结束或卸载还原;键盘拖拽不动 body 光标(没有按下的鼠标)。

    同时给 Sortable 拖拽中的那一项加上 primary 语义色(主色描边 + 主色淡底 + 手柄主色),此前只有阴影和中性 ring,长列表里认不出被抓起的是哪一行。

    9a2cc41
  4. v0.12.0

    @hulianui/tokens新功能

    preset 新增容器内边距兜底 safelist,堵住一种极难归因的接入失效(#336)。

    Card / Dialog / Drawer / DocumentSheet 的内边距是全库唯一一族用 arbitrary value 写的间距
    px-[var(--card-body-px,1.25rem)] 这种),400 个组件里只有这 4 个这么写,因为密度要靠
    CSS 变量随 size 变体下发,同时还要能被 className="p-0" 经 tailwind-merge 盖掉。

    代价是消费方漏配 @source 时,症状不是「组件没样式」:px-4 / gap-2 / rounded-xl
    这些常规类消费方自己代码里也写、Tailwind 照样生成,库组件等于蹭到了;精准消失的只有那族
    唯瑚琏独有的字面量。净效果是「边框圆角颜色全对,唯独容器内边距整片塌掉」,看着像组件 bug,
    于是根因被绕开、业务代码里补一句 className="p-4" 了事。

    preset-core.css 现在用 @source inline() 把这 30 个类钉住,无论消费方扫没扫到组件源码
    都必定生成,实测代价 386 字节。它不是 @source 的替代品:其余 390 个组件的类名照旧
    只能靠蹭,该配还得配。清单与组件源码的一致性由新门禁 pnpm check:container-padding 双向
    机械保证(缺失与陈旧都拦)。

    d311ad3
  5. v0.57.1

    @hulianui/ui修复

    Card 文档补两条坑(#336):根节点自己不带任何内边距、内容必须放进 CardBody(且本库叫
    CardBody 不是 shadcn/ui 的 CardContent);以及整卡内边距都塌了时先怀疑消费方漏配
    @source,判据是构建产物 CSS 里 grep card-body-px

    组件 md 随 npm 包发布、MCP 的 get_component_doc 直读 node_modules 里那一份,所以这类
    文档缺口对 agent 消费方就是运行时缺口。

    d311ad3

还有 86 个更早版本,切到“全部”查看。