EmDash 的 Block Kit 允许沙箱插件将其管理 UI 描述为 JSON。宿主渲染这些块——插件提供的 JavaScript 永远不会在浏览器中运行。
工作原理
- 用户导航到插件的管理页面。
- 管理端向插件的管理路由发送
page_load交互。 - 插件返回包含块数组的
BlockResponse。 - 管理端使用
BlockRenderer组件渲染块。 - 当用户交互(点击按钮、提交表单)时,管理端将交互发送回插件。
- 插件返回新的块,循环重复。
import { definePlugin } from "emdash";
import type { PluginContext } from "emdash";
interface BlockInteraction {
type: "page_load" | "block_action" | "form_submit";
page?: string;
action_id?: string;
values?: Record<string, unknown>;
}
export default definePlugin({
routes: {
admin: {
handler: async (routeCtx, ctx: PluginContext) => {
const interaction = routeCtx.input as BlockInteraction;
if (interaction.type === "page_load") {
return {
blocks: [
{ type: "header", text: "My Plugin Settings" },
{
type: "form",
block_id: "settings",
fields: [
{ type: "text_input", action_id: "api_url", label: "API URL" },
{ type: "toggle", action_id: "enabled", label: "Enabled", initial_value: true },
],
submit: { label: "Save", action_id: "save" },
},
],
};
}
if (interaction.type === "form_submit" && interaction.action_id === "save") {
await ctx.kv.set("settings", interaction.values);
return {
blocks: [/* ... updated blocks ... */],
toast: { message: "Settings saved", type: "success" },
};
}
return { blocks: [] };
},
},
},
});
标准格式的路由处理器接受两个参数:routeCtx(包含 input、request、requestMeta)和 ctx(PluginContext)。
块类型
| Type | Description |
|---|---|
header | 大号粗体标题 |
section | 带可选配件元素的文本 |
divider | 水平分隔线 |
fields | 两列标签/值网格 |
table | 带格式化、排序、分页的数据表 |
actions | 水平排列的按钮和控件行 |
stats | 带趋势指标的仪表板指标卡 |
form | 带条件可见性和提交的输入字段 |
image | 带标题的块级图像 |
context | 小号静音帮助文本 |
columns | 带嵌套块的 2-3 列布局 |
empty | 带图标、标题、描述、可选命令行和操作按钮的空状态占位符 |
accordion | 包裹嵌套块的可折叠部分 |
元素类型
| Type | Description |
|---|---|
button | 带可选确认对话框的操作按钮 |
text_input | 单行或多行文本输入 |
number_input | 带最小值/最大值的数字输入 |
select | 下拉选择 |
toggle | 开/关开关 |
secret_input | 用于 API 密钥和令牌的掩码输入 |
构建器助手
@emdash-cms/blocks 包导出构建器助手以实现更简洁的代码:
import { blocks, elements } from "@emdash-cms/blocks";
const { header, form, section, stats } = blocks;
const { textInput, toggle, select, button } = elements;
return {
blocks: [
header("SEO Settings"),
form({
blockId: "settings",
fields: [
textInput("site_title", "Site Title", { initialValue: "My Site" }),
toggle("generate_sitemap", "Generate Sitemap", { initialValue: true }),
select("robots", "Default Robots", [
{ label: "Index, Follow", value: "index,follow" },
{ label: "No Index", value: "noindex,follow" },
]),
],
submit: { label: "Save", actionId: "save" },
}),
],
};
条件字段
表单字段可以根据其他字段值有条件地显示:
{
"type": "toggle",
"action_id": "auth_enabled",
"label": "Enable Authentication"
}
{
"type": "secret_input",
"action_id": "api_key",
"label": "API Key",
"condition": { "field": "auth_enabled", "eq": true }
}
api_key 字段仅在 auth_enabled 打开时显示。条件在客户端评估,无需往返。
试用
使用 Block Playground 交互式地构建和测试块布局。