Un éditeur basé sur React et Prosemirror qui alimente Outline et peut également être utilisé pour afficher du contenu en lecture seule. L'éditeur est WYSIWYG et comprend des outils de formatage tout en conservant la possibilité d'écrire des raccourcis markdown en ligne et de produire du Markdown brut. Voir le livre d'histoires de la démonstration en direct .
Remarque importante : ce projet ne tente pas d'être un éditeur Markdown polyvalent . Il est construit pour la base de connaissances Outline, et tandis que d'autres sont invités à utiliser ou à utiliser ce package dans vos propres produits, les décisions de développement sont centrées sur les besoins d'Outline.
yarn add rich-markdown-editorou
npm install rich-markdown-editor Notez que les composants react , react-dom et styled-components sont des dépendances homologues obligatoires .
import Editor from "rich-markdown-editor" ;
< Editor
defaultValue = "Hello world!"
/> Clonez ce dépôt et exécutez le Storybook avec yarn start pour voir une grande variété d'exemples d'utilisation.
id Un identifiant unique pour cet éditeur, utilisé pour conserver les paramètres dans le stockage local. Si aucun id n’est transmis, l’éditeur utilisera par défaut le chemin d’accès de l’emplacement.
defaultValueUne chaîne de démarque qui représente la valeur initiale de l'éditeur. Utilisez-le pour restaurer le contenu précédemment enregistré afin que l'utilisateur puisse continuer à le modifier.
value Une chaîne de démarque qui représente la valeur de l'éditeur. Utilisez cet accessoire pour modifier la valeur de l'éditeur une fois monté, cela restituera l'intégralité de l'éditeur et, en tant que tel, ne convient qu'en mode readOnly seule. Ne redirigez pas la valeur de onChange vers value , l'éditeur conserve son propre état interne, ce qui entraînerait des effets secondaires inattendus.
placeholderPermet de remplacer l'espace réservé. La valeur par défaut est « Écrivez quelque chose de sympa… ».
readOnly Avec readOnly défini sur false l'éditeur est optimisé pour la composition. Lorsque true l'éditeur peut être utilisé pour afficher le contenu précédemment écrit – les titres obtiennent des ancres et les liens deviennent cliquables.
readOnlyWriteCheckboxes Avec readOnlyWriteCheckboxes défini sur true les cases à cocher peuvent toujours être cochées ou décochées dans un cas particulier tandis que readOnly est défini sur true et l'éditeur ne peut pas être modifié autrement.
autoFocus Lorsqu'il est défini sur true avec readOnly défini sur false , se concentre automatiquement sur la fin du document.
maxLengthLorsqu'il est défini, il applique une longueur maximale de caractères sur le document, sans inclure la syntaxe de démarque.
extensionsPermet de transmettre des plugins Prosemirror supplémentaires à l'instance Prosemirror sous-jacente.
disableExtensions Liste des noms d'extensions inclus à désactiver. Supprime les éléments de menu et les commandes correspondants. Par exemple, réglé sur ["em", "blockquote"] pour désactiver le texte en italique et les guillemets.
themePermet de remplacer le thème intégré pour personnaliser l'éditeur, par exemple en utilisant votre propre police et les couleurs de votre marque pour que l'éditeur s'intègre dans votre application. Voir le thème intégré pour un exemple des clés qui doivent être fournies.
dictionaryPermet de remplacer le dictionnaire de copie intégré, par exemple pour internationaliser l'éditeur. Consultez le dictionnaire intégré pour un exemple des clés qui doivent être fournies.
dark Avec dark défini sur true l'éditeur utilisera un thème sombre par défaut inclus. Voir la source ici.
dir Par défaut : auto
Contrôle la direction du document. Les valeurs possibles sont :
ltr : la mise en page de l'éditeur est optimisée pour les documents LTR et le contenu est explicitement marqué comme LTR.rtl : la mise en page de l'éditeur est optimisée pour les documents RTL et le contenu est explicitement marqué comme RTL.auto : la disposition de l'éditeur est décidée par le navigateur en fonction du contenu du document. tooltipUn composant React qui sera enroulé autour des éléments dotés d'une info-bulle facultative. Vous pouvez l'utiliser pour injecter votre propre bibliothèque d'info-bulles dans l'éditeur – le composant recevra les accessoires suivants :
tooltip : Un nœud React avec le contenu de l'info-bulleplacement : Enum top , bottom , left , rightchildren : Le composant que l'info-bulle encapsule doit être rendu headingsOffset Un nombre qui décalera les titres du document d'un certain nombre de niveaux. Par exemple, si vous imbriquez déjà l'éditeur sous un titre h1 principal, vous souhaiterez peut-être que l'utilisateur ne puisse créer que des titres h2 et ci-dessous, dans ce cas, vous définirez l'accessoire sur 1 .
scrollToUne chaîne représentant une ancre de titre – le document défilera en douceur afin que le titre soit visible dans la fenêtre.
embeds Définissez éventuellement des intégrations qui seront insérées à la place des liens lorsque la fonction matcher renvoie une valeur véridique. La valeur de retour de la méthode matcher sera disponible sur le composant sous props.attrs.matches . Si title et icon sont fournis, l'intégration apparaîtra également dans le menu de bloc.
< Editor
embeds = { [
{
title : "Google Doc" ,
keywords : "google docs gdocs" ,
icon : < GoogleDocIcon /> ,
defaultHidden : false ,
matcher : href => href . matches ( / docs.google.com / i ) ,
component : GoogleDocEmbed
}
] }
/>uploadImage(file: Blob): Promise<string> Si vous souhaitez que l'éditeur prenne en charge les images, ce rappel doit être fourni. Le rappel doit accepter un seul objet File et renvoyer une promesse qui se résout dans une URL lorsque l'image a été téléchargée vers un emplacement de stockage, par exemple S3. par exemple :
< Editor
uploadImage = { async file => {
const result = await s3 . upload ( file ) ;
return result . url ;
} }
/> onBlur(): void Ce rappel est déclenché lorsque l'utilisateur perd le focus sur l'éditeur contenteditable et tous les éléments d'interface utilisateur associés tels que le menu de bloc et les barres d'outils flottantes. Si vous souhaitez écouter les événements de flou uniquement sur la zone modifiable, utilisez les accessoires handleDOMEvents .
onFocus(): void Ce rappel est déclenché lorsque l'utilisateur se concentre sur l'éditeur contenteditable ou sur tout élément d'interface utilisateur associé tel que le menu de bloc ou les barres d'outils flottantes. Si vous souhaitez écouter les événements de focus uniquement sur la zone contenteditable, utilisez les accessoires handleDOMEvents .
onSave({ done: boolean }): void Ce rappel est déclenché lorsque l'utilisateur demande explicitement d'enregistrer à l'aide d'un raccourci clavier, Cmd+S ou Cmd+Enter . Vous pouvez l'utiliser comme signal pour enregistrer le document sur un serveur distant.
onCancel(): void Ce rappel est déclenché lorsque Cmd+Escape est appuyé dans l'éditeur. Vous pouvez l'utiliser pour annuler l'édition.
onChange(() => value): voidCe rappel est déclenché lorsque le contenu de l'éditeur change, généralement en raison d'une saisie de l'utilisateur telle qu'une frappe au clavier ou de l'utilisation d'options de formatage. Vous pouvez l'utiliser pour conserver localement l'état des éditeurs.
Il renvoie une fonction qui, lorsqu'elle est appelée, renvoie la valeur texte actuelle du document. Cette optimisation vise à éviter de sérialiser l'état du document en texte à chaque événement de modification, permettant ainsi à l'application hôte de choisir quand elle a besoin de la valeur sérialisée.
onImageUploadStart(): void Ce rappel est déclenché avant uploadImage et peut être utilisé pour afficher une interface utilisateur indiquant qu'un téléchargement est en cours.
onImageUploadStop(): voidDéclenché une fois qu'un téléchargement d'image a réussi ou échoué.
onSearchLink(term: string): Promise<{ title: string, subtitle?: string, url: string }[]>L'éditeur offre la possibilité de rechercher des liens à insérer à partir de la barre d'outils de formatage. Si ce rappel est fourni, il doit accepter un terme de recherche comme seul paramètre et renvoyer une promesse qui se résout en un tableau d'objets. par exemple :
< Editor
onSearchLink = { async searchTerm => {
const results = await MyAPI . search ( searchTerm ) ;
return results . map ( result => {
title : result . name ,
subtitle : `Created ${ result . createdAt } ` ,
url : result . url
} )
} }
/> onCreateLink(title: string): Promise<string>L'éditeur offre la possibilité de créer des liens à partir de la barre d'outils de formatage pour la création de documents à la volée. Si ce rappel est fourni, il doit accepter un lien "titre" comme seul paramètre et renvoyer une promesse qui se résout en une URL pour le lien créé, par exemple :
< Editor
onCreateLink = { async title => {
const url = await MyAPI . create ( {
title
} ) ;
return url ;
} }
/> onShowToast(message: string, type: ToastType): void Déclenché lorsque l'éditeur souhaite afficher un message à l'utilisateur. Connectez-vous au système de notification de votre application ou utilisez de manière simple window.alert(message) . Le deuxième paramètre est le type de toast : « erreur » ou « info ».
onClickLink(href: string, event: MouseEvent): void Ce rappel permet de remplacer la gestion des liens. Il arrive souvent que vous souhaitiez que les liens externes ouvrent une nouvelle fenêtre et que les liens internes utilisent quelque chose comme react-router pour naviguer. Si aucun rappel n'est fourni, le comportement par défaut d'ouverture d'un nouvel onglet s'appliquera à tous les liens. par exemple :
import { history } from "react-router" ;
< Editor
onClickLink = { ( href , event ) => {
if ( isInternalLink ( href ) ) {
history . push ( href ) ;
} else {
window . location . href = href ;
}
} }
/> onHoverLink(event: MouseEvent): booleanCe rappel permet de détecter lorsque l'utilisateur survole un lien dans le document.
< Editor
onHoverLink = { event => {
console . log ( `Hovered link ${ event . target . href } ` ) ;
} }
/> onClickHashtag(tag: string, event: MouseEvent): voidCe rappel permet de gérer le clic sur les hashtags dans le texte du document. Si aucun rappel n'est fourni, les hashtags seront affichés sous forme de texte normal, vous pouvez donc choisir de les prendre en charge ou non en passant cet accessoire.
import { history } from "react-router" ;
< Editor
onClickHashtag = { tag => {
history . push ( `/hashtags/ ${ tag } ` ) ;
} }
/> handleDOMEvents: {[name: string]: (view: EditorView, event: Event) => boolean;} Cet objet mappe les noms d'événements ( focus , paste , touchstart , etc.) aux fonctions de rappel.
< Editor
handleDOMEvents = { {
focus : ( ) => console . log ( "FOCUS" ) ,
blur : ( ) => console . log ( "BLUR" ) ,
paste : ( ) => console . log ( "PASTE" ) ,
touchstart : ( ) => console . log ( "TOUCH START" ) ,
} }
/>Le composant Editor expose quelques méthodes pour interagir avec l’éditeur monté.
focusAtStart(): voidPlacez le curseur au début du document et concentrez-le.
focusAtEnd(): voidPlacez le curseur à la fin du document et concentrez-le.
getHeadings(): { title: string, level: number, id: string }[] Renvoie un tableau d'objets avec le contenu textuel de tous les titres du document, leur niveau dans la hiérarchie et l'identifiant de l'ancre. Ceci est utile pour construire votre propre table des matières puisque l'option toc a été supprimée dans la v10.
Ce projet utilise du fil pour gérer les dépendances. Vous pouvez utiliser npm mais il ne respectera pas le fichier Yarn Lock et pourra installer des versions légèrement différentes.
yarn install
Lors de l'exécution en développement, Storybook est inclus dans les exemples d'éditeurs avec rechargement à chaud. Après avoir installé les dépendances, exécutez yarn start pour démarrer.
Lors du développement à l'aide yarn link , vous pouvez utiliser yarn watch pour reconstruire continuellement les modifications en dist à mesure que vous apportez des modifications.
Ce projet est sous licence BSD.