I'm curious if we can define our own block type instead of using one from DRAFTBLOCKTYPE.
Currently I'm playing with draft-wysiwyg which uses plugin named draft-image-plugin. The problem is that I've to pass the block-image
as the type of the block instead of atomic
to make the plugin working.
Actually, I had tried to use the solution from this where I override the plugin's type to atomic
. But it affects other blocks with atomic
type on the application where I can't create my own blockRendererFn since the blockRenderer is 'swallowed' by that plugin's blockRenderer.
To set the block type to atomic
, I can easily achieved it by:
AtomicBlockUtils.insertAtomicBlock(
editorState,
entityKey,
' '
)
How to set the block type to any custom defined type such as block-image
or block-table
? Is that even possible?
Yes, that's possible, and you have a few different options. Here are some I know of:
If you have control over the component that renders blocks of type atomic
, it would probably be easiest to add your new type as an entity to those blocks.
If that's not an option, it get's a bit more cumbersome. AtomicBlockUtils
is actually just a module made to help people create media (atomic) blocks easier (even though more utility functions will probably be added in the future). If you want the exact same behavior, but with a different type, you could copy that module and just exchange 'atomic'
with something else (e.g. 'block-image'
or a variable to make it more generic/resuable).
The technique they use is basically to create a selection of an empty block, and then use the Modifier.setBlockType() function to give it a new block type:
const asAtomicBlock = DraftModifier.setBlockType(
afterSplit, // ContentState
insertionTarget, // SelectionState
'atomic' // your custom type
);
addNewBlock()
(it doesn't work exactly like the one in AtomicBlockUtils
though):/*
Adds a new block (currently replaces an empty block) at the current cursor position
of the given `newType`.
*/
const addNewBlock = (editorState, newType = Block.UNSTYLED, initialData = {}) => {
const selectionState = editorState.getSelection();
if (!selectionState.isCollapsed()) {
return editorState;
}
const contentState = editorState.getCurrentContent();
const key = selectionState.getStartKey();
const blockMap = contentState.getBlockMap();
const currentBlock = getCurrentBlock(editorState);
if (!currentBlock) {
return editorState;
}
if (currentBlock.getLength() === 0) {
if (currentBlock.getType() === newType) {
return editorState;
}
const newBlock = currentBlock.merge({
type: newType,
data: getDefaultBlockData(newType, initialData),
});
const newContentState = contentState.merge({
blockMap: blockMap.set(key, newBlock),
selectionAfter: selectionState,
});
return EditorState.push(editorState, newContentState, 'change-block-type');
}
return editorState;
};
So if you want to e.g. create a block of type 'block-image', with a src attribute, you can use this function like so:
const newEditorState = addNewBlock(this.state.editorState, 'block-image', { src: 'https://...' })
this.setState({ editorState: newEditorState })
Update: If you add a new type, you also need to add it to your editor's blockRenderMap:
import { Map } from 'immutable'
<Editor
// editor props
blockRenderMap={Map({
['unstyled']: {
element: 'div'
},
['block-image']: {
element: 'div' // or whatever element you want as a wrapper
},
// all your other block types
})}
/>