Last active
May 31, 2017 16:16
-
-
Save bultas/981cde34b3d1a2cb9b558ca9467bca77 to your computer and use it in GitHub Desktop.
DraftJS - Text Alignment via block metadata
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
https://gist.github.com/joshdover/7c5e61ed68cc5552dc8a25463e357960 | |
https://github.com/jpuri/react-draft-wysiwyg/blob/master/js/src/components/Controls/TextAlign/index.js |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getBlockClassName(name) { | |
return `richText-block richText-${name}-block`; | |
} | |
export function myBlockStyleFn(contentBlock) { | |
const type = contentBlock.getType(); | |
const blockAlignment = | |
contentBlock.getData() && contentBlock.getData().get('text-align'); | |
if (blockAlignment) { | |
return `${getBlockClassName(blockAlignment)} richText-textAlignment-block`; | |
} | |
if (type === 'unstyled') { | |
return getBlockClassName('unstyled'); | |
} | |
return null; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.richText-block { | |
margin-bottom: 15px; | |
} | |
.richText-textAlignment-block > div { | |
display: inline; | |
} | |
.richText-left-block { | |
text-align: left; | |
} | |
.richText-center-block { | |
text-align: center; | |
} | |
.richText-right-block { | |
text-align: right; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function CustomEditor(props) { | |
... | |
return ( | |
<Editor | |
editorState={editorState} | |
onChange={onChange} | |
blockStyleFn={myBlockStyleFn} | |
handleReturn={createHandleReturn(editorState, onChange)} | |
handleBeforeInput={createHandleBeforeInput( | |
editorState, | |
onChange | |
)} | |
handleKeyCommand={createHandleKeyCommand( | |
editorState, | |
onChange | |
)} | |
/> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { EditorState } from 'draft-js'; | |
import { stateToHTML } from 'draft-js-export-html'; | |
import { stateFromElement } from 'draft-js-import-element'; | |
import RichTextEditor, { createDecorator } from 'lib/richTextEditor'; | |
import rmSpaces from 'lib/rmSpaces'; | |
function createElementFromHTMLString(HTMLString) { | |
const element = document.createElement('div'); | |
element.innerHTML = HTMLString; | |
return element; | |
} | |
function createContentStateFromHTMLString(HTMLString) { | |
return stateFromElement(createElementFromHTMLString(HTMLString), { | |
customBlockFn: ({ tagName, style }) => { | |
if (tagName === 'P' && style.textAlign) { | |
return { data: { textAlign: style.textAlign } }; | |
} | |
return null; | |
} | |
}); | |
} | |
// function createContentStateFromHTMLString(HTMLString) { | |
// const cleanHTML = rmSpaces(HTMLString); // cleanup for better html > state conversion | |
// const blocksFromHTML = convertFromHTML(cleanHTML); | |
// | |
// return ContentState.createFromBlockArray( | |
// blocksFromHTML.contentBlocks, | |
// blocksFromHTML.entityMap | |
// ); | |
// } | |
function getEditorStateFromHTMLString(HTMLString) { | |
const contentState = createContentStateFromHTMLString(HTMLString); | |
const editorState = EditorState.createWithContent( | |
contentState, | |
createDecorator() | |
); | |
return editorState; | |
} | |
export default class CustomRichTextEditor extends React.Component { | |
constructor(props) { | |
super(props); | |
const { value, onChange } = props; | |
this.state = { | |
editorState: getEditorStateFromHTMLString(value) | |
}; | |
this.changeEditorState = eState => { | |
const newEditorHTMLValue = rmSpaces( | |
stateToHTML(eState.getCurrentContent(), { | |
blockStyleFn: block => { | |
if (block.getData().get('textAlign')) { | |
return { | |
style: { | |
textAlign: block.getData().get('textAlign') | |
} | |
}; | |
} | |
return null; | |
} | |
}) | |
); | |
this.setState({ | |
editorState: eState | |
}); | |
onChange(newEditorHTMLValue); | |
}; | |
} | |
render() { | |
return ( | |
<RichTextEditor | |
{...this.props} | |
editorState={this.state.editorState} | |
onChange={this.changeEditorState} | |
/> | |
); | |
} | |
} | |
CustomRichTextEditor.propTypes = { | |
value: React.PropTypes.string.isRequired, | |
onChange: React.PropTypes.func.isRequired | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import Immutable from 'immutable'; | |
import { EditorState, Modifier } from 'draft-js'; | |
import { getToolbarButtonStyle } from '../helpers/styleHelpers'; | |
export function getSelectedBlocksMap(editorState: EditorState): OrderedMap { | |
const selectionState = editorState.getSelection(); | |
const contentState = editorState.getCurrentContent(); | |
const startKey = selectionState.getStartKey(); | |
const endKey = selectionState.getEndKey(); | |
const blockMap = contentState.getBlockMap(); | |
return blockMap | |
.toSeq() | |
.skipUntil((_, k) => k === startKey) | |
.takeUntil((_, k) => k === endKey) | |
.concat([[endKey, blockMap.get(endKey)]]); | |
} | |
export function getSelectedBlocksList(editorState: EditorState): List { | |
return getSelectedBlocksMap(editorState).toList(); | |
} | |
export function getSelectedBlocksMetadata(editorState: EditorState): Map { | |
let metaData = new Immutable.Map({}); | |
const selectedBlocks = getSelectedBlocksList(editorState); | |
if (selectedBlocks && selectedBlocks.size > 0) { | |
for (let i = 0; i < selectedBlocks.size; i += 1) { | |
const data = selectedBlocks.get(i).getData(); | |
if (!data || data.size === 0) { | |
metaData = metaData.clear(); | |
break; | |
} | |
if (i === 0) { | |
metaData = data; | |
} else { | |
metaData.forEach((value, key) => { | |
// eslint-disable-line no-loop-func | |
if (!data.get(key) || data.get(key) !== value) { | |
metaData = metaData.delete(key); | |
} | |
}); | |
if (metaData.size === 0) { | |
metaData = metaData.clear(); | |
break; | |
} | |
} | |
} | |
} | |
return metaData; | |
} | |
function setBlockData(editorState, data) { | |
const newContentState = Modifier.setBlockData( | |
editorState.getCurrentContent(), | |
editorState.getSelection(), | |
data | |
); | |
return EditorState.push(editorState, newContentState, 'change-block-data'); | |
} | |
function getNextAlignment(currentAlignment) { | |
switch (currentAlignment) { | |
case 'right': | |
return 'left'; | |
case 'left': | |
return 'center'; | |
case 'center': | |
return 'right'; | |
default: | |
return 'left'; | |
} | |
} | |
export function TextAlignmentControl({ editorState, onToggle, styles }) { | |
return ( | |
<div | |
style={getToolbarButtonStyle(styles, false)} | |
onMouseDown={e => { | |
e.preventDefault(); | |
onToggle( | |
setBlockData(editorState, { | |
'text-align': getNextAlignment( | |
getSelectedBlocksMetadata(editorState).get( | |
'text-align' | |
) | |
) | |
}) | |
); | |
}} | |
> | |
Align | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment