InspectorPanel
inspector-panel属性检查器 · 设计工具的字段 schema 驱动属性面板,按 kind 派生控件 · spacing 四联链接锁定 / 主题 token 色板 / MIXED 混合值占位 / commitMode 控制回吐时机 · 内置 layout/color/typography/border/effects 五套预设 schema
用法
基础用法
内置 5 类预设 schema + 主题 token 绑定,改动实时回吐到预览盒。
const [style, setStyle] = useState(initialStyle);
<InspectorPanel
selectedElement="Card / Title"
props={style}
tokenSource={tokens}
onChange={(path, value) => setStyle((prev) => ({ ...prev, [path]: value }))}
/>自定义 schema(不止 CSS)
sections 换成业务属性,面板本身不认识任何具体属性,只按 kind 派生控件。
<InspectorPanel
title="卡片配置"
sections={[
{
id: "meta",
label: "内容",
fields: [
{ key: "headline", label: "标题", kind: "text" },
{ key: "featured", label: "置顶", kind: "toggle" },
],
},
]}
props={values}
onChange={(path, value) => setValues((prev) => ({ ...prev, [path]: value }))}
/>多选混合值 + 松手才回吐
取值不一致的属性传 MIXED 显示「多个值」;commitMode="commit" 让拖动/输入过程不回吐。
- 松手 / 失焦后才会看到回吐
<InspectorPanel
selectedElement="3 个元素"
commitMode="commit"
categories={["typography", "effects"]}
props={{ fontSize: MIXED, fontWeight: MIXED, opacity: MIXED }}
onChange={(path, value) => apply(path, value)}
/>只取部分分类
categories 决定内置预设的取用与顺序,未知 id 忽略。
<InspectorPanel categories={["layout", "border"]} props={style} onChange={onChange} />何时用
设计工具 / 低代码搭建器里与选中元素双向绑定的右侧属性面板:把一组属性描述成 schema,面板按 kind 派生控件、按 key 读值、按 key 回吐。
不是「表单」:提交语义、校验、字段依赖请用 Form / ProForm;单个属性的编辑控件直接用 Slider / ColorPicker / Segmented,不必套面板。内置的 5 类预设只是默认值,业务属性(权重、跳转方式、置顶)同样可以用它,见「自定义 schema」示例。
导入
import { InspectorPanel, MIXED, inspectorSections, layoutFields, spacingSides } from "@hulianui/ui"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| onChange * | (path: string, value: InspectorValue) => void | — | 单 path 变更回吐,path 就是字段声明的 key |
| props | Record\<string, unknown\> | — | 属性值表;先按扁平键命中,未命中再按 a.b.c 点号下钻 |
| selectedElement | string | null | — | 选中元素标识;显式传 null 进空态,不传则不判空 |
| sections | InspectorSection[] | — | 完整分类 schema;传了它 categories 失效 |
| categories | readonly string[] | — | 只取内置预设的这几类,且按传入顺序排列(layout / color / typography / border / effects) |
| tokenSource | readonly InspectorToken[] | — | 色值控件可选的主题 token;形状与文档站 SEMANTIC_GROUPS 的色卡一致 |
| commitMode | "change" | "commit" | "change" | change 拖动/按键即回吐;commit 松手/失焦/回车才回吐 |
| onBatchChange | (changes: InspectorChange[]) => void | — | 一次交互改多个 path 时的批量回吐(见下方 Events) |
| title | ReactNode | 取自 locale | 面板标题;传 null 不渲染标题栏 |
| emptyText | ReactNode | 取自 locale | 空态文案 |
| labels | Partial\<InspectorPanelLabels\> | — | 覆盖取自 locale 的文案(mixed / linkSides / 四边名 等) |
| className | string | — | 面板外层类名 |
字段类型(InspectorField 判别联合,按 kind 收窄):
| kind | 派生控件 | 该 kind 特有字段 |
|---|---|---|
| spacing | 四个数字框 + 链接锁定钮 | sides?(覆盖派生 path)· min / max / step / unit |
| color | 色块(弹出 ColorPicker)+ 文本框 + token 色板 | tokenGroup? |
| length | 滑杆 + 数字框 | min / max / step / unit |
| number | 数字框 | min / max / step / unit |
| enum | ≤4 项 Segmented,更多 Select | options * · display?: "segmented" | "select" |
| toggle | Switch | — |
| text | 文本框 | placeholder? |
公共字段:key (属性路径,同时是回吐的 path)· `label` (可见标签 + 控件 aria-label)· hint? · disabled?。
Events
| 事件 | 类型 | 说明 |
|---|---|---|
| onChange | (path: string, value: InspectorValue) => void | 每个被改动的 path 触发一次。链接锁定的 spacing 会在同一 tick 连发 4 次 |
| onBatchChange | (changes: InspectorChange[]) => void | 传了它,多 path 变更只走它,不再逐条 onChange;单 path 变更始终走 onChange |
回吐值形态由字段自己决定,不看输入形态:unit 有值回吐 "12px" 字符串,无 unit 回吐数字 12;数字框清空回吐 null(= 删除该属性,不是 0);token 色块回吐该 token 的 value,没写 value 就回吐 var(--token)。
无障碍
- 每个控件都带
aria-label(取字段label);spacing 四个框各自是「内边距 上 / 右 / 下 / 左」,不会四个同名。 length的滑杆与数字框是同一属性的两种输入方式,共用同一可访问名(滑杆经aria-labelledby指向可见标签),角色不同所以读屏可区分。- 链接锁定钮用
aria-pressed表达开关态,不是靠颜色。 - token 色块的无障碍名取
tokenSource[].label(缺省回退到token),不是var(--color-x)变量串——读屏念的是「主色」而不是一串变量名。色板下方那行 token 名是给视觉用户的当前值读数,不是无障碍兜底。 - 分类折叠走 Collapsible,
aria-expanded由它维护;键盘可达。 - 混合值不靠灰色暗示:文本/数字类走
placeholder,开关/枚举旁边有可读文字,读屏能听见。
禁忌 / 坑
- `onChange` 会在同一 tick 连发多次(链接锁定的 spacing 是 4 次)。消费方必须用函数式更新
setState((prev) => …),写成setState({ ...style, [path]: value })会让后三次覆盖前三次,表现为「只有最后一边生效」。嫌麻烦就传onBatchChange一次拿全。 commitMode覆盖滑杆、输入框与色块弹出的 ColorPicker 三者。commit模式下取色器松手 / 失焦 / 回车才回吐,拖动中的每帧值只留在面板内部(取色器此时是非受控的,外部props变了才会重新同步)。tokenSource[].token必须带 `color-` 前缀(color-primary而不是primary)。Tailwind v4@theme的真名带前缀,写成裸名色板会画不出颜色也不报错。- 混合值哨兵是
Symbol.for("hulian.inspector.mixed"),不能 JSON 序列化。属性表要过一遍网络/存储时,在边界上把它转成自己的标记再转回来。 - 数字框清空回吐
null不是0。消费方要区分「没设置」和「设成 0」,null应当删除该属性而不是写0。 - 面板不持有业务值:
props不回写,控件就不会动(commit模式的输入草稿与拖动中的滑块除外)。它是受控组件,不是自带状态的编辑器。 - 面板自身的文案(
title/ 空态 /mixed/linkSides/ 四边名 / 两个色值控件名)走 ConfigProvider 的 locale,外层包<ConfigProvider locale={enUS}>即变英文。优先级是labels/title/emptyTextprop > locale > 内置中文兜底。 - 内置预设的字段 `label` 仍是中文,不在 locale 覆盖范围内——它们属于
sections数据而不是面板本身。要整屏英文请自带sections。
相关
Form · ProForm · ColorPicker · ColorSwatchPicker · Slider · Segmented · Collapsible · Flow