https://github.com/outline/rich-markdown-editor

The open source React and Prosemirror based markdown editor that powers Outline. Want to try it out? Create an account:

https://github.com/outline/rich-markdown-editor

Science Score: 10.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
  • .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
    1 of 48 committers (2.1%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.0%) to scientific vocabulary

Keywords

editor hacktoberfest javascript markdown prosemirror wysiwyg wysiwyg-editor

Keywords from Contributors

data-profilers datacleaner pipeline-testing interactive projection sequences transformers distribution charts network-simulation
Last synced: 5 months ago · JSON representation

Repository

The open source React and Prosemirror based markdown editor that powers Outline. Want to try it out? Create an account:

Basic Info
  • Host: GitHub
  • Owner: outline
  • License: bsd-3-clause
  • Language: TypeScript
  • Default Branch: main
  • Homepage: https://www.getoutline.com
  • Size: 3.26 MB
Statistics
  • Stars: 2,915
  • Watchers: 36
  • Forks: 589
  • Open Issues: 35
  • Releases: 20
Archived
Topics
editor hacktoberfest javascript markdown prosemirror wysiwyg wysiwyg-editor
Created almost 8 years ago · Last pushed about 4 years ago
Metadata Files
Readme Funding License

README.md

npm version CircleCI Formatted with Prettier TypeScript Sponsor

rich-markdown-editor

A React and Prosemirror based editor that powers Outline and can also be used for displaying content in a read-only fashion. The editor is WYSIWYG and includes formatting tools whilst retaining the ability to write markdown shortcuts inline and output plain Markdown. See the Live demo storybook.

Important Note: This project is not attempting to be an all-purpose Markdown editor. It is built for the Outline knowledge base, and whilst others are welcome to fork or use this package in your own products, development decisions are centered around the needs of Outline.

Usage

Install

bash yarn add rich-markdown-editor

or

bash npm install rich-markdown-editor

Note that react, react-dom, and styled-components are required peer dependencies.

Import

```javascript import Editor from "rich-markdown-editor";

```

Clone this repo and run the Storybook with yarn start to see a wide variety of example usage.

Props

id

A unique id for this editor, used to persist settings in local storage. If no id is passed then the editor will default to using the location pathname.

defaultValue

A markdown string that represents the initial value of the editor. Use this to prop to restore previously saved content for the user to continue editing.

value

A markdown string that represents the value of the editor. Use this prop to change the value of the editor once mounted, this will re-render the entire editor and as such is only suitable when also in readOnly mode. Do not pipe the value of onChange back into value, the editor keeps it's own internal state and this will result in unexpected side effects.

placeholder

Allows overriding of the placeholder. The default is "Write something nice…".

readOnly

With readOnly set to false the editor is optimized for composition. When true the editor can be used to display previously written content – headings gain anchors and links become clickable.

readOnlyWriteCheckboxes

With readOnlyWriteCheckboxes set to true checkboxes can still be checked or unchecked as a special case while readOnly is set to true and the editor is otherwise unable to be edited.

autoFocus

When set true together with readOnly set to false, focus at the end of the document automatically.

maxLength

When set enforces a maximum character length on the document, not including markdown syntax.

extensions

Allows additional Prosemirror plugins to be passed to the underlying Prosemirror instance.

disableExtensions

List of included extension names to disable. Removes corresponding menu items and commands. E.g. set to ["em", "blockquote"] to disable italic text and blockquotes.

theme

Allows overriding the inbuilt theme to brand the editor, for example use your own font face and brand colors to have the editor fit within your application. See the inbuilt theme for an example of the keys that should be provided.

dictionary

Allows overriding the inbuilt copy dictionary, for example to internationalize the editor. See the inbuilt dictionary for an example of the keys that should be provided.

dark

With dark set to true the editor will use a default dark theme that's included. See the source here.

dir

Default: auto

Controls direction of the document. Possible values are: - ltr: Editor layout is optimized for LTR documents and the content is explicitly marked as LTR. - rtl: Editor layout is optimized for RTL documents and the content is explicitly marked as RTL. - auto: Editor layout is decided by the browser based on document content.

tooltip

