Alignment

Prerequisite

This plugin exposes a decorator for blocks. You can use it in combination with any kind of plugin that manages a Draft.js block e.g. image or video. Keep in mind the plugin must accept a decorator for the block. The `Simple Alignment Example` further down contains an example plugin rendering a colored div. In addition this plugin only works in combination with the @draft-js-plugins/focus.

Usage

Select (via mouse or keyboard) a block supporting alignment modifications. A tooltip will pop up and you can update the alignment.

Supported Environment

  • Desktop: Yes
  • Mobile: No
  • Screen-reader: No

Getting Started

npm install @draft-js-plugins/editor
npm install @draft-js-plugins/focus
npm install @draft-js-plugins/alignment

Importing the default styles

The plugin ships with a default styling available at this location in the installed package:  node_modules/@draft-js-plugins/alignment/lib/plugin.css

Webpack Usage

  • 1. Install Webpack loaders:  npm i style-loader css-loader --save-dev
  • 2. Add the below section to Webpack config (if your config already has a loaders array, simply add the below loader object to your existing list.
    module.exports = { module: { loaders: [ { test: /plugin\.css$/, loaders: ['style-loader', 'css'], }, ], }, }; 
  • 3. Add the below import line to your component to tell Webpack to inject the style to your component.
    import '@draft-js-plugins/alignment/lib/plugin.css';
  • 4. Restart Webpack.

Configuration Parameters

Simple Alignment Example

This is a simple example. Focus the block by clicking on it and change alignment via the toolbar.
More text here to demonstrate how inline left/right alignment works …
SimpleAlignmentEditor.js
import React, { Component } from 'react'; import { convertFromRaw, DefaultDraftBlockRenderMap, EditorState, } from 'draft-js'; import Immutable from 'immutable'; import Editor, { composeDecorators } from '@draft-js-plugins/editor'; import createAlignmentPlugin from '@draft-js-plugins/alignment'; import createFocusPlugin from '@draft-js-plugins/focus'; import createColorBlockPlugin from './colorBlockPlugin'; import editorStyles from './editorStyles.module.css'; const focusPlugin = createFocusPlugin(); const alignmentPlugin = createAlignmentPlugin(); const { AlignmentTool } = alignmentPlugin; const decorator = composeDecorators( alignmentPlugin.decorator, focusPlugin.decorator ); const colorBlockPlugin = createColorBlockPlugin({ decorator }); const plugins = [focusPlugin, alignmentPlugin, colorBlockPlugin]; /* eslint-disable */ const initialState = { entityMap: { 0: { type: 'colorBlock', mutability: 'IMMUTABLE', data: {}, }, }, blocks: [ { key: '9gm3s', text: 'This is a simple example. Focus the block by clicking on it and change alignment via the toolbar.', type: 'unstyled', depth: 0, inlineStyleRanges: [], entityRanges: [], data: {}, }, { key: 'ov7r', text: ' ', type: 'atomic', depth: 0, inlineStyleRanges: [], entityRanges: [ { offset: 0, length: 1, key: 0, }, ], data: {}, }, { key: 'e23a8', text: 'More text here to demonstrate how inline left/right alignment works …', type: 'unstyled', depth: 0, inlineStyleRanges: [], entityRanges: [], data: {}, }, ], }; /* eslint-enable */ function BlockWrapper({ children }) { return <div className={editorStyles.wrapper}>{children}</div>; } const blockRenderMap = Immutable.Map({ atomic: { element: 'figure', wrapper: <BlockWrapper />, }, }); const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap); export default class SimpleAlignmentEditor extends Component { state = { editorState: EditorState.createWithContent(convertFromRaw(initialState)), }; onChange = (editorState) => { this.setState({ editorState, }); }; focus = () => { this.editor.focus(); }; render() { return ( <div> <div className={editorStyles.editor} onClick={this.focus}> <Editor editorState={this.state.editorState} onChange={this.onChange} plugins={plugins} ref={(element) => { this.editor = element; }} blockRenderMap={extendedBlockRenderMap} /> <AlignmentTool /> </div> </div> ); } } 
colorBlockPlugin.js
import React from 'react'; const ColorBlock = React.forwardRef( ( { block, // eslint-disable-line no-unused-vars blockProps, // eslint-disable-line no-unused-vars customStyleMap, // eslint-disable-line no-unused-vars customStyleFn, // eslint-disable-line no-unused-vars decorator, // eslint-disable-line no-unused-vars forceSelection, // eslint-disable-line no-unused-vars offsetKey, // eslint-disable-line no-unused-vars selection, // eslint-disable-line no-unused-vars tree, // eslint-disable-line no-unused-vars contentState, // eslint-disable-line no-unused-vars blockStyleFn, // eslint-disable-line no-unused-vars preventScroll, // eslint-disable-line no-unused-vars style, ...elementProps }, ref ) => ( <div ref={ref} {...elementProps} style={{ width: 200, height: 80, backgroundColor: '#9bc0c7', ...style }} /> ) ); const createColorBlockPlugin = (config = {}) => { const component = config.decorator ? config.decorator(ColorBlock) : ColorBlock; return { blockRendererFn: (block, { getEditorState }) => { if (block.getType() === 'atomic') { const contentState = getEditorState().getCurrentContent(); const entity = contentState.getEntity(block.getEntityAt(0)); const type = entity.getType(); if (type === 'colorBlock') { return { component, editable: false, }; } } return null; }, }; }; ColorBlock.displayName = 'ColorBlock'; export default createColorBlockPlugin; 
editorStyles.css
.editor { box-sizing: border-box; border: 1px solid #ddd; cursor: text; padding: 16px; border-radius: 2px; margin-bottom: 2em; box-shadow: inset 0px 1px 8px -3px #ababab; background: #fefefe; } .editor :global(.public-DraftEditor-content) { min-height: 140px; } .options { margin-bottom: 20px; } .wrapper { position: relative; z-index: 1; } 

Themed Alignment Example

This is a simple example. Focus the block by clicking on it and change alignment via the toolbar.
More text here to demonstrate how inline left/right alignment works …
SimpleAlignmentEditor.js
import React, { Component } from 'react'; import { convertFromRaw, DefaultDraftBlockRenderMap, EditorState, } from 'draft-js'; import Immutable from 'immutable'; import Editor, { composeDecorators } from '@draft-js-plugins/editor'; import createAlignmentPlugin from '@draft-js-plugins/alignment'; import createFocusPlugin from '@draft-js-plugins/focus'; import createColorBlockPlugin from './colorBlockPlugin'; import editorStyles from './editorStyles.module.css'; import alignmentToolStyles from './alignmentToolStyles.module.css'; import buttonStyles from './buttonStyles.module.css'; const focusPlugin = createFocusPlugin(); const alignmentPlugin = createAlignmentPlugin({ theme: { alignmentToolStyles, buttonStyles, }, }); const { AlignmentTool } = alignmentPlugin; const decorator = composeDecorators( alignmentPlugin.decorator, focusPlugin.decorator ); const colorBlockPlugin = createColorBlockPlugin({ decorator }); const plugins = [focusPlugin, alignmentPlugin, colorBlockPlugin]; /* eslint-disable */ const initialState = { entityMap: { 0: { type: 'colorBlock', mutability: 'IMMUTABLE', data: {}, }, }, blocks: [ { key: '9gm3s', text: 'This is a simple example. Focus the block by clicking on it and change alignment via the toolbar.', type: 'unstyled', depth: 0, inlineStyleRanges: [], entityRanges: [], data: {}, }, { key: 'ov7r', text: ' ', type: 'atomic', depth: 0, inlineStyleRanges: [], entityRanges: [ { offset: 0, length: 1, key: 0, }, ], data: {}, }, { key: 'e23a8', text: 'More text here to demonstrate how inline left/right alignment works …', type: 'unstyled', depth: 0, inlineStyleRanges: [], entityRanges: [], data: {}, }, ], }; /* eslint-enable */ function BlockWrapper({ children }) { return <div className={editorStyles.wrapper}>{children}</div>; } const blockRenderMap = Immutable.Map({ atomic: { element: 'figure', wrapper: <BlockWrapper />, }, }); const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap); export default class ThemedAlignmentEditor extends Component { state = { editorState: EditorState.createWithContent(convertFromRaw(initialState)), }; onChange = (editorState) => { this.setState({ editorState, }); }; focus = () => { this.editor.focus(); }; render() { return ( <div> <div className={editorStyles.editor} onClick={this.focus}> <Editor editorState={this.state.editorState} onChange={this.onChange} plugins={plugins} ref={(element) => { this.editor = element; }} blockRenderMap={extendedBlockRenderMap} /> <AlignmentTool /> </div> </div> ); } } 
editorStyles.css
.editor { box-sizing: border-box; border: 1px solid #ddd; cursor: text; padding: 16px; border-radius: 2px; margin-bottom: 2em; box-shadow: inset 0px 1px 8px -3px #ababab; background: #fefefe; } .editor :global(.public-DraftEditor-content) { min-height: 140px; } .options { margin-bottom: 20px; } .wrapper { position: relative; z-index: 1; } 
alignmentToolStyles.css
.alignmentTool { left: 50%; transform: translate(-50%) scale(0); position: absolute; border: 1px solid #111; background: #333; border-radius: 4px; box-shadow: 0px 1px 3px 0px rgba(220, 220, 220, 1); z-index: 2; box-sizing: border-box; } .alignmentTool:after, .alignmentTool:before { top: 100%; left: 50%; border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none; } .alignmentTool:after { border-color: rgba(255, 255, 255, 0); border-top-color: #333; border-width: 4px; margin-left: -4px; } .alignmentTool:before { border-color: rgba(221, 221, 221, 0); border-top-color: #111; border-width: 6px; margin-left: -6px; } 
buttonStyles.css
.buttonWrapper { display: inline-block; } .button { background: #333; color: #ddd; font-size: 18px; border: 0; padding-top: 5px; vertical-align: bottom; height: 34px; width: 36px; border-radius: 4px; } .button svg { fill: #ddd; } .button:hover, .button:focus { background: #444; outline: 0; /* reset for :focus */ } .active { color: #6a9cc9; } .active svg { fill: #6a9cc9; }