Ein auf React und Prosemirror basierender Editor, der Outline unterstützt und auch zum schreibgeschützten Anzeigen von Inhalten verwendet werden kann. Der Editor ist WYSIWYG und enthält Formatierungswerkzeuge, bietet aber weiterhin die Möglichkeit, Markdown-Verknüpfungen inline zu schreiben und einfachen Markdown auszugeben. Sehen Sie sich das Live-Demo-Storybook an.
Wichtiger Hinweis: Dieses Projekt soll kein Allzweck-Markdown-Editor sein . Es wurde für die Outline-Wissensdatenbank entwickelt, und während andere dieses Paket gerne abzweigen oder in Ihren eigenen Produkten verwenden können, konzentrieren sich Entwicklungsentscheidungen auf die Bedürfnisse von Outline.
yarn add rich-markdown-editor
oder
npm install rich-markdown-editor
Beachten Sie, dass react
, react-dom
und styled-components
erforderliche Peer-Abhängigkeiten sind.
import Editor from "rich-markdown-editor" ;
< Editor
defaultValue = "Hello world!"
/>
Klonen Sie dieses Repo und führen Sie das Storybook mit yarn start
aus, um eine Vielzahl von Anwendungsbeispielen zu sehen.
id
Eine eindeutige ID für diesen Editor, die zum Beibehalten von Einstellungen im lokalen Speicher verwendet wird. Wenn keine id
übergeben wird, verwendet der Editor standardmäßig den Pfadnamen des Standorts.
defaultValue
Eine Markdown-Zeichenfolge, die den Anfangswert des Editors darstellt. Verwenden Sie dies, um zuvor gespeicherte Inhalte wiederherzustellen, damit der Benutzer die Bearbeitung fortsetzen kann.
value
Eine Markdown-Zeichenfolge, die den Wert des Editors darstellt. Verwenden Sie diese Requisite, um den Wert des Editors nach dem Mounten zu ändern. Dadurch wird der gesamte Editor neu gerendert und ist daher nur im readOnly
Modus geeignet. Leiten Sie den Wert von onChange
nicht zurück in value
weiter, da der Editor seinen eigenen internen Status behält und dies zu unerwarteten Nebenwirkungen führt.
placeholder
Ermöglicht das Überschreiben des Platzhalters. Die Standardeinstellung ist „Schreibe etwas Schönes…“.
readOnly
Wenn readOnly
auf false
gesetzt ist, ist der Editor für die Komposition optimiert. Bei true
kann der Editor verwendet werden, um zuvor geschriebene Inhalte anzuzeigen – Überschriften erhalten Anker und Links werden anklickbar.
readOnlyWriteCheckboxes
Wenn readOnlyWriteCheckboxes
auf true
gesetzt ist, können Kontrollkästchen als Sonderfall weiterhin aktiviert oder deaktiviert werden, während readOnly
auf true
gesetzt ist und der Editor ansonsten nicht bearbeitet werden kann.
autoFocus
Wenn true
zusammen mit readOnly
auf false
gesetzt ist, wird der Fokus automatisch auf das Ende des Dokuments gesetzt.
maxLength
Wenn diese Einstellung festgelegt ist, wird eine maximale Zeichenlänge für das Dokument erzwungen, ohne Markdown-Syntax.
extensions
Ermöglicht die Übergabe zusätzlicher Prosemirror-Plugins an die zugrunde liegende Prosemirror-Instanz.
disableExtensions
Liste der enthaltenen Erweiterungsnamen, die deaktiviert werden sollen. Entfernt entsprechende Menüelemente und Befehle. Setzen Sie ihn beispielsweise auf ["em", "blockquote"]
um kursiven Text und Blockzitate zu deaktivieren.
theme
Ermöglicht das Überschreiben des integrierten Designs, um den Editor zu kennzeichnen. Verwenden Sie beispielsweise Ihre eigene Schriftart und Markenfarben, damit der Editor in Ihre Anwendung passt. Ein Beispiel für die Schlüssel, die bereitgestellt werden sollten, finden Sie im integrierten Design.
dictionary
Ermöglicht das Überschreiben des integrierten Kopierwörterbuchs, um beispielsweise den Editor zu internationalisieren. Ein Beispiel für die Schlüssel, die bereitgestellt werden sollten, finden Sie im integrierten Wörterbuch.
dark
Wenn dark
auf true
gesetzt ist, verwendet der Editor ein standardmäßiges dunkles Design, das enthalten ist. Die Quelle finden Sie hier.
dir
Standard: auto
Steuert die Richtung des Dokuments. Mögliche Werte sind:
ltr
: Das Editor-Layout ist für LTR-Dokumente optimiert und der Inhalt ist explizit als LTR gekennzeichnet.rtl
: Das Editor-Layout ist für RTL-Dokumente optimiert und der Inhalt ist explizit als RTL gekennzeichnet.auto
: Das Editor-Layout wird vom Browser basierend auf dem Dokumentinhalt festgelegt. tooltip
Eine React-Komponente, die um Elemente gewickelt wird, die über einen optionalen Tooltip verfügen. Damit können Sie Ihre eigene Tooltip-Bibliothek in den Editor einfügen – der Komponente werden die folgenden Requisiten übergeben:
tooltip
: Ein React-Knoten mit dem Tooltip-Inhaltplacement
: Aufzählung top
, bottom
, left
, right
children
: Die Komponente, die der Tooltip umschließt, muss gerendert werden headingsOffset
Eine Zahl, die die Dokumentüberschriften um mehrere Ebenen versetzt. Wenn Sie den Editor beispielsweise bereits unter einem h1
Haupttitel verschachteln, möchten Sie möglicherweise, dass der Benutzer nur h2
Überschriften und darunter erstellen kann. In diesem Fall würden Sie die Requisite auf 1
setzen.
scrollTo
Eine Zeichenfolge, die einen Überschriftenanker darstellt – das Dokument führt einen sanften Bildlauf durch, sodass die Überschrift im Ansichtsfenster sichtbar ist.
embeds
Definieren Sie optional Einbettungen, die anstelle von Links eingefügt werden, wenn die matcher
-Funktion einen wahrheitsgetreuen Wert zurückgibt. Der Rückgabewert der Matcher-Methode ist in der Komponente unter props.attrs.matches
verfügbar. Wenn title
und icon
angegeben werden, erscheint die Einbettung auch im Blockmenü.
< 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>
Wenn Sie möchten, dass der Editor Bilder unterstützt, muss dieser Rückruf bereitgestellt werden. Der Rückruf sollte ein einzelnes File
akzeptieren und ein Versprechen zurückgeben, das in eine URL aufgelöst wird, wenn das Bild an einen Speicherort, beispielsweise S3, hochgeladen wurde. z.B:
< Editor
uploadImage = { async file => {
const result = await s3 . upload ( file ) ;
return result . url ;
} }
/>
onBlur(): void
Dieser Rückruf wird ausgelöst, wenn der Benutzer den Fokus auf den Editor contenteditable und alle zugehörigen UI-Elemente wie das Blockmenü und schwebende Symbolleisten verliert. Wenn Sie nur im inhaltsbearbeitbaren Bereich auf Unschärfeereignisse warten möchten, verwenden Sie handleDOMEvents
Requisiten.
onFocus(): void
Dieser Rückruf wird ausgelöst, wenn der Benutzer den Fokus auf den Editor contenteditable oder alle zugehörigen UI-Elemente wie das Blockmenü oder schwebende Symbolleisten richtet. Wenn Sie nur im inhaltsbearbeitbaren Bereich auf Fokusereignisse warten möchten, verwenden Sie handleDOMEvents
Requisiten.
onSave({ done: boolean }): void
Dieser Rückruf wird ausgelöst, wenn der Benutzer explizit das Speichern über die Tastenkombination Cmd+S
oder Cmd+Enter
anfordert. Sie können dies als Signal verwenden, um das Dokument auf einem Remote-Server zu speichern.
onCancel(): void
Dieser Rückruf wird ausgelöst, wenn im Editor Cmd+Escape
gedrückt wird. Sie können damit die Bearbeitung abbrechen.
onChange(() => value): void
Dieser Rückruf wird ausgelöst, wenn sich der Inhalt des Editors ändert, normalerweise aufgrund von Benutzereingaben wie einem Tastendruck oder der Verwendung von Formatierungsoptionen. Sie können dies verwenden, um den Editorstatus lokal beizubehalten.
Es gibt eine Funktion zurück, die beim Aufruf den aktuellen Textwert des Dokuments zurückgibt. Diese Optimierung wird vorgenommen, um zu vermeiden, dass der Status des Dokuments bei jedem Änderungsereignis in Text umgewandelt wird, sodass die Host-App auswählen kann, wann sie den serialisierten Wert benötigt.
onImageUploadStart(): void
Dieser Rückruf wird vor uploadImage
ausgelöst und kann verwendet werden, um eine Benutzeroberfläche anzuzeigen, die anzeigt, dass ein Upload ausgeführt wird.
onImageUploadStop(): void
Wird ausgelöst, sobald ein Bild-Upload erfolgreich war oder fehlgeschlagen ist.
onSearchLink(term: string): Promise<{ title: string, subtitle?: string, url: string }[]>
Der Editor bietet die Möglichkeit, nach Links zu suchen, die über die Formatierungssymbolleiste eingefügt werden können. Wenn dieser Rückruf bereitgestellt wird, sollte er einen Suchbegriff als einzigen Parameter akzeptieren und ein Versprechen zurückgeben, das in ein Array von Objekten aufgelöst wird. z.B:
< 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>
Der Editor bietet die Möglichkeit, Links über die Formatierungssymbolleiste zu erstellen, um Dokumente im Handumdrehen zu erstellen. Wenn dieser Rückruf bereitgestellt wird, sollte er einen Link-„Titel“ als einzigen Parameter akzeptieren und ein Versprechen zurückgeben, das in eine URL für den erstellten Link aufgelöst wird, z. B.:
< Editor
onCreateLink = { async title => {
const url = await MyAPI . create ( {
title
} ) ;
return url ;
} }
/>
onShowToast(message: string, type: ToastType): void
Wird ausgelöst, wenn der Editor dem Benutzer eine Nachricht anzeigen möchte. Schließen Sie sich an das Benachrichtigungssystem Ihrer App an oder verwenden Sie ganz einfach window.alert(message)
. Der zweite Parameter ist die Art des Toasts: „error“ oder „info“.
onClickLink(href: string, event: MouseEvent): void
Dieser Rückruf ermöglicht das Überschreiben der Linkbehandlung. Es ist oft der Fall, dass Sie möchten, dass externe Links ein neues Fenster öffnen und interne Links so etwas wie react-router
zum Navigieren verwenden. Wenn kein Rückruf bereitgestellt wird, gilt für alle Links das Standardverhalten beim Öffnen eines neuen Tabs. z.B:
import { history } from "react-router" ;
< Editor
onClickLink = { ( href , event ) => {
if ( isInternalLink ( href ) ) {
history . push ( href ) ;
} else {
window . location . href = href ;
}
} }
/>
onHoverLink(event: MouseEvent): boolean
Dieser Rückruf ermöglicht die Erkennung, wenn der Benutzer mit der Maus über einen Link im Dokument fährt.
< Editor
onHoverLink = { event => {
console . log ( `Hovered link ${ event . target . href } ` ) ;
} }
/>
onClickHashtag(tag: string, event: MouseEvent): void
Dieser Rückruf ermöglicht die Handhabung des Klickens auf Hashtags im Dokumenttext. Wenn kein Rückruf bereitgestellt wird, werden Hashtags als normaler Text gerendert, sodass Sie durch Übergabe dieser Requisite auswählen können, ob sie unterstützt werden sollen oder nicht.
import { history } from "react-router" ;
< Editor
onClickHashtag = { tag => {
history . push ( `/hashtags/ ${ tag } ` ) ;
} }
/>
handleDOMEvents: {[name: string]: (view: EditorView, event: Event) => boolean;}
Dieses Objekt ordnet Ereignisnamen ( focus
, paste
, touchstart
usw.) Callback-Funktionen zu.
< Editor
handleDOMEvents = { {
focus : ( ) => console . log ( "FOCUS" ) ,
blur : ( ) => console . log ( "BLUR" ) ,
paste : ( ) => console . log ( "PASTE" ) ,
touchstart : ( ) => console . log ( "TOUCH START" ) ,
} }
/>
Die Editor-Komponente stellt einige Methoden für die Interaktion mit dem bereitgestellten Editor bereit.
focusAtStart(): void
Platzieren Sie den Cursor am Anfang des Dokuments und fokussieren Sie ihn.
focusAtEnd(): void
Platzieren Sie den Cursor am Ende des Dokuments und fokussieren Sie ihn.
getHeadings(): { title: string, level: number, id: string }[]
Gibt ein Array von Objekten mit dem Textinhalt aller Überschriften im Dokument, ihrer Ebene in der Hierarchie und der Anker-ID zurück. Dies ist nützlich, um Ihr eigenes Inhaltsverzeichnis zu erstellen, da die toc
-Option in Version 10 entfernt wurde.
Dieses Projekt verwendet Garn, um Abhängigkeiten zu verwalten. Sie können npm verwenden, es berücksichtigt jedoch nicht die Garnsperrdatei und installiert möglicherweise leicht unterschiedliche Versionen.
yarn install
Bei der Ausführung in der Entwicklung ist Storybook mit Hot-Reloading in Beispieleditoren integriert. Führen Sie nach der Installation der Abhängigkeiten yarn start
aus, um loszulegen.
Wenn Sie bei der Entwicklung mit yarn link
arbeiten, können Sie yarn watch
verwenden, um Änderungen kontinuierlich in dist
umzuwandeln, während Sie Änderungen vornehmen.
Dieses Projekt ist BSD-lizenziert.