@axhub/genie-editor-client
v0.0.1
Published
`@axhub/genie-editor-client` 是给 Genie Editor 宿主侧使用的一层轻量客户端集成工具包。
Downloads
140
Readme
@axhub/genie-editor-client
@axhub/genie-editor-client 是给 Genie Editor 宿主侧使用的一层轻量客户端集成工具包。
当前首批能力聚焦在 React tweak helper,但它的定位不是只服务 React hook,而是承接页面宿主与 axhub-genie-editor 对接时需要的客户端侧工具。
对外使用口径
如果你是这个 npm 包的使用方,对外只需要关注:
- 安装
@axhub/genie-editor-client - 所有 import 都从
@axhub/genie-editor-client读取 - 把 schema / values / adapter 注册到全局 tweak protocol
axhub-genie-editor 是当前仓库里的 editor 运行时消费方,用来读取你注册到页面全局的 tweak protocol。它不是这个 README 面向的安装入口,也不是你在宿主项目里需要直接依赖的包。
它不定义业务字段,也不替宿主决定哪些属性可编辑,只做三件事:
- 提供一个
useSyncExternalStore风格的 tweak store - 把 React 侧状态包装成 Genie Editor 可识别的 tweak adapter
- 帮宿主把元素级 tweak 能力注册到全局协议中
协议本身仍然是框架无关的,未来 Vue / jQuery / 原生 DOM 宿主也可以直接实现同一套协议。
安装
import {
createGenieEditorReactTweakStore,
createGenieEditorReactTweakAdapter,
useGenieEditorReactTweakStore,
useRegisterGenieEditorTweak,
} from '@axhub/genie-editor-client';如果你的宿主需要直接访问协议类型,也可以直接从同一个包导入:
import type {
GenieEditorTweakSchema,
GenieEditorTweakValues,
} from '@axhub/genie-editor-client';如果你的宿主需要在“字段结构变了但没有重建 adapter”时手动刷新 editor,也可以导入:
import { notifyGlobalGenieEditorTweakProtocol } from '@axhub/genie-editor-client';何时使用
适合以下场景:
- 宿主本身是 React 页面
- 元素的 tweak 值已经存在于 React state / props / store 中
- 希望让 Genie Editor 的
"调整"tab 直接消费这些值
不适合以下场景:
- 想把页面级全局配置直接映射为 tweak
- 想让 editor 内置一套固定可编辑字段
- 想把 tweak 设计成只读静态 schema 且没有 element 绑定关系
核心概念
1. store
createGenieEditorReactTweakStore(initialValues) 创建一个最小外部 store:
const tweakStore = createGenieEditorReactTweakStore({
title: '旧标题',
visible: true,
});它提供:
getSnapshot()subscribe(listener)set(nextValues)update(patch)
如果组件里想直接消费这个 store,可以用:
const values = useGenieEditorReactTweakStore(tweakStore);2. schema
schema 完全由宿主决定。编辑器只识别通用字段描述,不提供业务字段白名单。
const tweakSchema = {
title: '卡片配置',
description: '这些配置绑定到当前卡片实例。',
fields: [
{
key: 'title',
label: '标题',
type: 'text',
},
{
key: 'visible',
label: '显示',
type: 'switch',
},
],
} satisfies GenieEditorTweakSchema;当前支持的 type:
textnumbersliderselectcardcheckboxswitchcolor
其中 card 适合表达纵向单选卡片。每个选项使用:
label作为卡片标题description作为卡片描述value作为实际回写值
3. 注册到全局 tweak protocol
最简单的 React 用法是直接使用 useRegisterGenieEditorTweak(...):
import React from 'react';
import {
createGenieEditorReactTweakStore,
useRegisterGenieEditorTweak,
} from '@axhub/genie-editor-client';
import type { GenieEditorTweakSchema } from '@axhub/genie-editor-client';
const tweakSchema: GenieEditorTweakSchema = {
title: '卡片配置',
fields: [
{ key: 'title', label: '标题', type: 'text' },
{ key: 'visible', label: '显示', type: 'switch' },
],
};
export function SalesCard() {
const rootRef = React.useRef<HTMLDivElement | null>(null);
const tweakStore = React.useMemo(
() =>
createGenieEditorReactTweakStore({
title: '本周销售额',
visible: true,
}),
[],
);
useRegisterGenieEditorTweak({
elementRef: rootRef,
schema: tweakSchema,
store: tweakStore,
onUpdate: async (patch) => {
tweakStore.update(patch);
},
});
return <div ref={rootRef}>...</div>;
}行为说明:
- 只要
elementRef.current和schema都可用,hook 就会注册 adapter - 组件卸载时会自动注销
- 注册和注销都会自动通知 Genie Editor 刷新全局 tweak 列表
- store 通过
subscribe推送值变化时,Genie Editor 会自动回读最新 values - editor 选中该元素后,如果
schema.fields.length > 0,会显示"调整"tab "调整"tab 会排在"样式"前面
这意味着大多数 React 场景不需要你手动调用刷新函数:
- 组件挂载 / 卸载
- HMR 导致 hook 重新注册
store.set(...)/store.update(...)
这些都会自动反映到 Genie Editor。
手动创建 adapter
如果你不想用 hook,也可以手动创建 adapter:
import { ensureGlobalGenieEditorTweakProtocol } from '@axhub/genie-editor-client';
import {
createGenieEditorReactTweakAdapter,
createGenieEditorReactTweakStore,
} from '@axhub/genie-editor-client';
const element = document.querySelector('#sales-card') as Element;
const store = createGenieEditorReactTweakStore({ title: '销售额' });
const unregister = ensureGlobalGenieEditorTweakProtocol().register(
createGenieEditorReactTweakAdapter({
element,
schema: {
fields: [{ key: 'title', label: '标题', type: 'text' }],
},
store,
onUpdate: async (patch) => {
store.update(patch);
},
}),
);什么时候需要显式刷新
如果你是“原地修改” schema,而不是让 hook / adapter 重新注册,Genie Editor 不一定知道字段结构已经变了。这类场景可以显式通知一次:
import { notifyGlobalGenieEditorTweakProtocol } from '@axhub/genie-editor-client';
mutableSchema.fields = [
{ key: 'title', label: '标题', type: 'text' },
{ key: 'theme', label: '主题色', type: 'color' },
];
notifyGlobalGenieEditorTweakProtocol();更适合显式刷新的场景:
- 你在原对象上 push / splice
schema.fields - 你改变了 adapter 的匹配逻辑,但没有重新注册
- 你把多个外部数据源合并成一个 schema,变化发生在 React 之外
如果你已经让 useRegisterGenieEditorTweak(...) 因为依赖变化而重新注册 adapter,通常就不需要再手动刷新。
与 editor 的关系
客户端包只负责注册和协议桥接。对外使用时,你只需要依赖 @axhub/genie-editor-client;如果页面里存在 Genie Editor 运行时,它会去消费这些全局注册的数据。
当前仓库里的 editor 消费方式是:
- editor 通过
window.__AXHUB_GENIE_EDITOR_TWEAK_PROTOCOL__读取 adapter - editor 在 property panel 中读取
getSchema(element)/getValues(element) - editor 在用户修改时调用
update(element, patch) - editor 在 adapter 注册、注销、订阅更新、显式
notify()后刷新 tweak 视图 - editor 会把 tweak 改动写入变更摘要,并在 prompt 中排到样式前面
约束
- tweak 是元素级绑定,不是页面级全局配置
- schema / values / update 必须由宿主控制
- editor 不保证通用“恢复默认值”语义,当前回退仍然依赖宿主 adapter 接受回写 patch
- 客户端包里的 React helper 只是便捷层,不会改变底层协议
