last-draft is a Draft.js editor inspired by MegaDraft and draft-js-plugins
npm install last-draft --save
Check out this awesome ๐ Last Draft example
To run the example simply git clone
, then run yarn install
and npm run dev
import React, { Component } from 'react'
import { render } from 'react-dom'
import {Editor, editorStateFromHtml, editorStateToHtml, editorStateFromRaw, editorStateToJSON} from 'last-draft'
/* init the state, either from raw or html */
import raw from './initialState/raw'
export default class ExampleEditor extends Component {
constructor(props) {
super(props)
const INITIAL_STATE = editorStateFromRaw(raw)
this.state = { value: INITIAL_STATE }
}
onChange(editorState) {
this.setState({ value: editorState })
console.log(editorStateToHtml(editorState))
console.log(editorStateToJSON(editorState))
}
render() {
return (
<Editor
editorState={this.state.value}
placeholder='Enter text...'
onChange={::this.onChange} />
)
}
}
Array of inline styles to use in the toolbar. Any of the following: bold
, italic
, strikethrough
, underline
, code
, dropcap
. By default all are included:
<Editor
editorState={this.state.value}
inline={['bold', 'italic', 'dropcap']}
onChange={::this.onChange} />
When to show the sidebar. Any of the following: never
, always
, newline
. newline
is the default:
<Editor
editorState={this.state.value}
sidebarVisibleOn='always'
onChange={::this.onChange} />
Array of block styles to use in the toolbar. Any of the following: ul
, ol
, h1
, h2
, h3
, h4
, h5
, blockquote
, quote
. By default ul
, ol
and blockquote
are included:
<Editor
editorState={this.state.value}
blocks={['blockquote', 'code']}
onChange={::this.onChange} />
Array of entities to use. Any of the following: link
, hashtag
, mentions
. By default all are included:
<Editor
editorState={this.state.value}
entities={['link']}
onChange={::this.onChange} />
Plugins include custom functionality which can be activated from a button in the toolbar. By default the image
plugin is always included. However you can create your own plugins! Some examples are below:
- ld-video - Adds embed video functionality from youtube and vimeo
- ld-audio - Adds an audio player with soundcloud support
- ld-color-picker - Adds Color picker functionality
- ld-emoji - Adds emoji functionality
- ld-gif - Adds gif functionality from Giphy
- ld-mention - Adds mention functionality
- ld-html - Adds Edit html functionality
- ld-todo - Adds todo functionality
import video from 'ld-video'
import audio from 'ld-audio'
import color from 'ld-color-picker'
import emoji from 'ld-emoji'
import gif from 'ld-gif'
import mention from 'ld-mention'
import html from 'ld-html'
import todo from 'ld-todo'
let plugins = [video, audio, color, emoji, gif, mention, html, todo]
<Editor
editorState={this.state.value}
plugins={plugins}
onChange={::this.onChange} />
For an overview on how to create your own plugin, check out writing-a-last-draft-plugin
To create and test your own plugin, I would advise to test it in this repo, by following the steps below:
-
Create a new
/video
folder in/plugins
copy thesrc\video
folder from ld-video -
Add the following line to
/plugins/index
:export video from './video/plugin'
-
Import your test plugin to the Editor in
last-draft/src/components/Editor
: -
Update the plugin import line to
import {image, placeholder, video} from '../plugins/'
-
Update the line in the
getValidPlugins ()
function: tolet plugins = [image, placeholder, video]
Copy any of the above ld-
plugins as a starting point.
Once its working then create your new plugin repo, then npm run build
and publish it to npm.
A list of users for mentions functionality. An array of objects with properties name
, link
and avatar
. You must also add the ld-mention to show mentions on autocomplete.
<Editor
editorState={this.state.value}
mentionUsers={mentionUsers}
onChange={::this.onChange} />
const mentionUsers = [
{
name: 'Steven Iseki',
link: 'https://github.com/steveniseki',
avatar: 'https://avatars1.githubusercontent.com/u/6695114?v=3&s=400',
},
{
name: 'Nik Graf',
link: 'https://github.com/nikgraf',
avatar: 'https://avatars2.githubusercontent.com/u/223045?v=3&s=400',
}
]
A function that returns a list of filtered users for mentions functionality.
The searchValue
is passed to the function, which will filter and return the users e.g. Searching for users in github. Returns a promise which should return an object with the mentionUsers array. You must also add the ld-mention to show mentions on autocomplete.
const mentionUsersAsync = function (searchValue, cb) {
return new Promise(
(resolve, reject) => {
let url = `https://api.github.com/search/users?q=${searchValue}`
fetch(url)
.then( (response) => { return response.json() })
.then((data) => {
let users = data.items.map( (u, i) => { return { name: u.login, link: u.html_url, avatar: u.avatar_url } })
resolve({ mentionUsers: users })
})
}
)
}
A callback to parse the url for example uploading the file to S3 or a database and returning the url. Returns a promise which should return an object with a src property e.g. resolve({ src: 'http://imgur.com/yrwFoXT.jpg' })
. You can also return srcSet
prop for responsive images resolve({ src: 'x.jpg' srcSet: 'y.jpg' })
<Editor
editorState={this.state.value}
uploadImageAsync={uploadImageAsync}
onChange={::this.onChange} />
function uploadImageAsync(file) {
return new Promise(
(resolve, reject) => {
/* simulating a 2 second call to parse file and return an img src... */
setTimeout( () => {
const src = 'http://imgur.com/yrwFoXT.jpg'
resolve({ src: src })
}, 2000)
}
)
}
Whether to focus the Editor on component mount. Default is false
Whether to show the tooltips on hover over button icons. Default is true
The max offset in pixels left the toolbar is allowed. This is to prevent the toolbar being positioned off the screen to the left when selecting for instance the first few words in a paragraph. Default is 150
Whether to show the Separators between inline, blocks and plugins. Default is true
Pass in a custom theme to override the base Last Draft styles. An object with the following properties:
let THEME = { backgroundColor: '#181818', color: '#66ff00', highlight: '#ffc0cb' }
Last Draft uses styled-components ๐ for the base styling.
You need to include the base draft.css styles, similar to with any Draft.js Editor.
You can set a custom theme for the Last Draft Editor. As shown in the last draft example
let THEME = {
backgroundColor: '#181818',
color: '#66ff00',
highlight: '#ffc0cb'
}
<Editor theme={THEME}
You can also add custom css to override the base styling with the following class names specified below in ld.css.
Block styles
.ld-header {}
.ld-unordered-list {}
.ld-ordered-list {}
.ld-blockquote {}
Entity styles
.ld-link {}
.ld-hashtag {}
.ld-mention {}
Plugin Block styles
.ld-block-wrapper {}
.ld-block {}
.ld-block-actions-wrapper {}
.ld-block-actions {}
.ld-block-action {}
.ld-block-content {}
.ld-block-input-wrapper {}
.ld-block-input {}
.ld-image-block {}
.ld-image-placeholder-block {}
.ld-image-placeholder-block-loader {}
.ld-image-block-button {}
Button styles
.ld-button-blockquote {}
.ld-button-bold {}
.ld-button-close {}
.ld-button-error {}
.ld-button-header {}
.ld-button-image {}
.ld-button-italic {}
.ld-button-link {}
.ld-button-ordered-list {}
.ld-button-unordered-list {}
.ld-button-unlink {}
Inline Toolbar
.ld-toolbar-wrapper {}
.ld-toolbar {}
.ld-toolbar-error {}
.ld-toolbar-button-wrapper {}
.ld-toolbar-button {}
.ld-link-toolbar-button {}
.ld-link-toolbar-item {}
.ld-link-toolbar-input {}
Sidebar
.ld-sidebar {}
.ld-sidebar-menu-wrapper {}
.ld-sidemenu-wrapper {}
.ld-sidemenu {}
.ld-sidemenu-button {}
yarn install
npm run dev
open http://127.0.0.1:3000