
Markdown-Editor: Ein WYSIWYG- und Markup-Editor auf Basis von Gravity UI
Markdown-Editor: Ein WYSIWYG- und Markup-Editor auf Basis von Gravity UI

TL;DR
- Ermöglicht gleichzeitiges Arbeiten im WYSIWYG- und im Markdown-Markup-Modus (mit Preview und Split).
- Unterstützt eine große Anzahl von Blöcken out of the box.
- Lässt sich funktional erweitern — im WYSIWYG-Modus gibt es ein Extension-System.
- Für die Nutzung in React-Anwendungen entwickelt.
- Nutzt Theming und Komponenten aus Gravity UI.
- Komplett auf Open-Source-Technologien aufgebaut (ProseMirror, CodeMirror, markdown-it, Diplodoc, Gravity UI).
- Entspricht dem CommonMark-Standard, unterstützt die Standard-Markdown-Sprache sowie Yandex Flavored Markdown (YFM).
Hallo! Ich heiße Sergey Makhnatkin und arbeite als Entwickler im Bereich User Experience bei Yandex Cloud. Letztes Jahr haben wir über unser Design-System und die Komponentenbibliothek Gravity UI geschrieben. Seitdem wurde das System mehrfach aktualisiert und um neue Funktionen erweitert, und heute möchte ich über ein neues Tool sprechen — den Markdown Editor, der den Prozess der Arbeit mit Dokumentation deutlich vereinfacht.
Wir sprechen über die Entstehungsgeschichte der Benutzeroberfläche, architektonische Besonderheiten sowie technische Details zur Integration und zur Entwicklung eigener Erweiterungen — und danach darüber, warum das alles als Open Source verfügbar ist.
Übrigens: Hier kann man das Tool ausprobieren:
Warum wir einen eigenen Markdown Editor brauchen
Um Unternehmensinformationen bequem zu speichern und zu strukturieren, haben wir die Plattform Wiki entwickelt, mit der sich Wissensdatenbanken erstellen lassen. Neben der Wissensdatenbank haben wir auch Ansätze für Dokumentation weiterentwickelt, wie zum Beispiel Docs as Code, bei dem Dokumentation und Code Seite an Seite im Dateispeicher leben (.md-Dateien). So entstand die Plattform Diplodoс.
Wiki und Diplodoc verbindet, dass beide Plattformen mit einem Markdown-Dialekt arbeiten — Yandex Flavored Markdown (YFM), der in Nebius, Bitrix, DoubleCloud, Mappable, Meteum verwendet wird.
Mit der Zeit haben wir festgestellt, dass es zwei Nutzergruppen gibt, die sich den Prozess des Erstellens und Bearbeitens von Text unterschiedlich vorstellen. Die einen möchten beim Arbeiten mit dem Text sofort das Endergebnis sehen — wie in MS Word, Confluence oder Notion. Die anderen vertrauen ausschließlich dem Markup und formatieren Seiten lieber mit Markdown. Bekannte Bibliotheken, die gleichzeitig im WYSIWYG/Markdown-Modus arbeiten, haben wir nicht gefunden. Notion ist zum Beispiel nur WYSIWYG, und in Code-Editoren gibt es nur Markdown und einen Preview-Modus.
Wir haben einen Markdown-Editor entwickelt, der gleichzeitig in zwei Modi arbeiten kann: visuell (WYSIWYG) und im Markup-Modus (Markdown). Im ersten Modus helfen Icons in der Toolbar beim Auszeichnen, und im zweiten können Nutzer den Markdown-Code manuell bearbeiten. Außerdem speichert unsere Lösung das Dokument als md-Datei, unabhängig davon, welcher Modus beim Erstellen verwendet wurde.
So sieht der visuelle Editor aus, in dem man Text über Buttons formatieren kann:

Und so — der Markup-Modus, in dem Formatierungselemente durch spezielle Zeichen обозначаются:

Funktionen des Markdown Editor in Gravity UI
Der Editor entspricht dem CommonMark-Standard, unterstützt die Standard-Markdown-Sprache sowie YFM. Außerdem haben wir die Möglichkeit hinzugefügt, die Syntax auch um andere Markdown-Dialekte zu erweitern, zum Beispiel GitHub Flavored Markdown. Dabei erlaubt der Editor den Wechsel vom Markup-Modus in den WYSIWYG-Modus; das Dokument wird weiterhin als md-Markup oder als erweitertes md (z. B. im Fall von YFM) gespeichert.
Erweiterungen
Im Editor sind von Anfang an viele Erweiterungen und Einstellungen integriert. Zum Beispiel Mermaid-Diagramme und HTML-Blöcke:


