Skip to content

Typen-Referenz

@templatical/types stellt alle gemeinsamen TypeScript-Typen, Block-Factory-Funktionen und Hilfsfunktionen bereit.

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

Template-Struktur

TemplateContent

Der Root-Typ, der ein E-Mail-Template repräsentiert.

ts
interface TemplateContent {
  blocks: Block[];
  settings: TemplateSettings;
}

TemplateSettings

ts
interface TemplateSettings {
  width: number;                  // Template-Breite in Pixeln (Standard: 600)
  backgroundColor: string;        // Hintergrundfarbe
  textColor: string;              // Standard-Textfarbe; Textblöcke erben sie (Standard #1a1a1a)
  linkColor?: string;             // Linkfarbe; Links erben die Textfarbe, wenn nicht gesetzt
  linkUnderline: boolean;         // Textlinks unterstreichen (Standard true)
  fontFamily: string;             // Standard-Schriftfamilie
  preheaderText?: string;         // E-Mail-Preheader-Text
  locale: string;                 // BCP-47-Inhaltssprache; <html lang> (Standard 'en')
  direction?: ContentDirection;   // 'ltr' | 'rtl'; ungesetzt folgt der Inhaltssprache
}

type ContentDirection = 'ltr' | 'rtl';

Block

Eine diskriminierte Union aller Blocktypen:

ts
type Block =
  | TitleBlock
  | ParagraphBlock
  | ImageBlock
  | ButtonBlock
  | SectionBlock
  | DividerBlock
  | VideoBlock
  | SpacerBlock
  | SocialIconsBlock
  | MenuBlock
  | TableBlock
  | HtmlBlock
  | CountdownBlock
  | CustomBlock;

BlockType

ts
type BlockType =
  | 'title' | 'paragraph' | 'image' | 'button' | 'section'
  | 'divider' | 'video' | 'spacer' | 'social'
  | 'menu' | 'table' | 'html' | 'countdown' | 'custom';

Basistypen

BaseBlock

Alle Blöcke erweitern dieses Interface.

ts
interface BaseBlock {
  id: string;
  type: string;
  styles: BlockStyles;
  visibility?: BlockVisibility;
  displayCondition?: DisplayCondition;
}

BlockStyles

ts
interface BlockStyles {
  padding: SpacingValue;
  backgroundColor?: string;
}

SpacingValue

ts
interface SpacingValue {
  top: number;
  right: number;
  bottom: number;
  left: number;
}

BlockVisibility

Steuert, auf welchen Viewports ein Block sichtbar ist.

ts
interface BlockVisibility {
  desktop: boolean;
  mobile: boolean;
}

Blocktypen

Detaillierte Beschreibungen der einzelnen Blocktypen finden Sie im Blocks-Leitfaden.

TitleBlock

ts
interface TitleBlock extends BaseBlock {
  type: 'title';
  content: string;          // HTML-Inhalt
  level: 1 | 2 | 3 | 4;   // H1=36px, H2=28px, H3=22px, H4=18px
  color: string;
  textAlign: 'left' | 'center' | 'right';
  fontFamily?: string;
}

ParagraphBlock

ts
interface ParagraphBlock extends BaseBlock {
  type: 'paragraph';
  content: string;          // HTML-Inhalt (alle Formatierungen sind inline über TipTap)
}

ImageBlock

ts
interface ImageBlock extends BaseBlock {
  type: 'image';
  src: string;
  alt: string;
  width: number | 'full';
  /** Ohne Angabe wird die Höhe aus der Breite abgeleitet, das Seitenverhältnis bleibt erhalten. */
  height?: number;
  align: 'left' | 'center' | 'right';
  /** Eckenradius in px. Ohne Angabe oder 0 bleiben die Ecken eckig. */
  borderRadius?: number;
  linkUrl?: string;
  linkOpenInNewTab?: boolean;
  placeholderUrl?: string;
  decorative?: boolean;
}

ButtonBlock

ts
interface ButtonBlock extends BaseBlock {
  type: 'button';
  text: string;
  url: string;
  backgroundColor: string;
  textColor: string;
  borderRadius: number;
  fontSize: number;
  buttonPadding: SpacingValue;
  fontFamily?: string;
  openInNewTab?: boolean;
  width?: number | 'full';
  align: 'left' | 'center' | 'right';
}

SectionBlock

Container für mehrspaltige Layouts.

ts
interface SectionBlock extends BaseBlock {
  type: 'section';
  columns: ColumnLayout;
  children: Block[][];      // Array von Spalten, die jeweils Blöcke enthalten
  stackOnMobile?: boolean;  // fehlt/true: Spalten stapeln auf Mobilgeräten (MJML-Standard).
                            // false: als <mj-group> gerendert, bleiben nebeneinander.
}

type ColumnLayout = '1' | '2' | '3' | '2-1' | '1-2';

DividerBlock

ts
interface DividerBlock extends BaseBlock {
  type: 'divider';
  lineStyle: 'solid' | 'dashed' | 'dotted';
  color: string;
  thickness: number;
  width: number | 'full';
}

