Éditeur Markdown: un éditeur WYSIWYG et de balisage construit sur Gravity UI

TL;DR
  • Permet de travailler simultanément en mode WYSIWYG et en balisage markdown (avec aperçu et split).
  • Prend en charge un grand nombre de blocs prêts à l’emploi.
  • Permet d’étendre les fonctionnalités — en mode WYSIWYG, il existe un système d’extensions.
  • Conçu pour fonctionner dans des applications React.
  • Utilise la thématisation et des composants de Gravity UI.
  • Entièrement construit sur des technologies open source (ProseMirror, CodeMirror, markdown-it, Diplodoc, Gravity UI).
  • Conforme au standard CommonMark, prend en charge le langage markdown standard et Yandex Flavored Markdown (YFM).

Bonjour! Je m’appelle Sergey Makhnatkin, je travaille comme développeur dans l’équipe User Experience de Yandex Cloud. L’an dernier, nous avons écrit à propos de notre design system et de la bibliothèque de composants Gravity UI. Depuis, le système a été mis à jour à plusieurs reprises et s’est enrichi de nouvelles fonctionnalités, et aujourd’hui je veux vous parler d’un nouvel outil — Markdown Editor — qui simplifie considérablement le travail avec la documentation.

Nous allons parler de l’historique de création de l’interface utilisateur, des particularités d’architecture et des détails techniques d’intégration et de développement d’extensions personnalisées — puis, pourquoi tout cela est disponible en open source.

Au fait, vous pouvez essayer l’outil ici:

Pourquoi nous avons besoin de notre propre Markdown Editor

Pour stocker et structurer facilement l’information d’entreprise, nous avons développé la plateforme Wiki, qui permet de créer des bases de connaissances. En plus de la base de connaissances, nous avons fait évoluer des approches de documentation comme Docs as Code, où la documentation et le code cohabitent côte à côte dans un stockage de fichiers (.md). C’est ainsi qu’est apparue la plateforme Diplodoс.

Wiki et Diplodoc ont en commun que les deux plateformes utilisent un dialecte markdown — Yandex Flavored Markdown (YFM), qui est utilisé chez Nebius, Bitrix, DoubleCloud, Mappable, Meteum.

Avec le temps, nous avons remarqué qu’il existe deux groupes d’utilisateurs, qui se représentent différemment le processus de création et d’édition de texte. Les uns préfèrent voir immédiatement le résultat final en travaillant sur le texte, comme dans MS Word, Confluence ou Notion. Les autres ne jurent que par le balisage et préfèrent mettre en forme les pages avec markdown. Nous n’avons pas trouvé de bibliothèques connues qui fonctionnent simultanément en mode WYSIWYG/markdown. Par exemple, Notion n’est que WYSIWYG, et dans les éditeurs de code il n’y a souvent que markdown et un mode d’aperçu.

Nous avons développé un éditeur markdown capable de fonctionner simultanément dans deux modes: visuel (WYSIWYG) et mode balisage (markdown). Dans le premier mode, des icônes sur la barre d’outils aident à baliser le texte, et dans le second, les utilisateurs peuvent éditer manuellement le code markdown. De plus, notre solution enregistre le document comme un fichier md, quel que soit le mode utilisé lors de sa création.

Voici à quoi ressemble l’éditeur visuel, où le texte peut être mis en forme à l’aide de boutons:

Full screen image

Et voici le mode balisage, où les éléments de mise en forme sont indiqués à l’aide de symboles spéciaux:

Full screen image

Fonctionnalités de Markdown Editor dans Gravity UI

L’éditeur est conforme au standard CommonMark, prend en charge le langage markdown standard et le langage YFM. Nous avons également ajouté la possibilité d’étendre la syntaxe à d’autres dialectes markdown, par exemple GitHub Flavored Markdown. L’éditeur permet de passer du mode markup au mode WYSIWYG, et le document sera stocké sous forme de balisage md ou de md étendu (par exemple dans le cas de YFM).

Extensions

Dès le départ, l’éditeur intègre de nombreuses extensions et réglages. Par exemple, les diagrammes Mermaid et les blocs HTML:

Full screen image
Full screen image

Nous avons cherché à rendre le cœur de l’éditeur facilement extensible. Les développeurs peuvent créer leur propre extension ou des fonctionnalités supplémentaires qui aideront à:

  • ajouter de nouvelles entités — blocs ou modificateurs de texte;
  • configurer davantage le parseur markdown;
  • ajouter des actions permettant de piloter l’éditeur de l’extérieur;
  • enrichir les fonctionnalités de l’interface, par exemple afficher un menu des commandes disponibles lors de la saisie d’un slash;
  • modifier le comportement actuel, par exemple insérer des images et des fichiers et les téléverser dans un stockage.

Voici une série d’exemples de telles extensions que nous avons développées pour notre Wiki:

  • mode d’édition collaborative;
Full screen image
Full screen image
Full screen image
Full screen image
  • inclusions;
Full screen image
  • structure de section;
Full screen image
  • sections pour créer une grille pratique;
Full screen image
  • mode markdown avec aperçu;
Full screen image
  • et bien d’autres.
Full screen image

