LovelyEditor is a React component to provide a variety of editors to be added to your app. It also gives you the opportunity to create your own editor and add it to the LovelyEditor-component. As a result the edited content will come in the shape of HTML markup to be added to your page. Each editor will create an isolated HTML markup of its part. This makes it very easy for you to include a variety of different Editors into your App and organise them and their returned value exactly the way you need it. Also including a new Editor that is not supported yet can be accomplished within just a few easy steps.
This makes it very easy for you to include a variety of different Editors into your App and organise them and their returned value exactly the way you need it. Also including a new Editor that is not supported yet can be accomplished within just a few easy steps.
The Example-App shows what our LovelyEditor can do. The app consists of 2 main parts, a toolbar and our LovelyEditor. The toolbar adds additional (pre-defined) Editors to our LovelyEditor. Each Editor block is extended by a Delete button, which removes an editor block from our LovelyEditor. Drag & Drop was added to illustrate that our LovelyEditor plays nice with other libraries.
- Features
- Examples
- Requirements
- Installation
- LovelyEditor components
- Quickstart
- How to include your own custom Editor
- How to contribute and develop
- How to create a release
- Provides a variety of pre-designed editors: eg. EditorQuill
- design and features are largely customisable: make it your own!
- easy way to create and add your own custom editor or extend existing ones
- use every EditorComponent (eg. EditorQuill) independently without need to look out you for the others
The following link will provide you with certain examples on how the component may be used: https://lovely-editor.netlify.com. By selecting one of the options within "App Example" you will see a variety of possibilities on what you are able to use the component for. For example within "Menu and Quill Block Editor" there is an example-menu included to quickly add different editor-types (eg. Richtext, CodeMirror, etc.) to the application. It is also possible to use the same editor-type several times.
To see what kind of HTML-Output the Editors return check out our example. The generated HTML of all editors is ready to be used in your app.
node 8.6.x
npm 5.3.x
The following environment variables need to be set, scoped to read: packages
GITHUB_TOKEN=YOUR_PAT_FROM_GITHUB_HERE
npm install --save lovely-editor
and import it in your App with:
import { LovelyEditor } from 'lovely-editor'
If you want to use the basic styling as well you can either import it in your index.js
import('lovely-editor/dist/lovely-editor.min.css')
Or add it to your index.html.
The LovelyEditor basically consists out of three main components:
- LovelyEditor
- EditorBlock
- Editors (eg. EditorQuill)
The LovelyEditor
rendered components tree looks like this:
<LovelyEditor>
<EditorBlock>
// a EditorComponent, eg. <EditorQuill />
</EditorBlock>
</LovelyEditor>
The main entry point in your app is the LovelyEditor
. Its properties have to
be specified and all necessary EditorBlock
and EditorComponent
s are rendered
automatically, based on the editorState and
blocksConfig.
Follow the Installation first before taking a look at the following comprehensive example:
The following app showcases the usage of the LovelyEditor
with one pre-configured Editor
(in this case EditorQuill
) and a current editorState
.
The app itself controls the LovelyEditor
by not only subscribing to the LovelyEditor
's
onChange
but also by providing it's editorState
as a property. The changes are
received and the YourApp
's state
updated. This leads to a re-rendering of
the LovelyEditor
with a new valid editorState. You can find a similar example also
in our Storybook.
import { LovelyEditor } from 'lovely-editor'
import { EditorQuill } from 'lovely-editor/dist/components/editor-quill'
// current state of LovelyEditor
const editorState = [
{
id: 1,
type: 'richtext',
data: {
value: '<p>Hello World. <strong>This is bold.</strong></p>'
},
meta: {
title: 'Quill Block'
}
},
]
// renders a specific component for the requested block.type
// in this case EditorQuill would be rendered for all blocks of type "richtext"
const editorQuillConfig = {
type: 'richtext',
component: EditorQuill
}
// sets which editor component should be rendered for which block.type
const blocksConfig = [editorQuillConfig]
class YourApp extends React.Component {
constructor(props) {
super(props)
this.state = {
editorState
}
this.onChange = this.onChange.bind(this)
}
onChange(change) {
this.setState({ editorState: change.editorState })
}
render() {
return (
<LovelyEditor
blocksConfig={blocksConfig}
editorState={this.state.editorState}
onChange={this.onChange}
/>
)
}
}
To tell the editor it's current state we need to specify the editorState
.
It is responsible for telling the component which Editor
gets what kind of
data (eg. current content for the richtext editor).
The function of the editorState
is, as the name says, to represent the current
state of the <LovelyEditor />
. That means if you e.g. type in a new text into
a <EditorQuill />
the editorState
will change. Your app can access the
current editorState
by subscribing to the onChange
property of the <LovelyEditor />
.
Through this any changes to an Editor (eg. EditorQuill) lead to an onChange event
of the <LovelyEditor />
and lets you use the change for your own purposes
(eg. validate changes or show "unsaved" messages).
A editorState
can look similar to:
const editorState = [
{
id: 1, // block.id, must be unique
type: 'richtext',
data: {
value: '<p>Hello World. <strong>This is bold.</strong></p>'
},
meta: {
title: 'Quill Block'
}
}
]
Attention: the block.id must be unique! Make sure each block has it's own individual (it can be random though) id. The id is used to identify each block with the LovelyEditor.
Note, that each block type (eg. "richtext") in the editorState
must have a
matching type configuration in the blocksConfig
to be rendered.
Then you have to provide a blocksConfig
configurations. This means telling
the <LovelyEditor />
which EditorComponent
to use for which specified type (e.g.
<EditorQuill />
for type "richtext").
But the order and number of currently rendered Editors are specified through
the editorState
(see Editor State).
An example config could look like:
const editorQuillConfig = {
type: 'richtext',
component: EditorQuill
}
const blocksConfig = [editorQuillConfig]
As a final step we define our App component where we first set the editorState
as this.state
and create an onChange
-method to sync the changes in the
<LovelyEditor />
with the editorState
of the App and set it as the new
state (or do even more if we want to).
class YourApp extends React.Component {
constructor(props) {
super(props)
this.state = {
editorState
}
this.onChange = this.onChange.bind(this)
}
onChange(change) {
// get the change from the LovelyEditor and sync the YourApp's state
this.setState({ editorState: change.editorState })
}
//...
}
The final step is the render()
-method for our App component. Here we put in
our Editor
with its 3 necessary properties (blocksConfig
, editorState
and onChange
). As we have defined the requirements for those properties we
only have to assign them to the Editor
.
render() {
return (
<LovelyEditor
blocksConfig={blocksConfig}
editorState={this.state.editorState}
onChange={this.onChange}
/>
)
}
The entire code of the example can be found in the Quickstart section.
If you want to use the same styling like the basic styling in our Storybook, you have to include the CSS from lovely-editor in your own application. Example import in SCSS:
@import "~lovely-editor/dist/lovely-editor.min.css";
Take a look at the Quill Editor implementation which illustrates how one can add a new custom editor.
Once you have cloned the repository enter nvm use && npm install
to
install all the dependencies, required to develop.
The package comes with the following npm scripts:
npm run build
: builds the package to ./distnpm run build:storybook
: build static production version of component library to ./build/storybooknpm run coverage
: runs the tests and reports the coverage with nycnpm run lint
: lints JS codenpm run storybook
: run local server with component library and Storybooknpm start
: similar tonpm run storybook
npm run test
: runs the tests (test files path and pattern:src/**/*.spec.js
)npm run test:node
: verifies the installed and used node version
This package uses Storybook to showcase the
components. Just enter npm run storybook
to start it on your local machine or
visit https://lovely-editor.netlify.com.
When attempting to commit files in this repository, some taks will automatically run to ensure a consistently high level of code quality:
- JavaScript files (.js):
- runs
eslint
and automatically fixes auto-fixable issues (see related JS guidelines here) - runs
prettier
and auto-formats your code (see what it does here) - runs all unit tests concerning the committed files with
mocha
- runs
If any of the tasks fail (which means your code does not lint or unit tests are failing), your commit or push will be aborted.
-
Update CHANGES
-
Commit it as "prepare release x.y.z"
-
Create a git tag:
npm version major | minor | patch
This will update the version in packages.json and create a git tag.
- Push the git tag and changes
git push && git push --tags
- Merge release in release branch (eg.
release/x.y
)
Github uses personal access tokens (PAT) for authentication. To generate one go to your Github token settings page. Consult the Github Docs for more information on how tokens work.
The following environment variables need to be set:
GITHUB_TOKEN=YOUR_PAT_FROM_GITHUB_HERE
We are using GitHub Packages to host this repo to npm. GitHub Packages Docs and here
- increase version in
package.json
- Check in all changes and commit
- run
git tag <version>
- run
git push --tags
- run
npm run build
- run
npm publish
Add the following to your project's .npmrc
:
@lovelysystems:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
If you use yarn add always-auth=true
to the .npmrc
as well.