Wir haben versucht, den Kern des Editors leicht erweiterbar zu gestalten. Entwickler können eigene Erweiterungen oder zusätzliche Funktionalität erstellen, die helfen:
- neue Entitäten hinzuzufügen — Blöcke oder Text-Modifikatoren;
- den Markdown-Parser zusätzlich zu konfigurieren;
- Actions hinzuzufügen, die es erlauben, den Editor von außen zu steuern;
- die UI-Funktionalität anzureichern, z. B. ein Menü verfügbarer Befehle beim Tippen eines Slash anzuzeigen;
- das aktuelle Verhalten zu modifizieren, z. B. Bilder und Dateien einzufügen und in einen Storage hochzuladen.
Hier sind einige Beispiele solcher Erweiterungen, die wir für unser Wiki entwickelt haben:
- kollaborativer Bearbeitungsmodus;

- Diagrammblock draw.io;

- Plugin YandexGPT;


- Includes;

- Abschnittsstruktur;

- Sections zum Erstellen eines удобlichen Rasters;

- Markdown-Modus mit Preview;

- und vieles mehr.

Markup kann automatisch преобразовываться. Wenn Sie lieber ohne Maus arbeiten, stehen im visuellen Modus spezielle Zeichen zur Verfügung, mit denen Markup direkt im Text angewendet werden kann. Zum Beispiel schalten ** Text im WYSIWYG-Modus in Fettdruck um. Mit diesen Zeichen kann man Text formatieren sowie Inline- und Block-Code erstellen.
Außerdem kann man das Erweiterungsmenü durch Eingabe des Zeichens / öffnen.

Voreinstellungen
Der Editor позволяет, die Toolbar mit Werkzeugen für jedes Projekt отдельно zu konfigurieren, wird aber mit mehreren fertigen Konfigurationen geliefert — Presets.
Editor ohne Presets:

Das CommonMark-Preset unterstützt Standard-Markdown-Elemente: Fettschrift, Kursivschrift, Überschriften, Listen, Links, Zitate und Code-Blöcke.

Im Standard-Preset появляется zusätzlich durchgestrichener Text sowie eine Tabelle, in deren Zellen nur Text stehen kann. Dieses Preset entspricht dem Standard von markdown-it.

Wie oben erwähnt, unterstützt der Editor auch YFM und lässt sich daher hervorragend mit Diplodoc integrieren. Im YFM-Preset появляются zusätzliche Elemente: erweiterte Tabellen, Einfügen von Dateien und Bildern, Checkboxen, Cut, Tabs, Monospace-Schrift.

Das Full-Preset enthält еще mehr Elemente.

