Anmelden

Für alles eine API

Alles, was Sumaq kann, könnt ihr steuern. Konfiguration, Methoden, Events, Style-Tokens: alles da, und alles funktioniert so, wie ihr es erwarten würdet.

Schnellstart

import Sumaq from './src/sumaq.js';

const editor = new Sumaq('#my-container', {
  toolbar: ['h1', 'h2', 'p', '|', 'bold', 'italic', '|', 'link'],
  onChange: (html) => console.log(html)
});

Der Konstruktor nimmt einen Container (CSS-Selektor oder DOM-Element) und ein optionales Konfigurationsobjekt. Er gibt eine Editor-Instanz zurück. Der bestehende HTML-Inhalt des Containers wird beibehalten und in den Editor geladen.

Konfiguration

Option Typ Standard Beschreibung
toolbar string[] Alle 25 Buttons + Trennzeichen Button-IDs in Reihenfolge. '|' fügt ein Trennzeichen ein.
styleOverrides string | null null CSS-String, der als zweites <style> im Shadow DOM eingefügt wird, nach den Basis-Styles.
onChange function | null null Callback bei entprellter Inhaltsänderung. Erhält bereinigtes HTML.
extensions array [] Extension-Objekte. Werden durchgereicht. Siehe Extensions.

Methoden

getHTML()string

Gibt den Inhalt des Editors als bereinigtes HTML zurück. Im Quellcode-Modus wird der rohe Textarea-Wert vor der Rückgabe bereinigt.

const html = editor.getHTML();

setHTML(html)void

Setzt den Inhalt des Editors. Die Eingabe wird bereinigt, dann normalisiert (semantische Tag-Konvertierung, Inline-Style-Bereinigung). Löst ein 'change'-Event aus.

editor.setHTML('<p>Hallo <strong>Welt</strong></p>');

getText()string

Gibt den reinen Textinhalt zurück (ohne HTML-Tags).

const text = editor.getText();

on(event, callback)void

Registriert einen Event-Listener.

editor.on('change', (html) => { /* ... */ });

off(event, callback?)void

Entfernt einen Event-Listener. Wird callback weggelassen, werden alle Listener für dieses Event entfernt.

editor.off('change', myHandler);  // bestimmten Listener entfernen
editor.off('change');              // alle 'change'-Listener entfernen

destroy()void

Vollständiger Aufräumprozess. Trennt den Mutation-Observer, schließt offene Dialoge, entfernt den selectionchange-Listener, zerstört Extensions, baut das Shadow DOM ab und stellt den bereinigten HTML-Inhalt im ursprünglichen Container wieder her.

editor.destroy();

Events

'change'

Entprellt (150ms). Feuert, nachdem sich der Inhalt stabilisiert hat. Erhält bereinigtes HTML.

editor.on('change', (html) => saveToServer(html));

'input'

Sofort. Feuert bei jedem Tastendruck / jeder Content-Mutation. Erhält HTML (roh im Quellcode-Modus).

editor.on('input', (html) => updatePreview(html));

'drop'

Feuert, wenn Inhalte in den Editor gezogen werden. Das Standard-Drop-Verhalten des Browsers wird unterbunden. Der Editor fügt nichts selbst ein. Er reicht die Daten zur externen Verarbeitung weiter (z.B. CMS-Asset-Upload, Base64-Konvertierung).

