Editor-API
Der Haupteinstiegspunkt ist die init()-Funktion aus @templatical/editor.
init(config)
Erstellt und hängt den Editor in ein Container-Element ein. Gibt ein Promise zurück, das aufgelöst wird, sobald der Editor bereit ist.
import { init } from "@templatical/editor";
import "@templatical/editor/style.css";
const editor = await init({
container: "#editor",
content: savedTemplate,
onChange(content) {
// Automatisch speichern oder Zustand aktualisieren
},
});Rückgabewert: TemplaticalEditor
unmount()
Zerstört die Editor-Instanz und räumt Event-Listener auf.
import { unmount } from "@templatical/editor";
unmount();TemplaticalEditorConfig
| Property | Type | Required | Beschreibung |
|---|---|---|---|
container | string | HTMLElement | Yes | CSS-Selektor oder DOM-Element, in das der Editor eingehängt wird. Im Standardmodus (Shadow DOM) muss es ein Element sein, das einen Shadow Root aufnehmen kann — <div> wird empfohlen. Siehe Anforderungen an das Container-Element unten |
shadowDom | boolean | No | Mountet innerhalb eines Shadow DOM zur CSS-Isolation von der Host-Seite. Standardwert true. Auf false setzen, um stattdessen im Light DOM zu mounten (z. B. für document.querySelector-Zugriff auf Editor-Interna oder Firefox-<101 / Safari-<16.4-Unterstützung). Siehe Shadow DOM für Kompromisse |
content | TemplateContent | No | Anfänglicher Template-Inhalt. Standardmäßig ein leeres Template |
onChange | (content: TemplateContent) => void | No | Wird aufgerufen, wenn sich der Template-Inhalt ändert (entprellt) |
onSave | (content: TemplateContent) => void | No | Wird aufgerufen, wenn der Benutzer eine Speicheraktion auslöst |
onError | (error: Error) => void | No | Wird aufgerufen, wenn ein Fehler auftritt |
onRequestMedia | (context?: MediaRequestContext) => Promise<MediaResult | null> | No | Wird aufgerufen, wenn der Benutzer ein Bild auswählen möchte. Gibt { url, alt? } oder null zurück |
mergeTags | MergeTagsConfig | No | Merge-Tag-Konfiguration. Siehe Merge-Tags |
displayConditions | DisplayConditionsConfig | No | Konfiguration für Anzeigebedingungen. Siehe Anzeigebedingungen |
customBlocks | CustomBlockDefinition[] | No | Definitionen für benutzerdefinierte Blocktypen. Siehe Benutzerdefinierte Blöcke |
paletteBlocks | string[] | No | Allowlist + Reihenfolge für die Block-Palette. Nur die aufgeführten Typen erscheinen, in dieser Reihenfolge; nicht aufgeführte integrierte Blöcke werden ausgeblendet. Integrierte Blöcke über ihren reinen Typ ('image'), benutzerdefinierte über den custom:-präfixierten Typ ('custom:qrcode'). Siehe Block-Palette anpassen |
blockDefaults | BlockDefaults | No | Standard-Property-Überschreibungen für neue Blöcke. Siehe Standardwerte |
templateDefaults | TemplateDefaults | No | Standardeinstellungen für leere Templates. Siehe Standardwerte |
fonts | FontsConfig | No | Schriftart-Konfiguration. Siehe Benutzerdefinierte Schriftarten |
theme | ThemeOverrides | No | Überschreibungen für Farb-Tokens. Unterstützt einen dark-Schlüssel für Dark-Mode-Überschreibungen. Siehe Theming |
uiTheme | 'light' | 'dark' | 'auto' | No | UI-Farbschema. 'auto' folgt den Systemeinstellungen. Standardwert ist 'auto' |
locale | string | No | Locale-Code (z. B. 'en', 'de'). Standardwert ist 'en' |
branding | boolean | No | Zeigt den "Powered by Templatical"-Footer. Standardwert true. Auf false setzen, um ihn auszublenden |
smallScreenNotice | boolean | No | Zeigt auf Viewports schmaler als ~768px einen Hinweis „Bitte größeren Bildschirm verwenden" anstelle des Editors. Standardwert true. Der Drag-and-Drop-Editor ist ein Desktop-Werkzeug und lässt sich auf einem Smartphone nicht sinnvoll darstellen. Auf false setzen, um den Editor bei jeder Breite zu rendern, wenn Sie kleine Bildschirme selbst behandeln |
Anforderungen an das Container-Element
Das Standard-Mount (Shadow DOM) ruft attachShadow() auf Ihrem Container auf, und die HTML-Spezifikation erlaubt Shadow Roots nur für eine feste Menge von Elementen. Verwenden Sie eines davon:
<article>, <aside>, <blockquote>, <body>, <div> (empfohlen), <footer>, <h1>–<h6>, <header>, <main>, <nav>, <p>, <section>, <span> sowie jedes von Ihnen definierte Custom Element.
Nicht erlaubt: <table>, <tr>, <td>, <form>, <input>, <button>, <select>, Listenelemente (<ul>, <ol>, <li>), <iframe>, ersetzte Elemente (<img>, <video> usw.). Die Übergabe eines dieser Elemente wirft eine DOMException aus attachShadow().
Wenn Ihre Integration ein nicht unterstütztes Element verwenden muss (z. B. Mount in eine <form>-Zelle eines CMS-Layouts), übergeben Sie shadowDom: false — das Light-DOM-Mount akzeptiert jedes Element. Der Kompromiss ist die Host-CSS-Isolation, auf die Sie verzichten.
Block-Palette anpassen
Standardmäßig listet die Seitenleisten-Palette jeden integrierten Blocktyp auf. Übergeben Sie paletteBlocks, um die Palette auf eine bestimmte Menge zu beschränken und ihre Reihenfolge zu steuern — nützlich, um nicht verwendete Blocktypen (video, table, …) auszublenden oder einen häufig genutzten benutzerdefinierten Block über die integrierten Blöcke zu stellen.
const editor = await init({
container: "#editor",
customBlocks: [qrCodeDefinition],
paletteBlocks: [
"section",
"title",
"paragraph",
"image",
"custom:qrcode", // ein benutzerdefinierter Block, zwischen integrierten Blöcken
"button",
],
});- Strikte Allowlist + Reihenfolge. Es werden nur die aufgeführten Typen angezeigt, in genau dieser Reihenfolge. Jeder nicht aufgeführte integrierte Block (hier
divider,video,social,menu,table,spacer,html) wird aus der Palette ausgeblendet. - Integrierte Blöcke über ihren reinen Typ (
"section","image", …) und benutzerdefinierte Blöcke über ihrencustom:-präfixierten Typ ("custom:qrcode") referenzieren, sodass beide frei vermischt werden können. - Unbekannte Einträge werden übersprungen. Ein Tippfehler, ein nicht registrierter benutzerdefinierter Block oder
countdownaußerhalb eines Cloud-Plans wird mit einer Warnung in der Konsole protokolliert und nicht in die Palette aufgenommen. - Das Filtern der Palette wirkt sich nie auf das Rendering aus. Das Ausblenden eines Blocktyps entfernt ihn nur aus der Palette — vorhandener Inhalt, der diesen Typ bereits verwendet, wird weiterhin korrekt gerendert.
paletteBlockssteuert, was Benutzer einfügen können, nicht, was der Editor anzeigen kann.
Lassen Sie paletteBlocks weg (oder übergeben Sie ein leeres Array), um die vollständige Standard-Palette anzuzeigen.
TemplaticalEditor
Das von init() zurückgegebene Objekt.
getContent()
Gibt den aktuellen Template-Inhalt als TemplateContent-Objekt zurück.
const content = editor.getContent();
// { blocks: [...], settings: { width: 600, ... } }setContent(content)
Ersetzt den Editor-Inhalt.
import { createDefaultTemplateContent } from "@templatical/types";
editor.setContent(createDefaultTemplateContent());setTheme(theme)
Wechselt das UI-Farbschema zur Laufzeit, ohne den Editor neu zu initialisieren.
editor.setTheme("dark");
editor.setTheme("light");
editor.setTheme("auto"); // folgt der SystemeinstellungParameter: theme: 'light' | 'dark' | 'auto'
unmount()
Zerstört diese Editor-Instanz.
toMjml()
Rendert den aktuellen Inhalt in MJML-Markup. Gibt ein Promise<string> zurück, da das Auflösen benutzerdefinierter Blöcke asynchrone Arbeit erfordern kann (der Liquid-Renderer des Editors wird bei Bedarf geladen).
const mjml = await editor.toMjml();Wirft einen klaren Fehler, wenn @templatical/renderer nicht installiert ist. Der Renderer ist eine optionale Peer-Abhängigkeit – installieren Sie ihn nur, wenn Sie MJML-Export aus dem Browser benötigen. Siehe Installation für Details.
Um MJML zu HTML zu kompilieren, verwenden Sie eine beliebige MJML-Bibliothek (z. B. mjml für Node.js).
Cloud-Editor
Der Cloud-Editor stellt toMjml() nicht zur Verfügung – das Cloud-Backend übernimmt die MJML-Konvertierung serverseitig mit zusätzlicher Verarbeitung (signierte Bild-URLs, Asset-Umschreibung). Verwenden Sie den OSS-Editor (init, nicht initCloud), wenn Sie clientseitigen MJML-Export wünschen.
renderCustomBlock(block)
Rendert einen einzelnen benutzerdefinierten Block in seine HTML-Darstellung. Nützlich für Headless-Aufrufer, die @templatical/renderers renderCustomBlock-Option von außerhalb der Editor-Instanz steuern möchten – etwa beim direkten Aufruf des Renderers mit eigener Konfiguration.
const html = await editor.renderCustomBlock(customBlock);Core-Composables
Für fortgeschrittene Anwendungsfälle können Sie die Composables aus @templatical/core direkt verwenden.
useEditor(options)
Das Kern-Composable, das den gesamten Editor-Zustand verwaltet: den Block-Baum, Template-Einstellungen, Block-Auswahl, Viewport-Modus sowie alle Mutationsmethoden. Dies ist das, was init() intern verwendet. Verwenden Sie es direkt, wenn Sie eine vollständig benutzerdefinierte Editor-Oberfläche auf der Templatical-State-Engine aufbauen.
import { useEditor } from "@templatical/core";
const editor = useEditor({ content: templateContent });
editor.selectBlock(blockId);
editor.updateBlock(blockId, { content: "New text" });
editor.setViewport("mobile");useHistory(options)
Verfolgt Inhalts-Snapshots und stellt Undo/Redo bereit. Wird mit der Content-Ref des Editors verbunden und erfasst den Zustand nach jeder Mutation. Eine konfigurierbare maximale Verlaufsgröße verhindert unbegrenztes Speicherwachstum.
import { useHistory } from "@templatical/core";
const history = useHistory({
content: editor.content,
setContent: editor.setContent,
isRemoteOperation: () => false, // Aufzeichnung bei Remote-/Kollaborations-Updates überspringen
maxSize: 50,
});
history.undo();
history.redo();useBlockActions(options)
Komfortmethoden auf höherer Ebene für gängige Block-Operationen: einen Block erstellen und in einem Schritt einfügen, einen bestehenden Block duplizieren (Deep Clone mit neuer ID) und Löschen mit automatischer Auswahl-Bereinigung.
import { useBlockActions } from "@templatical/core";
const actions = useBlockActions({
addBlock: editor.addBlock,
removeBlock: editor.removeBlock,
updateBlock: editor.updateBlock,
selectBlock: editor.selectBlock,
});
const newBlock = actions.createAndAddBlock("text");
actions.duplicateBlock(existingBlock);
actions.deleteBlock(blockId);
actions.updateBlockProperty(blockId, "content", "<p>Updated</p>");useAutoSave(options)
Überwacht den Editor-Inhalt und ruft Ihren Speicher-Callback mit konfigurierbarer Entprellung (Debounce) auf. Enthält Pause/Resume zum vorübergehenden Deaktivieren von Speichervorgängen (z. B. während Massenoperationen) sowie eine flush()-Methode für sofortiges Speichern.
import { useAutoSave } from "@templatical/core";
const autoSave = useAutoSave({
content: editor.content,
isDirty: () => editor.state.isDirty,
onChange: (content) => saveToServer(content),
debounce: 1000,
enabled: true, // boolean oder () => boolean
});
autoSave.flush(); // Sofort speichern
autoSave.cancel(); // Ausstehenden entprellten Speichervorgang abbrechen
autoSave.pause(); // Auto-Save pausieren
autoSave.resume(); // Fortsetzen
autoSave.destroy(); // Überwachung beenden und aufräumenuseConditionPreview()
Verwaltet den Vorschauzustand für Anzeigebedingungen im Editor. Ermöglicht das Ein-/Ausschalten einzelner Blöcke, um zu simulieren, wie bedingter Inhalt aussieht, wenn unterschiedliche Bedingungen erfüllt sind.
import { useConditionPreview } from "@templatical/core";
const preview = useConditionPreview(editor);
preview.isHidden(blockId); // Prüfen, ob ein Block in der Vorschau ausgeblendet ist
preview.toggleBlock(blockId); // Sichtbarkeit eines Blocks umschalten
preview.reset(); // Alle Blöcke auf sichtbar zurücksetzen
preview.hasHiddenBlocks; // ComputedRef<boolean>useDataSourceFetch(options)
Übernimmt das Abrufen externer Daten für benutzerdefinierte Blöcke mit Datenquellen. Verwaltet den Ladezustand und die Fehlerbehandlung für den onFetch-Callback.
import { useDataSourceFetch } from "@templatical/core";
const dataFetch = useDataSourceFetch({
definition: computed(() => customBlockDefinition),
block: computed(() => customBlock),
onUpdate: (fieldValues, fetched) => {
updateBlock(block.id, { fieldValues, dataSourceFetched: fetched });
},
});
dataFetch.isFetching; // Ref<boolean>
dataFetch.fetchError; // Ref<boolean>
dataFetch.hasDataSource; // ComputedRef<boolean>
dataFetch.needsFetch; // ComputedRef<boolean>
await dataFetch.fetch(); // Abruf auslösen