Architektur
Die Basis des Editors im WYSIWYG-Modus ist die bekannte Bibliothek ProseMirror, und für das Markup используется CodeMirror. ProseMirror unterstützt Bearbeitung mit Formatierung, während CodeMirror für Situationen подходит, in denen man mit unformatiertem Text arbeiten muss.
Wir haben uns именно für diese Bibliotheken entschieden, weil sie vom gleichen Autor entwickelt wurden, in Architektur und Implementierungsansätzen konsistent sind, von einer großen Community поддерживаются, in vielen Editoren eingesetzt werden und für die Arbeit mit Text gut optimiert sind. Zum Beispiel: ein Transaktions- System zum Einbringen von Änderungen in das Dokument, Decorations für Views, DOM-Virtualisierung oder Unterstützung der Syntax vieler Programmiersprachen.
Integration
Unser Editor lässt sich einfach als React Hook einbinden:
import React from 'react';
import {useMarkdownEditor, MarkdownEditorView} from '@gravity-ui/markdown-editor';
import {toaster} from '@gravity-ui/uikit/toaster-singleton-react-18';
function Editor({onSubmit}) {
const editor = useMarkdownEditor({allowHTML: false});
React.useEffect(() => {
function submitHandler() {
// Serialize current content to markdown markup
const value = editor.getValue();
onSubmit(value);
}
editor.on('submit', submitHandler);
return () => {
editor.off('submit', submitHandler);
};
}, [onSubmit]);
return <MarkdownEditorView stickyToolbar autofocus toaster={toaster} editor={editor} />;
}
Wir verwenden Komponenten aus der uikit-Bibliothek von GravityUI. Dadurch ist garantiert, dass die gesamte UI konsistent ist und einheitlichen Styleguides entspricht. Die Nutzung dieser Komponenten обеспечивает außerdem ein hohes Maß an Konsistenz und Wiedererkennung für die Nutzer, was die Arbeit mit dem Editor noch bequemer macht.
Wir haben ausführliche Anleitungen, wie man den Editor in eine React-App einbindet, sowie dazu, wie man verschiedene Erweiterungen anschließt: zum Beispiel YandexGPT, Mermaid oder LaTeX.
Integration eigener Erweiterungen
Im Editor ist bereits eine Reihe zusätzlicher Erweiterungen integriert. Aber wenn das nicht reicht, können Entwickler ihre eigenen Erweiterungen in den WYSIWYG-Modus des Editors hinzufügen. Was Erweiterungen bringen können, haben wir oben besprochen.
Wenn Sie einen neuen Block oder Text-Modifikator hinzufügen möchten, müssen Sie zuerst die interne markdown-it-Instanz mit der Methode configureMd konfigurieren. Danach следует, das Wissen über die neue Entität mit den Methoden addNode oder addMark hinzuzufügen, indem Sie den Namen der Entität und eine Callback-Funktion übergeben, die ein Objekt mit drei обязательlichen Feldern zurückgibt:
import insPlugin from 'markdown-it-ins';
export const underlineMarkName = 'ins';
export const UnderlineSpecs: ExtensionAuto = (builder) => {
builder
.configureMd((md) => md.use(insPlugin))
.addMark(underlineMarkName, () => ({
spec: {
parseDOM: [{tag: 'ins'}, {tag: 'u'}],
toDOM() {
return ['ins'];
},
},
toMd: {open: '++', close: '++', mixable: true, expelEnclosingWhitespace: true},
fromMd: {tokenSpec: {name: underlineMarkName, type: 'mark'}},
}));
};
spec— Spezifikation für ProseMirror;fromMd— Konfiguration zum Parsen des Markdown-Markups in die Darstellung innerhalb von ProseMirror;toMd— Konfiguration zur Serialisierung der Entität in Markdown-Markup.
Unten zum Beispiel die Konfiguration einer Erweiterung für unterstrichenen Text. Sie kann erweitert werden, indem man eine Action über die Methode addAction hinzufügt:
import {toggleMark} from 'prosemirror-commands';
const undAction = 'underline';
builder
.addAction(undAction, ({schema}) => ({
isActive: (state) => Boolean(isMarkActive(state, markType)),
isEnable: toggleMark(underlineType(schema)),
run: toggleMark(underlineType(schema)),
})
)
Eine solche Action kann im Code wie folgt aufgerufen werden:
// editor – Editor-Instanz, die als Ergebnis von useMarkdownEditor erhalten wurde
editor.actions.underline.run(),
In der Dokumentation finden Sie eine vollständige Anleitung zum Erstellen einer neuen Erweiterung.
Wir erweitern ständig die Einsatzmöglichkeiten unseres Editors: Aktuell arbeiten wir an einem Plugin für VS Code, das es ermöglicht, mit md-Dateien in einem удобlichen WYSIWYG-Modus direkt im Editor zu arbeiten. Außerdem planen wir, einen vollwertigen mobilen Modus hinzuzufügen. Dadurch kann jeder Nutzer in unserem Editor arbeiten und braucht dafür nur ein Mobiltelefon zur Hand.
Unser Editor ist nicht über Nacht entstanden: Er ist das Ergebnis angesammelter Erfahrung und знаний. Wir sind stolz darauf, dass der Editor vollständig auf Open-Source-Produkten basiert, darunter die zuverlässigen und bewährten Tools ProseMirror, CodeMirror, markdown-it sowie unsere eigenen Entwicklungen — Diplodoc und Gravity UI.
Sie können jederzeit zur Weiterentwicklung des Editors beitragen: einen Pull Request erstellen oder bei der Lösung aktueller Probleme helfen, die im Bereich Issues aufgelistet sind. Ihre Unterstützung und ein frischer Blick helfen uns, den Editor besser zu machen. Und wenn Sie unser Projekt nützlich finden — geben Sie unserem GitHub-Repository einen Stern, das ist wertvoll :)

Sergey Makhnatkin
Frontend-Entwickler