A React component that will be wrapped around items that have an optional tooltip. You can use this to inject your own tooltip library into the editor – the component will be passed the following props:

  • tooltip: A React node with the tooltip content
  • placement: Enum top, bottom, left, right
  • children: The component that the tooltip wraps, must be rendered

headingsOffset

A number that will offset the document headings by a number of levels. For example, if you already nest the editor under a main h1 title you might want the user to only be able to create h2 headings and below, in this case you would set the prop to 1.

scrollTo

A string representing a heading anchor – the document will smooth scroll so that the heading is visible in the viewport.

embeds

Optionally define embeds which will be inserted in place of links when the matcher function returns a truthy value. The matcher method's return value will be available on the component under props.attrs.matches. If title and icon are provided then the embed will also appear in the block menu.

javascript <Editor embeds={[ { title: "Google Doc", keywords: "google docs gdocs", icon: <GoogleDocIcon />, defaultHidden: false, matcher: href => href.matches(/docs.google.com/i), component: GoogleDocEmbed } ]} />

Callbacks

uploadImage(file: Blob): Promise<string>

If you want the editor to support images then this callback must be provided. The callback should accept a single File object and return a promise the resolves to a url when the image has been uploaded to a storage location, for example S3. eg:

javascript <Editor uploadImage={async file => { const result = await s3.upload(file); return result.url; }} />

onBlur(): void

This callback is triggered when the user loses focus on the editor contenteditable and all associated UI elements such as the block menu and floating toolbars. If you want to listen for blur events on only the contenteditable area then use handleDOMEvents props.

onFocus(): void

This callback is triggered when the user gains focus on the editor contenteditable or any associated UI elements such as the block menu or floating toolbars. If you want to listen for focus events on only the contenteditable area then use handleDOMEvents props.

onSave({ done: boolean }): void

This callback is triggered when the user explicitly requests to save using a keyboard shortcut, Cmd+S or Cmd+Enter. You can use this as a signal to save the document to a remote server.

onCancel(): void

This callback is triggered when the Cmd+Escape is hit within the editor. You may use it to cancel editing.

onChange(() => value): void

This callback is triggered when the contents of the editor changes, usually due to user input such as a keystroke or using formatting options. You may use this to locally persist the editors state.

It returns a function which when called returns the current text value of the document. This optimization is made to avoid serializing the state of the document to text on every change event, allowing the host app to choose when it needs the serialized value.

onImageUploadStart(): void

This callback is triggered before uploadImage and can be used to show some UI that indicates an upload is in progress.

onImageUploadStop(): void

Triggered once an image upload has succeeded or failed.

onSearchLink(term: string): Promise<{ title: string, subtitle?: string, url: string }[]>

The editor provides an ability to search for links to insert from the formatting toolbar. If this callback is provided it should accept a search term as the only parameter and return a promise that resolves to an array of objects. eg:

```javascript { 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>

The editor provides an ability to create links from the formatting toolbar for on-the-fly document createion. If this callback is provided it should accept a link "title" as the only parameter and return a promise that resolves to a url for the created link, eg:

```javascript { const url = await MyAPI.create({ title });

return url;

}} /> ```

onShowToast(message: string, type: ToastType): void

Triggered when the editor wishes to show a message to the user. Hook into your app's notification system, or simplisticly use window.alert(message). The second parameter is the type of toast: 'error' or 'info'.

onClickLink(href: string, event: MouseEvent): void

This callback allows overriding of link handling. It's often the case that you want to have external links open a new window and have internal links use something like react-router to navigate. If no callback is provided then default behavior of opening a new tab will apply to all links. eg:

```javascript import { history } from "react-router";

{ if (isInternalLink(href)) { history.push(href); } else { window.location.href = href; } }} /> ```

onHoverLink(event: MouseEvent): boolean

This callback allows detecting when the user hovers over a link in the document.

javascript <Editor onHoverLink={event => { console.log(`Hovered link ${event.target.href}`); }} />

onClickHashtag(tag: string, event: MouseEvent): void

This callback allows handling of clicking on hashtags in the document text. If no callback is provided then hashtags will render as regular text, so you can choose if to support them or not by passing this prop.

```javascript import { history } from "react-router";