VideoBlock

Wird als verlinktes Thumbnail-Bild gerendert -- E-Mail-Clients unterstützen keine eingebettete Wiedergabe.

ts
interface VideoBlock extends BaseBlock {
  type: 'video';
  url: string;
  openInNewTab?: boolean;
  thumbnailUrl: string;   // Wird aus einer YouTube-/Vimeo-URL abgeleitet, wenn leer
  alt: string;
  width: number | 'full';
  /** Ohne Angabe wird die Höhe aus der Breite abgeleitet, das Seitenverhältnis bleibt erhalten. */
  height?: number;
  align: 'left' | 'center' | 'right';
  placeholderUrl?: string;
}

SpacerBlock

ts
interface SpacerBlock extends BaseBlock {
  type: 'spacer';
  height: number;
}

SocialIconsBlock

ts
interface SocialIconsBlock extends BaseBlock {
  type: 'social';
  icons: SocialIcon[];
  iconStyle: SocialIconStyle;
  iconSize: SocialIconSize;
  spacing: number;
  align: 'left' | 'center' | 'right';
}

interface SocialIcon {
  id: string;
  platform: SocialPlatform;
  url: string;
}

type SocialPlatform =
  | 'facebook' | 'twitter' | 'instagram' | 'linkedin'
  | 'youtube' | 'tiktok' | 'pinterest' | 'email'
  | 'whatsapp' | 'telegram' | 'discord' | 'snapchat'
  | 'reddit' | 'github' | 'dribbble' | 'behance'
  | 'website';


type SocialIconStyle = 'solid' | 'outlined' | 'rounded' | 'square' | 'circle';
type SocialIconSize = 'small' | 'medium' | 'large';
ts
interface MenuBlock extends BaseBlock {
  type: 'menu';
  items: MenuItemData[];
  fontSize: number;
  fontFamily?: string;
  color: string;
  linkColor?: string;
  textAlign: 'left' | 'center' | 'right';
  separator: string;
  separatorColor: string;
  spacing: number;
}

interface MenuItemData {
  id: string;
  text: string;
  url: string;
  openInNewTab: boolean;
  bold: boolean;
  underline: boolean;
  color?: string;
}

TableBlock

ts
interface TableBlock extends BaseBlock {
  type: 'table';
  rows: TableRowData[];
  hasHeaderRow: boolean;
  headerBackgroundColor?: string;
  borderColor: string;
  borderWidth: number;
  cellPadding: number;
  fontSize: number;
  fontFamily?: string;
  color: string;
  textAlign: 'left' | 'center' | 'right';
}

interface TableRowData {
  id: string;
  cells: TableCellData[];
}

interface TableCellData {
  id: string;
  content: string;
}

HtmlBlock

ts
interface HtmlBlock extends BaseBlock {
  type: 'html';
  content: string;          // Rohes HTML
}

CountdownBlock

Wird als animiertes GIF gerendert, was das Templatical-Cloud-Backend erfordert -- @templatical/renderer gibt stattdessen einen templatical:unrenderable-block-Marker aus. Siehe Blöcke ohne Renderer.

ts
interface CountdownBlock extends BaseBlock {
  type: 'countdown';
  targetDate: string;       // Lokales Datum/Uhrzeit, 'YYYY-MM-DDTHH:mm'
  timezone: string;         // IANA-Name, in dem das Ziel gelesen wird, z. B. 'Europe/Berlin'
  showDays: boolean;
  showHours: boolean;
  showMinutes: boolean;
  showSeconds: boolean;
  separator: ':' | '-' | ' ';
  digitFontSize: number;
  digitColor: string;
  labelColor: string;
  labelFontSize: number;
  backgroundColor: string;
  fontFamily?: string;
  labelDays: string;
  labelHours: string;
  labelMinutes: string;
  labelSeconds: string;
  expiredMessage: string;
  expiredImageUrl: string;  // Wird nach Ablauf statt des Timers angezeigt
  hideOnExpiry: boolean;
}

CustomBlock

ts
interface CustomBlock extends BaseBlock {
  type: 'custom';
  customType: string;
  fieldValues: Record<string, unknown>;
  renderedHtml?: string;
  dataSourceFetched?: boolean;
}

Konfigurationstypen

MergeTag

ts
interface MergeTag {
  label: string;
  value: string;
  group?: string;        // nur Picker: Gruppierungslabel
  description?: string;  // nur Picker: Hilfetext
  sample?: string;       // nur Vorschau: Beispielwert; nie im MJML
}

interface MergeTagRequestContext {
  reason: 'insert' | 'edit';
  current?: MergeTag;    // beim Bearbeiten, wenn das Token zu tags passt
}

MergeTagsConfig

ts
interface MergeTagsConfig {
  syntax?: SyntaxPresetName | SyntaxPreset;
  tags?: MergeTag[];
  onRequest?: (context?: MergeTagRequestContext) => Promise<MergeTag | null>;
  showRawValue?: boolean;   // Roh-Token im Tooltip anzeigen (Standard true)
  autocomplete?: boolean;   // tippbasiertes Autocomplete (Standard true)
}