Le balisage peut être transformé automatiquement. Si vous préférez travailler sans souris, le mode éditeur visuel propose des symboles spéciaux permettant d’appliquer le balisage directement dans le texte. Par exemple, ** met le texte en gras en mode WYSIWYG. Avec ces symboles, on peut mettre en forme le texte et créer du code inline et des blocs de code.

On peut aussi appeler le menu des extensions en saisissant le symbole /.

Full screen image

Presets

L’éditeur permet de configurer la barre d’outils pour chaque projet séparément, mais il est livré avec plusieurs configurations prêtes à l’emploi — des presets.

Éditeur sans presets:

Full screen image

Le preset CommonMark prend en charge les éléments markdown standard: gras, italique, titres, listes, liens, citations et blocs de code.

Full screen image

Dans le preset par défaut apparaît également le texte barré, ainsi qu’un tableau dont les cellules ne peuvent contenir que du texte. Ce preset correspond au markdown-it standard.

Full screen image

Comme indiqué plus haut, l’éditeur prend aussi en charge YFM, il s’intègre donc parfaitement à Diplodoc. Dans le preset YFM apparaissent des éléments supplémentaires: tableaux avancés, insertion de fichiers et d’images, cases à cocher, cut, onglets, police monospace.

Full screen image

Le preset complet contient encore plus d’éléments.

Full screen image

Architecture

Au cœur de l’éditeur en mode WYSIWYG se trouve la célèbre bibliothèque ProseMirror, et pour le balisage, on utilise CodeMirror. ProseMirror prend en charge l’édition avec mise en forme, tandis que CodeMirror est adapté aux situations où il faut travailler avec du texte non balisé.

Nous avons choisi précisément ces bibliothèques parce qu’elles ont été développées par le même auteur, partagent une architecture et des approches de mise en œuvre cohérentes, sont soutenues par une grande communauté, sont utilisées dans de nombreux éditeurs et sont bien optimisées pour le travail sur le texte. Par exemple: un système de transactions pour appliquer des modifications au document, des décorations pour la vue, la virtualisation du DOM, ou encore la prise en charge de la syntaxe de nombreux langages de programmation.

Intégration

Notre éditeur se connecte facilement comme hook React:


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} />;
}

Nous utilisons des composants de la bibliothèque uikit de GravityUI. Cela garantit que toute l’interface est cohérente et respecte des guides de style unifiés. L’utilisation de ces composants assure également un haut degré d’harmonisation et de reconnaissance pour les utilisateurs, ce qui rend le travail avec l’éditeur encore plus confortable.

Nous avons des instructions détaillées sur la manière d’intégrer l’éditeur dans une application React, ainsi que sur la façon de connecter différents types d’extensions: par exemple, YandexGPT, Mermaid ou LaTeX.

Intégration d’extensions sur mesure

Un certain nombre d’extensions supplémentaires est déjà intégré à l’éditeur. Mais si cela ne suffit pas, les développeurs peuvent ajouter leurs propres extensions au mode WYSIWYG de l’éditeur. Nous avons évoqué plus haut ce que les extensions peuvent apporter.

Si vous souhaitez ajouter un nouveau bloc ou un modificateur de texte, il faut d’abord configurer l’instance interne de markdown-it via la méthode configureMd. Ensuite, il faut ajouter la connaissance de la nouvelle entité à l’aide des méthodes addNode ou addMark, en passant le nom de l’entité et une fonction callback qui renvoie un objet avec trois champs obligatoires:

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 — spécification pour ProseMirror;
  • fromMd — configuration de parsing du balisage markdown vers la représentation interne dans ProseMirror;
  • toMd — configuration de sérialisation de l’entité vers le balisage markdown.

Par exemple, ci-dessous se trouve la configuration d’une extension pour le texte souligné. Elle peut être enrichie en ajoutant une action via la méthode addAction:

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)),
      })
  )

Une telle action peut être appelée dans le code comme suit:

// editor – instance de l’éditeur obtenue via l’appel à useMarkdownEditor
editor.actions.underline.run(),

Dans la documentation, vous pouvez consulter le guide complet pour créer une nouvelle extension.


Nous élargissons constamment les horizons d’utilisation de notre éditeur: nous travaillons actuellement sur un plugin pour VS Code qui permettra de travailler avec des fichiers md en mode WYSIWYG pratique directement depuis l’éditeur. Nous prévoyons également d’ajouter un mode mobile complet. Cela permettra à chaque utilisateur de travailler dans notre éditeur en n’ayant sous la main qu’un téléphone mobile.

Notre éditeur n’est pas apparu instantanément: c’est le résultat d’une accumulation d’expérience et de connaissances. Nous sommes fiers que l’éditeur repose entièrement sur des produits open source, y compris des outils fiables et éprouvés tels que ProseMirror, CodeMirror, markdown-it, ainsi que nos propres développements — Diplodoc et Gravity UI.

Vous pouvez toujours contribuer au développement de l’éditeur: créer une pull request ou aider à résoudre les problèmes en cours listés dans la section Issues. Votre soutien et un regard neuf nous aideront à améliorer l’éditeur. Et si vous trouvez notre projet utile, mettez une étoile à notre dépôt GitHub — c’est précieux :)

Éditeur Markdown: un éditeur WYSIWYG et de balisage construit sur Gravity UI

Sign in to save this post