Das Block Kit von EmDash ermöglicht es Sandbox-Plugins, ihre Admin-UI als JSON zu beschreiben. Der Host rendert die Blöcke – vom Plugin bereitgestelltes JavaScript wird niemals im Browser ausgeführt.
Wie es funktioniert
- Der Benutzer navigiert zur Admin-Seite eines Plugins.
- Der Admin sendet eine
page_load-Interaktion an die Admin-Route des Plugins. - Das Plugin gibt eine
BlockResponsezurück, die ein Array von Blöcken enthält. - Der Admin rendert die Blöcke mit der
BlockRenderer-Komponente. - Wenn der Benutzer interagiert (einen Button klickt, ein Formular absendet), sendet der Admin die Interaktion zurück an das Plugin.
- Das Plugin gibt neue Blöcke zurück, und der Zyklus wiederholt sich.
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: [] };
},
},
},
});
Der Standard-Format-Route-Handler nimmt zwei Argumente: routeCtx (mit input, request, requestMeta) und ctx (der PluginContext).
Block-Typen
| Type | Description |
|---|---|
header | Große fette Überschrift |
section | Text mit optionalem Accessory-Element |
divider | Horizontale Linie |
fields | Zweispaltige Label/Wert-Tabelle |
table | Datentabelle mit Formatierung, Sortierung, Paginierung |
actions | Horizontale Reihe von Buttons und Steuerelementen |
stats | Dashboard-Metrik-Karten mit Trendindikatoren |
form | Eingabefelder mit bedingter Sichtbarkeit und Absenden |
image | Block-Level-Bild mit Beschriftung |
context | Kleiner gedämpfter Hilfetext |
columns | 2–3 Spalten-Layout mit verschachtelten Blöcken |
empty | Leerzustands-Platzhalter mit Icon, Titel, Beschreibung, optionaler Befehlszeile und Action-Buttons |
accordion | Zusammenklappbarer Abschnitt, der verschachtelte Blöcke umschließt |
Element-Typen
| Type | Description |
|---|---|
button | Action-Button mit optionalem Bestätigungsdialog |
text_input | Einzeilige oder mehrzeilige Texteingabe |
number_input | Numerische Eingabe mit Min/Max |
select | Dropdown-Auswahl |
toggle | Ein/Aus-Schalter |
secret_input | Maskierte Eingabe für API-Schlüssel und Tokens |
Builder-Helfer
Das @emdash-cms/blocks-Paket exportiert Builder-Helfer für saubereren Code:
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" },
}),
],
};
Bedingte Felder
Formularfelder können basierend auf anderen Feldwerten bedingt angezeigt werden:
{
"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 }
}
Das api_key-Feld erscheint nur, wenn auth_enabled eingeschaltet ist. Bedingungen werden clientseitig ohne Round-Trip ausgewertet.
Ausprobieren
Verwenden Sie den Block Playground, um Block-Layouts interaktiv zu erstellen und zu testen.