Skip to content

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.

ts
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.

ts
import { unmount } from "@templatical/editor";

unmount();

TemplaticalEditorConfig

PropertyTypeRequiredBeschreibung
containerstring | HTMLElementYesCSS-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
shadowDombooleanNoMountet 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
contentTemplateContentNoAnfänglicher Template-Inhalt. Standardmäßig ein leeres Template
onChange(content: TemplateContent) => voidNoWird aufgerufen, wenn sich der Template-Inhalt ändert (entprellt)
onSave(content: TemplateContent) => voidNoWird aufgerufen, wenn der Benutzer eine Speicheraktion auslöst
onError(error: Error) => voidNoWird aufgerufen, wenn ein Fehler auftritt
onRequestMedia(context?: MediaRequestContext) => Promise<MediaResult | null>NoWird aufgerufen, wenn der Benutzer ein Bild auswählen möchte. Gibt { url, alt? } oder null zurück
mergeTagsMergeTagsConfigNoMerge-Tag-Konfiguration. Siehe Merge-Tags
displayConditionsDisplayConditionsConfigNoKonfiguration für Anzeigebedingungen. Siehe Anzeigebedingungen
customBlocksCustomBlockDefinition[]NoDefinitionen für benutzerdefinierte Blocktypen. Siehe Benutzerdefinierte Blöcke
paletteBlocksstring[]NoAllowlist + 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
blockDefaultsBlockDefaultsNoStandard-Property-Überschreibungen für neue Blöcke. Siehe Standardwerte
templateDefaultsTemplateDefaultsNoStandardeinstellungen für leere Templates. Siehe Standardwerte
fontsFontsConfigNoSchriftart-Konfiguration. Siehe Benutzerdefinierte Schriftarten
themeThemeOverridesNoÜberschreibungen für Farb-Tokens. Unterstützt einen dark-Schlüssel für Dark-Mode-Überschreibungen. Siehe Theming
uiTheme'light' | 'dark' | 'auto'NoUI-Farbschema. 'auto' folgt den Systemeinstellungen. Standardwert ist 'auto'
localestringNoLocale-Code (z. B. 'en', 'de'). Standardwert ist 'en'
brandingbooleanNoZeigt den "Powered by Templatical"-Footer. Standardwert true. Auf false setzen, um ihn auszublenden
smallScreenNoticebooleanNoZeigt 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.

ts
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 ihren custom:-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 countdown auß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. paletteBlocks steuert, 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.

ts
const content = editor.getContent();
// { blocks: [...], settings: { width: 600, ... } }

setContent(content)

Ersetzt den Editor-Inhalt.

ts
import { createDefaultTemplateContent } from "@templatical/types";

editor.setContent(createDefaultTemplateContent());

setTheme(theme)

Wechselt das UI-Farbschema zur Laufzeit, ohne den Editor neu zu initialisieren.

ts
editor.setTheme("dark");
editor.setTheme("light");
editor.setTheme("auto"); // folgt der Systemeinstellung

Parameter: 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).

ts
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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
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äumen

useConditionPreview()

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.

ts
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.

ts
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