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-editor
ou
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.
defaultValue
Une 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.
placeholder
Permet 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.
maxLength
Lorsqu'il est défini, il applique une longueur maximale de caractères sur le document, sans inclure la syntaxe de démarque.
extensions
Permet 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.
theme
Permet 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.
dictionary
Permet 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. tooltip
Un 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
, right
children
: 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
.
scrollTo
Une 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): void
Ce 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(): void
Dé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): boolean
Ce 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): void
Ce 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(): void
Placez le curseur au début du document et concentrez-le.
focusAtEnd(): void
Placez 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.