{ history.push(/hashtags/${tag}); }} /> ```

handleDOMEvents: {[name: string]: (view: EditorView, event: Event) => boolean;}

This object maps event names (focus, paste, touchstart, etc.) to callback functions.

javascript <Editor handleDOMEvents={{ focus: () => console.log("FOCUS"), blur: () => console.log("BLUR"), paste: () => console.log("PASTE"), touchstart: () => console.log("TOUCH START"), }} />

Interface

The Editor component exposes a few methods for interacting with the mounted editor.

focusAtStart(): void

Place the cursor at the start of the document and focus it.

focusAtEnd(): void

Place the cursor at the end of the document and focus it.

getHeadings(): { title: string, level: number, id: string }[]

Returns an array of objects with the text content of all the headings in the document, their level in the hierarchy, and the anchor id. This is useful to construct your own table of contents since the toc option was removed in v10.

Contributing

This project uses yarn to manage dependencies. You can use npm however it will not respect the yarn lock file and may install slightly different versions.

yarn install

When running in development Storybook is included to example editors with hot reloading. After installing dependencies run yarn start to get going.

When developing using yarn link, you can use yarn watch to continuously rebuild on change into dist as you make changes.

License

This project is BSD licensed.

Owner

  • Name: Outline
  • Login: outline
  • Kind: organization
  • Email: hello@getoutline.com
  • Location: United States of America

We're building an open source collaborative knowledge base for modern teams

GitHub Events

Total
  • Watch event: 52
  • Fork event: 9
Last Year
  • Watch event: 52
  • Fork event: 9

Committers

Last synced: 8 months ago

All Time
  • Total Commits: 884
  • Total Committers: 48
  • Avg Commits per committer: 18.417
  • Development Distribution Score (DDS): 0.122
Past Year
  • Commits: 0
  • Committers: 0
  • Avg Commits per committer: 0.0
  • Development Distribution Score (DDS): 0.0
Top Committers
Name Email Commits
Tom Moor t****r@g****m 776
dependabot[bot] 4****] 17
Jori Lallo j****o@g****m 14
Jaap Frolich j****h@g****m 10
Nan Yu t****u@g****m 9
JW j****4@g****m 6
Josh Slate j****e@g****m 5
Saumya Pandey s****9@g****m 4
Philipp Reinking p****p@d****o 2
Min Zhao s****n@g****m 2
Teejay85 t****0@g****m 2
Chris Barnes b****b@g****m 1
Daniel Fürst d****t@g****m 1
David Adeboye d****e@o****m 1
Everaldo Canuto e****o@g****m 1
Fabian Windheuser m****l@f****e 1
Farzad f****e@g****m 1
Gerren Scoon g****n@g****m 1
Charles Harries c****s@h****e 1
Anthony A****r 1
Anish De 6****0 1
André Glatzl a****l@g****m 1
Justin Hopkins j****s@l****m 1
John McDowall j****n@m****o 1
Javier Castro j****o@g****m 1
Andrey Blinov a****f@g****m 1
stefanoimperiale 3****e 1
searchableguy 6****y 1
saresend s****d@u****u 1
cinwell.li c****i@g****m 1
and 18 more...

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 55
  • Total pull requests: 45
  • Average time to close issues: about 2 months
  • Average time to close pull requests: 9 days
  • Total issue authors: 36
  • Total pull request authors: 19
  • Average comments per issue: 1.87
  • Average comments per pull request: 1.56
  • Merged pull requests: 28
  • Bot issues: 2
  • Bot pull requests: 7
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • tommoor (10)
  • Aaron-Hu (4)
  • bjj (3)
  • HT-Moh (3)
  • loun4 (2)
  • arslancharyev31 (2)
  • sentry-io[bot] (2)
  • dmechea (1)
  • mcholcha (1)
  • sklinov (1)
  • jxh0414com (1)
  • icellan (1)
  • gavindoughtie (1)
  • romaad (1)
  • SDAChess (1)
Pull Request Authors
  • tommoor (11)
  • dependabot[bot] (7)
  • JiangWeixian (4)
  • RuslanGabbasov (4)
  • iamsaumya (4)
  • gzuidhof (2)
  • nshelia (1)
  • hadielyakhni (1)
  • AnishDe12020 (1)
  • warnus (1)
  • chanchadsahil7 (1)
  • agustif (1)
  • thenanyu (1)
  • amazingmarvin (1)
  • kevinkong91 (1)
Top Labels
Issue Labels
bug (44) enhancement (9) $$$ (4) more-information-needed (3) duplicate (1) help wanted (1)
Pull Request Labels
dependencies (7)

Dependencies

package.json npm
  • @babel/core ^7.12.16 development
  • @babel/preset-env ^7.12.11 development
  • @babel/preset-react ^7.14.5 development
  • @babel/preset-typescript ^7.12.7 development
  • @storybook/addon-actions ^6.4.9 development
  • @storybook/addon-essentials ^6.4.9 development
  • @storybook/addon-links ^6.4.9 development
  • @storybook/react ^6.4.9 development
  • @types/fuzzy-search ^2.1.1 development
  • @types/jest ^26.0.20 development
  • @types/lodash ^4.14.149 development
  • @types/markdown-it ^10.0.1 development
  • @types/prosemirror-commands ^1.0.1 development
  • @types/prosemirror-dropcursor ^1.0.0 development
  • @types/prosemirror-gapcursor ^1.0.1 development
  • @types/prosemirror-history ^1.0.1 development
  • @types/prosemirror-inputrules ^1.0.2 development
  • @types/prosemirror-keymap ^1.0.1 development
  • @types/prosemirror-markdown ^1.0.3 development
  • @types/prosemirror-model ^1.7.2 development
  • @types/prosemirror-schema-list ^1.0.1 development
  • @types/prosemirror-state ^1.2.4 development
  • @types/prosemirror-view ^1.11.4 development
  • @types/react ^16.9.19 development
  • @types/react-dom ^16.9.5 development
  • @types/refractor ^2.8.0 development
  • @types/styled-components ^5.1.7 development
  • @typescript-eslint/eslint-plugin ^4.15.2 development
  • @typescript-eslint/parser ^4.15.2 development
  • babel-jest ^26.6.3 development
  • babel-loader ^8.2.2 development
  • eslint ^7.20.0 development
  • eslint-config-prettier ^6.15.0 development
  • eslint-config-react-app ^6.0.0 development
  • eslint-plugin-import ^2.22.0 development
  • eslint-plugin-jsx-a11y ^6.4.1 development
  • eslint-plugin-prettier ^3.1.4 development
  • eslint-plugin-react ^7.21.5 development
  • eslint-plugin-react-hooks ^4.0.8 development
  • jest ^26.6.3 development
  • prettier ^1.19.1 development
  • react ^17.0.0 development
  • react-dom ^17.0.0 development
  • source-map-loader ^0.2.4 development
  • styled-components ^5.2.1 development
  • ts-loader ^6.2.1 development
  • tsc-watch ^4.2.9 development
  • typescript 4.1.6 development
  • copy-to-clipboard ^3.0.8
  • fuzzy-search ^3.2.1
  • gemoji 6.x
  • lodash ^4.17.11
  • markdown-it ^12.2.0
  • markdown-it-container ^3.0.0
  • markdown-it-emoji ^2.0.0
  • outline-icons ^1.38.1
  • prosemirror-commands ^1.1.6
  • prosemirror-dropcursor ^1.3.3
  • prosemirror-gapcursor ^1.1.5
  • prosemirror-history ^1.1.3
  • prosemirror-inputrules ^1.1.3
  • prosemirror-keymap ^1.1.4
  • prosemirror-markdown ^1.5.2
  • prosemirror-model ^1.13.3
  • prosemirror-schema-list ^1.1.2
  • prosemirror-state ^1.3.4
  • prosemirror-tables ^1.1.1
  • prosemirror-transform 1.2.5
  • prosemirror-utils ^0.9.6
  • prosemirror-view 1.18.1
  • react-medium-image-zoom ^3.1.3
  • react-portal ^4.2.1
  • refractor ^3.3.1
  • resize-observer-polyfill ^1.5.1
  • slugify ^1.4.0
  • smooth-scroll-into-view-if-needed ^1.1.29
yarn.lock npm
  • 1517 dependencies