type SyntaxPresetName = 'liquid' | 'handlebars' | 'mailchimp' | 'ampscript';

DisplayCondition

ts
interface DisplayCondition {
  label: string;
  before: string;
  after: string;
  group?: string;
  description?: string;
}

DisplayConditionsConfig

ts
interface DisplayConditionsConfig {
  conditions: DisplayCondition[];
  allowCustom?: boolean;
}

CustomBlockDefinition

ts
interface CustomBlockDefinition {
  type: string;
  name: string;
  icon?: string;
  description?: string;
  fields: CustomBlockField[];
  template: string;                       // Liquid-Template
  dataSource?: DataSourceConfig;
  defaultStyles?: Partial<BlockStyles>;   // Stile für neue Instanzen
  stylesheet?: string;                    // CSS, einmal in mj-head emittiert
}

Details zu den Feldtypen finden Sie unter Benutzerdefinierte Blöcke.

ThemeOverrides

ts
interface ThemeOverrides {
  bg?: string;
  bgElevated?: string;
  bgHover?: string;
  bgActive?: string;
  border?: string;
  borderLight?: string;
  text?: string;
  textMuted?: string;
  textDim?: string;
  primary?: string;
  primaryHover?: string;
  primaryLight?: string;
  secondary?: string;
  secondaryHover?: string;
  secondaryLight?: string;
  success?: string;
  successLight?: string;
  warning?: string;
  warningLight?: string;
  danger?: string;
  dangerLight?: string;
  canvasBg?: string;
  dark?: Omit<ThemeOverrides, 'dark'>;
}

FontsConfig

ts
interface FontsConfig {
  defaultFallback?: string;
  defaultFont?: string;
  customFonts?: CustomFont[];
  builtIns?: boolean | string[];  // true/weggelassen: alle sieben; false: keine; string[]: Allowlist — siehe /de/guide/fonts
}

interface CustomFont {
  name: string;
  url: string;
  fallback?: string;
}

ViewportSize

ts
type ViewportSize = 'desktop' | 'mobile';

Factory-Funktionen

Alle Factory-Funktionen akzeptieren ein optionales Partial-Override-Objekt und geben einen vollständigen Block mit generierter ID zurück.

ts
import {
  createTitleBlock,
  createParagraphBlock,
  createImageBlock,
  createButtonBlock,
  createSectionBlock,
  createDividerBlock,
  createVideoBlock,
  createSpacerBlock,
  createSocialIconsBlock,
  createMenuBlock,
  createTableBlock,
  createHtmlBlock,
  createCountdownBlock,
  createCustomBlock,
  createBlock,
  cloneBlock,
  createDefaultTemplateContent,
  generateId,
} from '@templatical/types';

// Countdown-GIFs brauchen Cloud oder ein `blockRenderers.countdown`-Override; der OSS-Renderer gibt einen Platzhalter aus.

// Mit Standardwerten erstellen
const paragraph = createParagraphBlock();

// Mit Überschreibungen erstellen
const heading = createTitleBlock({
  content: '<h1>Hello</h1>',
  level: 1,
});

// Beliebigen Block per Typ-String erstellen
const block = createBlock('button');

// Deep Clone mit neuer ID
const copy = cloneBlock(existingBlock);

// Leeres Template
const template = createDefaultTemplateContent();

// Eine UUID generieren
const id = generateId();

Type Guards

ts
import {
  isTitle, isParagraph, isImage, isButton, isSection,
  isDivider, isVideo, isSpacer, isSocialIcons,
  isMenu, isTable, isHtml, isCountdown, isCustomBlock,
} from '@templatical/types';

if (isTitle(block)) {
  console.log(block.level); // TypeScript weiß, dass dies ein TitleBlock ist
}

EventEmitter

Ein typisierter Event-Emitter für Subscription-Muster.

ts
import { EventEmitter } from '@templatical/types';

type Events = {
  change: TemplateContent;
  select: string | null;
};

const emitter = new EventEmitter<Events>();

const unsubscribe = emitter.on('change', (content) => {
  console.log('Changed:', content);
});

emitter.emit('change', templateContent);
unsubscribe(); // Listener entfernen

Methoden

MethodeBeschreibung
on(event, handler)Abonnieren. Gibt eine Unsubscribe-Funktion zurück
off(event, handler)Einen bestimmten Handler abbestellen
emit(event, data)Ein Ereignis auslösen
removeAllListeners(event?)Alle Listener entfernen, optional für ein bestimmtes Ereignis
listenerCount(event)Anzahl der Listener für ein Ereignis

Speicherverträge

Template, TemplatePatch, SavedBlockInput, CommentsProvider, MediaProvider und die übrigen BYO-Speicherformen stehen unter Backend anbinden. Diese Seite ist das Blockmodell und die Editor-Config.