I really like this feature, but it is not able to align text, tell me how to do it?
PS with example code please, thanks!
Not sure what you are referring to. If you use the textAlignment prop on Editor, it will align your text for the entire editor.
I think that @Philin-Anton is referring to aligning certain blocks of text and not the entire editor. Any ideas on how one would go about doing that?
Thanks,
S,
You would have to do the following, create a getBlockStyle handler:
const getBlockStyle = (block) => {
switch (block.getType()) {
case 'left':
return 'align-left';
case 'center':
return 'align-center';
case 'right':
return 'align-right';
default:
return null;
}
}
pass it to your editor
<Editor
blockStyleFn={getBlockStyle}
...
/>
When clicking on a button that triggers a class 'align-right' or 'align-center' or 'align-left' will be added to your block container. WIth that you can use CSS to:
.align-right div {
text-align: right;
}
.align-center div {
text-align: center;
}
.align-left div {
text-align: left;
}
In order to hook buttons to commands you can have a look into the rich.html example from draftjs.
I generally wouldn't advise using block types that are outside the EditorBlockType enum.
@Philin-Anton I'd say there aren't really supported ways to do this right now on a per-block level. Is it possible that you only need certain block types to be aligned differently? If so, you can certainly use blockStyleFn for that.
@hellendag Wouldn't it be possible to do this now that https://github.com/facebook/draft-js/pull/216 has landed? When aligning a block, custom meta data could be assigned to that block, which can then be used in the blockStyleFn to derive which classes should be added.
@johanneslumpe I think that would enable it, yeah. I've imported that one but haven't merged it yet, though.
Yep we're hoping to use block level metadata for this too.
I did all as say @mitermayer, but i have error.
my code:
onCenter(self){
self.onChange(RichUtils.toggleBlockType(self.state.editorState, 'centerAlign'));
}
and that error:
nullthrows.js?2b54:18 Uncaught Error: Got unexpected null or undefined
that my getBlockStyle:
myBlockStyleFn(block) {
console.log(block.getType())
switch (block.getType()) {
case 'leftAlign':
return 'emailAlignLeft';
case 'centerAlign':
return 'emailAlignCenter';
case 'rightAlign':
return 'emailAlignRight';
default:
return null;
}
}
what i do wrong?
@Zulfia73 I think we will need https://github.com/facebook/draft-js/pull/372/files to be merged
@hellendag I think it's a common issue to set text alignment on a per-block basis.
@ruffle1986 The PR for block level meta data has already been imported so it is just a matter of time now until you can do alignment with meta data.
@johanneslumpe great news! thank you guys, you're awesome! 👍
For reference I found a hackish way around text alignment with the current version. I used custom inline styles and checked for their existence within a block in my blockStyler function to add alignment classes to the whole block. To do so I wrote a modifier which applies a style to all of the blocks within the selection range and removes an arbitrary array of styles, so that a block can only have one alignment at a time.
It's obviously a bit dirty, but works quite well so far.
@deanmcpherson Can you share the code? I'm interested in your workaround :)
@lmgonzalves Just threw the pieces roughly together at https://gist.github.com/deanmcpherson/69f9962b744b273ffb64fe294ab71bc4
Is there any 'api' solution so far? Block alignment seems to be a pretty common use case, so we really lack it in Draft. Thnx
any update about this? i'm getting this error following the steps of @mitermayer DraftEditorContents.react.js:151 Uncaught TypeError: Cannot read property 'wrapper' of undefined
@cinder92 block-level meta data has been included in version 0.8. So you do not need @mitermayer's hack from above - you can now use the meta data to tell your block which kind of text alignment you want. You can then retrieve the alignment in a custom block component and apply it in any way you want to the wrapper.
@johanneslumpe thanks for your quick reply! do you have any example about this? i'm searching since 2 hours ago and there is nothing! 👍
@cinder92 I'm sorry, but I do not have an actual working example of this right now. I might throw one together soon though. The basic gist is to get the current selection's content block instance and then set custom alignment metadata on it. How that metadata is then interpreted is up to the wrapper component. (Could be float or just text-align)
This is an example of how we did it. It's largely based on RichUtils, and gives us two new utilities:
toggleAlignment(editorState, alignment) - assigns a text alignment to the current blocksplitBlock(editorState) - override default "return" key behavior to handle keeping the same text alignment from the previous block to the newly created block.https://gist.github.com/joshdover/7c5e61ed68cc5552dc8a25463e357960
thanks @deanmcpherson for share your code, it works for me :+1: :octocat:
I've implemented the gist from @joshdover without errors, but no formatting is being added to the editor. What am I missing? Do I need to add a styles/CSS for this to work?
@creativenode you need probably parse this by styling method: https://facebook.github.io/draft-js/docs/advanced-topics-block-styling.html#blockstylefn
i have the same question.@cinder92 @Philin-Anton
with @mitermayer 's code ,we have a error like @cinder92 said : "DraftEditorContents.react.js:151 Uncaught TypeError: Cannot read property 'wrapper' of undefined"
I fixed it like this:
<Editor
blockRenderMap={this.extendedBlockRenderMap}
...
/>
and this.extendedBlockRenderMap is defined in construct:
`
constructor(props) {
super(props)
const blockRenderMap = Immutable.Map({
'text-align-left': {
element: 'div'
},
'text-align-center': {
element: 'div'
},
'text-align-right': {
element: 'div'
}
});
this.extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap);
...
}
`
so,when the draft.js meet a block have a type == 'text-align-left' will use div element to render it.
I find four ways to customize contentBlock, but only blockStyleFn works well for me.
[ ] blockRenderFn: well, if you want to write characters normally, it is not good choice because this function doesn't provide props.children;
[ ] blockRenderMap: it's not good as well as blockRenderFn. This Map needs to includes every block you need, unless you decide to create some new block types outside of provided EditorBlockType, and I don't suggest to do that.
[x] blockStyleFn: with Modifier.setBlockData and contentBlock.getData, you can easily use blockData to store your contentBlock text-align style when press text-align button and set a proper classname to your block. Here is what I deal with this issue.
// blockStyleFn
export default contentBlock => {
const type = contentBlock.getType();
const blockStyle = contentBlock.getData().get('style');
let cls = '';
switch (type) {
case BlockType.UNSTYLED:
cls = 'RichEditor-style__initial-unstyled';
break;
case BlockType.ATOMIC:
cls = 'RichEditor-style__initial-atomic';
break;
default:
}
// BASIC_BLOCKS includes unstyled, header-one, header-two,
// header-three, header-four, header-five, header-six
if (Object.keys(BlockType.BASIC_BLOCKS).some(key => BlockType.BASIC_BLOCKS[key] === type)) {
cls += ` RichEditor-style__text-align-${blockStyle.textAlign}`;
}
return cls;
};
I use this function because I really don't want to produce 'extra' blocks.
decorators: use composedDecorators it's also very easy to set text-align. But it does not work well with other strategy inside the same block, like HashTag or hyperAtTag. I found decorator component only serves one strategy at once.// BASIC_BLOCKS includes unstyled, header-one, header-two,
// header-three, header-four, header-five, header-six
// decorators
function matchTextAlignWrapper(contentBlock, callback, contentState) {
if (Object.keys(BlockType.BASIC_BLOCKS).some(key => BlockType.BASIC_BLOCKS[key] === type)) {
callback(0, contentBlock.getLength());
}
}
export const decorator = [
{
strategy: matchTextAlignWrapper,
component: TextAlignBlock
}
];
// TextAlignBlock
export default class TextAlignBlock extends Component {
render() {
const { children, className } = this.props;
const child = children[0];
const blockStyle = child.props.block.getData().get('style');
return (
<div
className={classnames(
className,
`RichEditor-style__text-align-${blockStyle.textAlign}`
)}
>
{this.props.children}
</div>
);
}
}
Wow - I see several answers here.
Closing this issue for now. ✨ Great work everyone!
I feel like draft-js should have this functionality by default instead of requiring these kinds of workarounds
I implement this functionality by check the if the currentBlockType is 'unstyled' or 'header-one' or other type. If it is 'unstyled' then I use toggleBlockType to do the alignment. If it is 'header-one' or other type, I use toggleInlineStyle. It works for me. And I think it is elegant.
There below is my code.
_toggleAlignment(alignmentType) {
const { editorState } = this.state
const selection = editorState.getSelection()
const anchorKey = selection.getAnchorKey()
const currentContent = editorState.getCurrentContent()
const currentContentBlock = currentContent.getBlockForKey(anchorKey)
const blockType = currentContentBlock.getType()
if (blockType === 'unstyled') {
this.toggleBlockType(alignmentType)
} else {
this.toggleInlineStyle(alignmentType)
}
}
You need have your own extendedBlockRenderMap , your own getBlockStyle and your own customStyleMap. Just like below:
```javascript
const colorStyleMap = {
red: {
color: 'rgba(255, 0, 0, 1.0)',
},
orange: {
color: 'rgba(255, 127, 0, 1.0)',
},
yellow: {
color: 'rgba(180, 180, 0, 1.0)',
},
green: {
color: 'rgba(0, 180, 0, 1.0)',
},
blue: {
color: 'rgba(0, 0, 255, 1.0)',
},
indigo: {
color: 'rgba(75, 0, 130, 1.0)',
},
violet: {
color: 'rgba(127, 0, 255, 1.0)',
},
papeLeft: {
display: 'inline-block',
width: '100%',
textAlign: 'left'
},
papeRight: {
display: 'inline-block',
width: '100%',
textAlign: 'right'
},
papeCenter: {
display: 'inline-block',
width: '100%',
textAlign: 'center'
},
}
const blockRenderMap = Map({
'papeLeft': {
element: 'div'
},
'papeRight': {
element: 'div'
},
'papeCenter': {
element: 'div'
}
})
const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap)
_getBlockStyle(block) {
switch (block.getType()) {
case 'blockquote': return 'pape-blockquote'
case 'papeLeft': return 'papeLeft'
case 'papeRight': return 'papeRight'
case 'papeCenter': return 'papeCenter'
default: return null
}
}
````
It seems only blockStyle worked.
There's still no suggestive answer or way to address this issue. Text align is a common feature needed in an editor.
@mitermayer Your solution works well in the editor. I just want to know on how can i render it, for instance using draft-js-export-html?
Already found how to render it.
Already found how to render it.
@JMA12 could share a code pen?
@ahungrynoob could you share a code pen ?
@morgangreenwalt Sorry. I have left this project for too long time to pick it up. But I recommend you to use slatejs. It’s more elegant and have a stronger community.
@juliankrispel this would be huge
Any update on the above?
@JMA12 Can you share your solution?
@ecureuill
@mitermayer's answer worked for me just tweaked it a little bit. Can't find my file where I used it. If ever I found it will post it here
Most helpful comment
I feel like draft-js should have this functionality by default instead of requiring these kinds of workarounds