editor.on('drop', ({ files, imageFiles, html, text, originalEvent }) => {
  if (imageFiles.length) {
    uploadToAssetManager(imageFiles).then(urls => {
      urls.forEach(url => {
        const img = document.createElement('img');
        img.src = url;
        img.alt = '';
        // Editor-Methoden oder setHTML zum Einfügen verwenden
      });
    });
  }
});
Eigenschaft Typ Beschreibung
filesFile[]Alle abgelegten Dateien
imageFilesFile[]Abgelegte Dateien mit image/* MIME-Typ
htmlstringHTML-Inhalt aus den Drop-Daten (falls vorhanden)
textstringKlartext-Inhalt aus den Drop-Daten (falls vorhanden)
originalEventDragEventDas native Drop-Event, für Koordinaten oder zusätzlichen dataTransfer-Zugriff

'imagePaste'

Feuert, wenn Bilder aus der Zwischenablage eingefügt werden (z.B. Screenshot einfügen, kopiertes Bild). Das Standard-Paste-Verhalten wird unterbunden. Wenn keine Bilder in der Zwischenablage sind, fällt der Editor auf Klartext-Einfügung zurück.

editor.on('imagePaste', ({ files }) => {
  files.forEach(file => {
    const reader = new FileReader();
    reader.onload = () => {
      const img = document.createElement('img');
      img.src = reader.result; // base64
      img.alt = '';
      editor.setHTML(editor.getHTML() + img.outerHTML);
    };
    reader.readAsDataURL(file);
  });
});
Eigenschaft Typ Beschreibung
filesFile[]Eingefügte Bilddateien (nur image/* MIME-Typ)

Sowohl drop als auch imagePaste sind bewusst CMS-agnostisch. Der Editor liefert die Daten, die Integration entscheidet, was damit geschieht. Keine Dateien werden vom Editor selbst eingefügt, hochgeladen oder konvertiert.

Toolbar-Buttons

25 Kern-Buttons plus '|' als Trennzeichen.

ID Funktion Ausgabe
h1Überschrift 1<h1>
h2Überschrift 2<h2>
h3Überschrift 3<h3>
h4Überschrift 4<h4>
h5Überschrift 5<h5>
h6Überschrift 6<h6>
pAbsatz<p>
preCodeblock<pre>
blockquoteZitat<blockquote> mit <cite>
boldFett<strong>
italicKursiv<em>
underlineUnterstrichen<u>
strikethroughDurchgestrichen<s>
superscriptHochgestellt<sup>
subscriptTiefgestellt<sub>
markHervorhebung<mark>
codeInline-Code<code>
linkLink einfügen/bearbeiten<a href>, Dialog mit drei Typen: URL (mit optionalem target="_blank"), E-Mail (mailto: mit optionalem Betreff), Telefon (tel:)
anchorAnker einfügen/bearbeiten<a id>: ID muss mit einem Buchstaben beginnen, nur Buchstaben/Zahlen/Bindestriche/Unterstriche erlaubt. Wird live im Dialog validiert.
alignLeftLinksbündigentfernt Ausrichtungsklasse
alignCenterZentriert.text-center
alignRightRechtsbündig.text-right
ulAufzählung<ul>
olNummerierung<ol>
hrHorizontale Linie<hr>
tableTabelle<table>: Dialog für Zeilen/Spalten (max. 10). Steht der Cursor in einer bestehenden Tabelle, öffnet sich der Bearbeitungsmodus mit vorausgefüllten Maßen und Optionen zum Ändern oder Löschen.
imageBild<img> (Dialog für src, alt)
undoRückgängigBrowser-Undo
redoWiederherstellenBrowser-Redo
sourceQuellcode-Ansichtwechselt zu <textarea> mit rohem HTML. Beim Zurückwechseln zur Rich-Text-Ansicht wird der Inhalt bereinigt.
'|'Trennzeichenoptischer Teiler, keine Funktion

Style-Overrides

Die styleOverrides-Konfiguration fügt ein zweites <style>-Element im Shadow DOM ein, nach den Basis-Styles. Euer CSS gewinnt durch die normale Kaskaden-Reihenfolge. Kein !important nötig.

const editor = new Sumaq('#editor', {
  styleOverrides: `
    .sumaq-content h1,
    .sumaq-content h2,
    .sumaq-content h3 {
      font-family: Georgia, 'Times New Roman', serif;
    }
    .sumaq-content a {
      color: oklch(.45 .15 260);
    }
    .sumaq-content blockquote {
      border-left-color: oklch(.6 .1 260);
    }
  `
});

Der einfachste Weg: --sumaq-* Custom Properties auf :host ändern.

const editor = new Sumaq('#editor', {
  styleOverrides: `
    :host {
      --sumaq-accent: oklch(.5 .2 150);
      --sumaq-border-blockquote: oklch(.5 .2 150);
    }
  `
});

CSS Custom Properties

Alle Tokens verwenden das --sumaq--Präfix. Auf :host definiert, kaskadieren sie in jede Komponente innerhalb des Shadow DOM.

Oberfläche

Token Standard Zweck
--sumaq-bgoklch(.985 .003 107)Editor-Wrapper-Hintergrund
--sumaq-bg-secondarytransparentToolbar-, Tabellenkopf-Hintergrund
--sumaq-bg-tertiaryoklch(.947 .007 81)Escape-Hinweis-Hintergrund
--sumaq-bg-activeoklch(.947 .007 81)Button-Aktiv-Status
--sumaq-bg-contentoklch(.985 .003 107)Inhaltsbereich-Hintergrund
--sumaq-bg-content-focusoklch(.985 .003 107)Inhaltsbereich bei Fokus
--sumaq-bg-codeoklch(.96 .005 95)Inline-<code>-Hintergrund
--sumaq-bg-preoklch(.2 .01 255)<pre>- und Quellansicht-Hintergrund
--sumaq-bg-markoklch(.94 .035 90)<mark>-Hervorhebungs-Hintergrund
--sumaq-bg-dialogoklch(.985 .003 107)Dialog-Hintergrund
--sumaq-bg-backdropoklch(0 0 0 / .35)Dialog-Backdrop-Overlay

Text

Token Standard Zweck
--sumaq-textoklch(.423 .003 107)Primäre Textfarbe
--sumaq-text-secondaryoklch(.55 .003 107)Sekundärer Text (Zitat, Cite)
--sumaq-text-tertiaryoklch(.7 .003 107)Tertiärer Text (Platzhalter)
--sumaq-text-codeoklch(.45 .04 255)Inline-<code>-Textfarbe
--sumaq-text-preoklch(.9 .005 255)<pre>- und Quellansicht-Textfarbe

Akzent

Token Standard Zweck
--sumaq-accentoklch(.308 .051 253)Links, Cursor, primäre Buttons, Aktiv-Zustände
--sumaq-accent-hoveroklch(.25 .05 253)Akzent-Hover-Status
--sumaq-accent-textoklch(.985 .003 107)Text auf akzentfarbigen Hintergründen

Gefahr

Token Standard Zweck
--sumaq-dangeroklch(.5 .13 30)Löschen-/Entfernen-Buttons
--sumaq-danger-hoveroklch(.43 .13 30)Gefahr-Hover-Status

Rahmen

Token Standard Zweck
--sumaq-borderoklch(.925 .008 92)Editor-Wrapper-Rahmen, Dialog-Eingaben
--sumaq-border-hoveroklch(.363 .039 255)Rahmen-Hover-Status
--sumaq-border-subtleoklch(.947 .007 81)Dialog-Kopf-/Fußzeilen-Trennlinien
--sumaq-border-tableoklch(.925 .008 92)Tabellenzellen-Rahmen, horizontale Linie
--sumaq-border-blockquoteoklch(.308 .051 253)Zitat-Linker-Rahmen

Radius

Token Standard Zweck
--sumaq-radius.1875remStandard-Radius (Buttons, Eingaben, Wrapper)
--sumaq-radius-sm.125remKleiner Radius (Code, Mark)
--sumaq-radius-lg.375remGroßer Radius (Dialog)

Schatten

Token Standard Zweck
--sumaq-shadow-dialog0 .25rem 1rem oklch(0 0 0 / .08)Dialog-Schatten
--sumaq-focus-ring0 0 0 .125rem oklch(.363 .039 255 / .35)Fokus-Ring auf Dialog-Eingaben

Sicher zu überschreiben

Diese Styles sind für Anpassung vorgesehen. Frei änderbar.

Inhalts-Typografie: Schriftfamilien, Schriftgrößen, Zeilenhöhen, Abstände bei Überschriften/Absätzen/Listen. Die Überschriften-Staffelung (h1h6 Schriftgrößen) ist ein guter Startpunkt.

Zitat-Styling: Rahmenfarbe, Hintergrund, Innenabstand, Cite-Formatierung.

Tabellen-Styling: Zellen-Innenabstand, Rahmenfarbe, Kopfzeilen-Hintergrund.

Code-Styling: <code>- und <pre>-Schriften, Hintergründe, Textfarben.

Link-Styling: Farbe, Unterstreichung, Hover-Status.

Button- und Dialog-Farben: Hintergrund, Textfarbe, Rahmenfarbe auf .sumaq-btn, .sumaq-btn-primary, .sumaq-dialog__cancel, .sumaq-link-remove. Bei Farben bleiben. Maße sind strukturell.

Nicht überschreiben

Der Editor liefert ein barrierefreies Fundament: wandernder Tabindex in der Toolbar, aria-pressed-Button-Zustände, Fokus-Management, Dialog-Fokus-Falle, Screen-Reader-Beschriftungen. Toolbar- oder Dialog-Styles zu überschreiben riskiert das zu brechen. Zwei Kategorien:

Strukturell: bricht das Layout

  • .sumaq-editor Flexbox (display, flex-direction)
  • .sumaq-toolbar Flex und Umbruch (display, flex-wrap, gap)
  • .sumaq-content Overflow-/Resize-Verhalten (overflow-y, resize, min-height)
  • .sumaq-dialog Zentrierung und Overlay (display, align-items, justify-content, height, width)
  • .sumaq-btn Maße (height, width), Icon-Ausrichtung und Touch-Targets hängen davon ab
  • .sumaq-dialog__box max-width und Zentrierung

Barrierefrei: bricht Barrierefreiheit

  • .sumaq-visually-hidden: Screen-Reader-Text. Diese Klasse entfernen oder ändern versteckt Inhalte vor assistiver Technologie.
  • Fokus-Indikatoren (outline, box-shadow auf :focus-visible), sehende Keyboard-Nutzer sind darauf angewiesen.
  • aria-pressed-Button-Zustände, der visuelle Gedrückt-Zustand (.sumaq-btn[aria-pressed="true"]) muss unterscheidbar bleiben.
  • Dialog-Backdrop (.sumaq-dialog::backdrop), fängt den visuellen Fokus. Transparent machen bricht das Modal-Pattern.
  • Escape-Hinweis (.sumaq-esc-hint) Positionierung, absolut positioniert relativ zum Wrapper.

Farben und Rahmen könnt ihr bei all diesen umstylen. Die Empfehlung: Layout- und Sichtbarkeitsregeln in Ruhe lassen, es sei denn, ihr testet das Ergebnis mit Keyboard und Screen Reader.

Statische Eigenschaften

Sumaq.defaultConfig   // Standard-Konfigurationsobjekt (toolbar, styleOverrides, onChange)
Sumaq.buttonConfig    // Button-Definitionen: label, title, command, value/action
Sumaq.icons           // SVG-Icon-Strings nach Button-ID
Sumaq.styles          // Basis-CSS Template-Literal

Diese werden nach der Klassen-Definition zugewiesen. Ihr könnt sie lesen und technisch auch vor dem Erstellen einer Instanz modifizieren, aber buttonConfig und icons werden über alle Instanzen geteilt, Änderungen sind also global.

defaultConfig wird flach mit eurer Instanz-Konfiguration zusammengeführt ({ ...defaultConfig, ...config }), also ersetzt jede übergebene Option den Standard für diesen Schlüssel.

Bereinigung

Allowlist-basiert. Jedes Mal, wenn HTML in den Editor rein- oder rausgeht (setHTML(), getHTML(), Quellcode-Modus-Wechsel), durchläuft es die Bereinigung.

Was überlebt: Elemente in ALLOWED_ELEMENTS (31 semantische Tags: p, h1h6, blockquote, pre, cite, ul, ol, li, table, thead, tbody, tr, td, th, hr, strong, em, u, s, sup, sub, mark, code, a, br, img) und Attribute in ALLOWED_ATTRS (pro Element: href/target/rel auf Links, src/alt auf Bildern, colspan/rowspan auf Tabellenzellen, start auf geordneten Listen, data-placeholder auf Cite, id global).

Was entfernt wird: <script>, <style>, <iframe>, <video>, <audio>, <svg>, <math>, Formularelemente werden mitsamt Inhalt entfernt. Unbekannte Elemente werden entpackt (Kinder bleiben). Alle on*-Event-Handler und javascript:-URIs werden entfernt. Inline-style- und class-Attribute werden durch einen separaten Bereinigungs-Schritt behandelt.

Extensions

Der Editor unterstützt eigene Extensions für Buttons, Dialoge und Formatierungen, die nicht zum Kern gehören. Extensions registrieren Buttons, deklarieren geschützte CSS-Klassen und erhalten Lifecycle-Hooks (init, onCommand, destroy).

Vollständige Dokumentation: Extensions