Skip to content

Installation

Aktive Entwicklung

Templatical wird aktiv weiterentwickelt und veröffentlicht häufig neue Versionen. Die öffentliche API stabilisiert sich — wir folgen SemVer, nutzen Changesets für jedes Release und dokumentieren Breaking Changes im Changelog. Pinne in Produktion eine Version und beobachte die GitHub-Releases, um aktuell zu bleiben.

Feature-Wunsch oder rauer Kante begegnet? Diskussion eröffnen — Feedback formt die Roadmap.

Voraussetzungen

  • Moderner Browser -- Chrome 80+, Firefox 80+, Safari 14+, Edge 80+
  • Container-Element -- muss eine definierte Höhe haben (der Editor füllt seinen Container aus)

npm

bash
npm install @templatical/editor
bash
pnpm add @templatical/editor
bash
yarn add @templatical/editor
bash
bun add @templatical/editor

@templatical/editor ist der visuelle Editor. Um Templates in MJML zu konvertieren, installieren Sie zusätzlich @templatical/renderer:

bash
npm install @templatical/renderer
bash
pnpm add @templatical/renderer
bash
yarn add @templatical/renderer
bash
bun add @templatical/renderer

Der Renderer ist optional. Installieren Sie ihn dort, wo Sie MJML-Ausgabe benötigen:

  • Im Browser, neben dem Editor – wenn Sie editor.toMjml() aufrufen, um aus der Sitzung des Nutzers zu exportieren.
  • In Node.js / auf dem Server – wenn Sie nur gespeichertes Template-JSON haben und es serverseitig in MJML umwandeln möchten. Dafür benötigen Sie den Editor nicht; installieren Sie nur den Renderer.

Wenn Sie editor.toMjml() aufrufen, ohne dass der Renderer installiert ist, wird ein klarer Fehler ausgelöst, der das fehlende Paket benennt.

Paketübersicht

PaketBeschreibungErforderlich
@templatical/editorVisueller Drag-and-Drop-Editor und init()-EinstiegspunktJa
@templatical/typesGemeinsame TypeScript-Typen, Block-Factory-Funktionen, Type GuardsAutomatisch installiert
@templatical/coreFramework-agnostische Editor-Logik (State, History)Automatisch installiert
@templatical/rendererRendert Templates zu MJMLOptional – installieren, wo Sie editor.toMjml() (Browser) oder renderToMjml() (Node.js, Server) aufrufen
@templatical/import-beefreeKonvertiert BeeFree-JSON-Templates in das Templatical-FormatOptional
@templatical/import-unlayerKonvertiert Unlayer-JSON-Design-Templates in das Templatical-FormatOptional

@templatical/types und @templatical/core sind direkte Abhängigkeiten von @templatical/editor und werden automatisch installiert.

Framework-Integration

Templatical wird in jedes beliebige DOM-Element eingebunden. Intern erstellt es seine eigene isolierte Anwendung und funktioniert daher mit jedem Framework – oder ganz ohne Framework.

ts
import { init } from '@templatical/editor';
import '@templatical/editor/style.css';

const editor = await init({
  container: '#editor',
  onChange(content) {
    console.log('Content changed', content);
  },
});

// Später, beim Entfernen des Editors:
editor.unmount();
tsx
import { useRef, useEffect } from 'react';
import { init } from '@templatical/editor';
import '@templatical/editor/style.css';
import type { TemplaticalEditor } from '@templatical/editor';

export function EmailEditor() {
  const containerRef = useRef<HTMLDivElement>(null);
  const editorRef = useRef<TemplaticalEditor | null>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    let cancelled = false;
    init({
      container: containerRef.current,
      onChange(content) {
        console.log('Content changed', content);
      },
    }).then((ed) => {
      if (!cancelled) editorRef.current = ed;
    });

    return () => {
      cancelled = true;
      editorRef.current?.unmount();
    };
  }, []);

  return <div ref={containerRef} style={{ height: '100vh' }} />;
}
vue
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { init } from '@templatical/editor';
import '@templatical/editor/style.css';
import type { TemplaticalEditor } from '@templatical/editor';

const container = ref<HTMLElement>();
let editor: TemplaticalEditor | null = null;

onMounted(async () => {
  if (!container.value) return;

  editor = await init({
    container: container.value,
    onChange(content) {
      console.log('Content changed', content);
    },
  });
});

onUnmounted(() => {
  editor?.unmount();
});
</script>

<template>
  <div ref="container" style="height: 100vh" />
</template>
svelte
<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { init } from '@templatical/editor';
  import '@templatical/editor/style.css';
  import type { TemplaticalEditor } from '@templatical/editor';

  let containerEl: HTMLElement;
  let editor: TemplaticalEditor | null = null;

  onMount(async () => {
    editor = await init({
      container: containerEl,
      onChange(content) {
        console.log('Content changed', content);
      },
    });
  });

  onDestroy(() => {
    editor?.unmount();
  });
</script>

<div bind:this={containerEl} style="height: 100vh;" />
ts
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { init } from '@templatical/editor';
import '@templatical/editor/style.css';
import type { TemplaticalEditor } from '@templatical/editor';

@Component({
  selector: 'app-email-editor',
  standalone: true,
  template: `<div #editorContainer style="height: 100vh"></div>`,
})
export class EmailEditorComponent implements OnInit, OnDestroy {
  @ViewChild('editorContainer', { static: true })
  containerRef!: ElementRef<HTMLElement>;

  private editor: TemplaticalEditor | null = null;

  async ngOnInit(): Promise<void> {
    this.editor = await init({
      container: this.containerRef.nativeElement,
      onChange(content) {
        console.log('Content changed', content);
      },
    });
  }

  ngOnDestroy(): void {
    this.editor?.unmount();
  }
}

Wichtig

Rufen Sie immer unmount() auf, wenn Sie den Editor von der Seite entfernen. Dadurch werden Event-Listener, Timer und DOM-Elemente aufgeräumt. Dies ist besonders wichtig in Single-Page-Anwendungen, bei denen Komponenten während der Navigation ein- und ausgebunden werden.

TypeScript-Unterstützung

Alle Pakete werden mit vollständigen TypeScript-Typdefinitionen ausgeliefert. Konfigurationsoptionen, Callback-Payloads, Blocktypen und Instanzmethoden sind vollständig typisiert:

ts
import { init, unmount } from '@templatical/editor';
import type { TemplaticalEditor, TemplaticalEditorConfig } from '@templatical/editor';
import type { TemplateContent, Block, ThemeOverrides, FontsConfig } from '@templatical/types';

CDN

Wenn Sie keinen Paketmanager verwenden möchten, können Sie den Editor direkt über Script-Tags laden:

html
<link rel="stylesheet" href="https://unpkg.com/@templatical/editor/dist/cdn/editor.css" />
<script type="module">
  import { init } from 'https://unpkg.com/@templatical/editor/dist/cdn/editor.js';

  const editor = await init({
    container: '#editor',
  });
</script>

<div id="editor" style="height: 100vh;"></div>

Der CDN-Build ist vollständig eigenständig – alle Abhängigkeiten sind gebündelt. Schwere Bibliotheken (TipTap, Vue, Pusher usw.) werden per Code-Splitting in separate Chunks aufgeteilt und bei Bedarf nachgeladen.