Most people call me Rose :)
I want to make this README super awesome but here's the basics for now:
- My tiny personal site: rosey.dev
- I write blog posts on technical topics at: dev.to/rose
A tool to convert content created in DraftJS to markdown and vice versa.
Home Page: https://rosey.github.io/markdown-draft-js/
License: MIT License
Most people call me Rose :)
I want to make this README super awesome but here's the basics for now:
I just noticed this:
If I enter the following markdown:
> Testing
>
>
> Hello
markdown-to-draft renders
Hello
(The "testing" bit just seems to get swallowed up)
Eg if draft's first "bold" char is whitespace, markdown generated is this, which is not valid:
** bold**
It should be
**bold**
Hi! We had an issue where we forked this library and made some local modifications, but when using it via a sha-(and fork) specific package.json line, it wasn't working, this was because the "prepublish" script only runs before the package is published to NPM. The fix for our fork was to duplicate the prepublish
script as a prepare
script, however perhaps that is a more useful stage to run at?
I just used the default migration but it seems to be working extra hard to set up a docker image, there has to be a better way ๐
as per the example below, markdownToDraft
does strange things with tables, they're converted to just the last value in the last row, plus the line before the table is removed.
I know markdown-draft-js (understandably) doesn't support tables fully but it would be great if it could just leave them alone rather than messing them up.
(the draftToMarkdown
in the last line is unnecessary, it's just there to demonstrate more clearly what the output looks like).
const v = 'this is the first line.\n' +
'\n' +
'this is the second line.\n' +
'\n' +
'| foo | bar |\n' +
'| --- | --- |\n' +
'| baz | bim |\n' +
'\n' +
'This is another line under the table.'
const s = EditorState.createWithContent(convertFromRaw(markdownToDraft(v)))
const raw = convertToRaw(s.getCurrentContent())
console.log(JSON.stringify(raw, null, 2))
console.log(draftToMarkdown(raw))
{
"blocks": [
{
"key": "d2fmf",
"text": "this is the first line.",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
},
{
"key": "5155o",
"text": "bim",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
},
{
"key": "c784q",
"text": "This is another line under the table.",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
}
],
"entityMap": {}
}
------------------------------------------------------------------------------------
this is the first line.
bim
This is another line under the table.
Hi Rosey,
I sent a few updates via email if you would like to incorporate, and just so you know its not spam, I am also writing here
babel-polyfill seems to be a required dependency but not defined as a peerdep in the package.json
Do we really need babel-polyfill for this package?
Hi,
I know that ---
is supported in Remarkable. But when sending my markdown through markdownToDraft
all the ---
's are filtered out. Do I do something wrong?
Here also a sample
---
**test**
---
Test
\# hello
#helo
Best,
Omid
So far, I've found that the underline and through styles don't work correctly
Hi @Rosey,
I am really happy for the preserveNewlines feature. It got me closer to 1-to-1 exact matching looks when converting, but I found newline handling was still a little bit off. I was able to fix it without breaking any unit tests. My draft-js editor is pretty much this, the standard Rich Text Editor Draft.js example.
Here is my example:
Input:
a
b
c
d
When converted by draft-to-markdown.js
it added a newline after each character, output:
a
b
c
d
And here's the same example but converted by markdown-to-draft.js
, input:
a
b
c
d
When converted by markdown-to-draft.js
it removed one newline after each character (except "a"), output:
a
b
c
d
Does this make sense?
Should I write unit tests to test these things?
I wrote a fix PR (#112)
Can this be included in your package and put into NPM to help us develop: rareconnect.org?
I'm not sure if you guys are aware of this:
https://snyk.io/test/npm/markdown-draft-js/1.3.0
reports a security vulnerability on Snyk. It can be solved by upgrading the underscore.string
dependency.
If you check out the example, when you modify the textarea, a newline always only counts as 1, even if you have 3 in a row.
But when you modify the draft editor, each newline is converted 1:1 to markdown. This behaviour is more desireable than the markdown-to-draft behaviour!
When I started on this project I was just kind of doing it for myself but I think it has enough people using it that I should be a bit more diligent (and probably should have been from the start, let's be honest) about explaining what changed in each version.
Previous issue outlining the problem: #52
And current code for escaping basic markdown, with a comment on its limitations - https://github.com/Rosey/markdown-draft-js/blob/master/src/draft-to-markdown.js#L3
contentState.getBlockMap is not a function
I'm getting this error when trying to put converted content into DraftJS state
EditorState.createWithContent(contentState, decorator);
What am I doing wrong?
Let's say in draft-js we have following content:
first line
- list
- two
- three
next line
That is converted to markdown as:
first line
1. list
1. two
1. three
next line
There should be a line between last list element three
and the next line
.
Otherwise, next line
is considered as a part of the list.
Hi,
Thanks for the great work. I am planning to use in favour of npmjs.com/package/draft-js-utils.
I would like to know do you have any plans to support sub/sup tag?
If I enter _abc_
into the draft editor, I'd expect to see the Markdown editor have \_abc\_
.
There are a set of similar test cases:
* sdfsfsf
=> \* sdfsfsf
abc **sdasda**
=> abc \*\*sdasda\*\*
4. abc
=> 4\. abc
c `abc` d
=> c \`abc\` d
> sdfjsflsdkfj
=> \> sdfjsflsdkfj
\abc
=> \\abc
There is the setting escapeMarkdownCharacters
which apparently only works markdown -> draft, which is not very intuitive for me, because when loading the content i want the stored markdown to be restored to the draft state.
However there's no option to escape markdown when converting draft -> markdown, if I want to escape user inputs. Draft returns blocks with bare text and styling information. Can there be either an option to also escape in this direction, or a callback to modify text while converting and before the style is applied, so I can write the escaping myself
Similar to #17
Draft.EditorState.createWithContent(Draft.convertFromRaw(markdownToDraft('-')))
Draft.EditorState.createWithContent(Draft.convertFromRaw(markdownToDraft('1.')))
hi there,
i noticed that although the standard styles like headings, bold, and italics are supported i am still unable to render mentions, links, or strikethrough properly.
this is the code line i use to extract editor content as markdown (to then store in a DB):
draftToMarkdown(convertToRaw(editorState.getCurrentContent()));
this is the code im using to render it back up as readOnly
const rawData = markdownToDraft(note.note, {
remarkablePreset: 'commonmark',
remarkableOptions: {
enable: {
inline: ['links', 'emphasis'],
core: ['abbr']
}
}
});
const contentState = convertFromRaw(rawData);
const editorState = EditorState.createWithContent(contentState);
...
<Editor editorState={editorState} onChange={() => {}} readOnly={true}/>
i noticed when displaying previously saved strikethrough text, the text was bounded by '~~' , links just appear as normal text, and mentions dont seem to be registered as links to the drafToMarkdown conversion (?)
I'm trying to exclude the conversion of links and images when converting from markdown to raw. Is there a settings flag I can set to disable it? Or maybe in the remark config?
Thank you for your work, the plugin is really handy
See failing test here: 71b848b
Would only be an issue for people using preserveNewlines: true
as by default stripping those newlines is correct markdown behaviour.
However, we have a hack around preserving newlines when the option is turned on, and in this case it isn't working correctly. The case being where we have one single block quote with blank lines in between text.
Something like this for draft js should be generated for blank lines -
> test
>
>
>
> hello!
but instead we end up with something like
> test
> hello
Hi!, your library is awesome!.
I've been encountering a cornercase bug. Whenever I set up a link entity on the end of the whole draft object, it breaks and translates to the following [LINK instead of [LINK]
(www.my_link.com). Any link entity ranged in between all blocks and chars work perfectly.
Example:
hello click here LINK_1
and here LINK_2
in that example LINK_1 translates to markdown but LINK_2 translates to [LINK_2
Thank you in advance!
Leo
Example of something that would fail:
bold text with italic inside that continues after bold doesn't
This should be rendered as:
**bold text _with italic inside_** _that continues after bold doesn't_
But instead is being rendered as
**bold text _with italic inside** that continues after bold doesn't_
I think we'll have to keep track of what inline "tags" are currently open and make sure we close/reopen nested children if a parent closes before the child is done.
var markdownString = draftToMarkdown(rawObject, {
entityItems: {
mention: {
open: function (entity) {
return '<span class="mention-item" data-user-id="' + entity.data.id + '">';
},
close: function (entity) {
return '</span>';
}
}
}
});
We have a way to specify open and close, but no content.
Suggest to add:
text: function (entity) {
}
not sure about function name
GitHub lets you write fenced codeblocks with syntax highlighting:
const javascript = true;
const highlighted = true;
The syntax for defining the language to highlight as is
```javascript
const javascript = true;
const highlighted = true;
It'd be great if markdown-draft-js
recognized that language declaration and added either a language
or a syntax
field to the data
of the code block so that e.g. the draft-js-prism-plugin
can pick it up.
I am working in a project that has quite a few custom markdown syntax, i've been given the task to create a rich text editor for it, and have been trying to figure out how to convert the markdown to draft while handling this custom syntax.
I've written a remarkable plugin that handles for example an opening warning tag:
<warning>
## Warning title
This is an **important** warning!
</warning>
This plugin uses a block rule
which according to the remarkable documentation made sense.
By digging into the markdown-to-draft.js implementation I noticed that only inline
item types from the remarkable parsedData
handle block entities.
I've also tried implementing this using the blockTypes
to no avail.
My question is, how to handle custom block rules and convert them into an atomic block with entity data?
so that you have CI in your prs?
Hi, thanks again for this awesome library!
When I try to convert an MD code block to Draft, a newline is added to the bottom of the code block. For my application, this means that each time a user switches from Draft editing to MD editing, a newline is added to all his code blocks.
const initialString = '```\ncountTheNewLines\n```';
const contentObject = Draft.EditorState.createWithContent(Draft.convertFromRaw(markdownToDraft(initialString)));
const newString = draftToMarkdown(
convertToRaw(contentObject.getCurrentContent())
);
console.log(newString); // '```\ncountTheNewLines\n\n```'
The markdown hr
block (horizontal rule) is currently not supported by markdown-to-draft.
When the markdown contains the hr
block code, for example this line:
---
This code is suppressed (see below) when converting the markdown to the raw Draft.js object.
We would like to add a custom blockType
to handle these hr
blocks, like this:
var rawDraftJSObject = markdownToDraft(markdownString, {
blockTypes: {
hr: function (_item) {
return {
type: 'HR',
text: '',
};
}
}
});
So that we could use the blockRendererFn
of Draft.js to render a custom component for this HR
block type, like this:
function blockRendererFn(contentBlock) {
if (contentBlock.getType() === 'HR') {
return {
component: MyCustomHrComponent,
editable: false,
};
}
}
// in React's render method
<Editor
blockRendererFn={blockRendererFn}
/>
// some sample component to be used by Draft.js for displaying the `HR` block type
const MyCustomHrComponent = () => {
return (
<figure>
<p>MY-CUSTOM-HR-COMPONENT</p>
</figure>
);
}
Remarkable already knows this hr
block (see remarkable hr block rule), and pushes a token with the type hr
to the state.
The issue is (as far as I see) that markdown-to-draft silently drops this type here:
markdown-draft-js/src/markdown-to-draft.js
Line 236 in 96ffba6
itemType
would be 'hr'
here. But even if we added this block type to the options.blockTypes
(as I did above), the first part of this expression would skip this item.
TL;DR: would it be possible to add the 'hr'
block type here, like this?
} else if ((itemType.indexOf('_open') !== -1 || itemType === 'fence' || itemType === 'hr') && BlockTypes[itemType]) {
I have PreserveNewLines enabled in the config, but it doesn't seem to be working.
markdown
foo
bar
rich text actual
foo
bar
rich text expected
foo
bar
eek that deadline came out of nowhere.
Hey!
I created a microservice version of your module! draft-to-markdown.now.sh
Your module is awesome, so useful for what I'm working on!
The demo at http://www.roserobertson.me/markdown-draft-js/ is using 2.0.0. It'd be great if the demo page was updated, but also listed the version it is using so that people who are running into issues might be able to understand why their usage doesn't match the demo.
Do you want to request a feature or report a bug?
I think is a bug
What is the current behavior?
the order list with error-index when inserting some text into 2 order list.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. You can use this jsfiddle to get started: https://jsfiddle.net/gmertk/e61z7nfa/.
the demo link: http://www.roserobertson.me/markdown-draft-js/
To Test:
there are some videos and screenshots for regression. The following:
What is the expected behavior?
With correct index
Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js?
Chrome Version 79.0.3945.88 (Official B
uild) (32-bit)
Is there any way to get it to convert a single linebreak as double space
, and double linebreak as \n
Currently I can't seem to find a way to handle this :/
First of all, thank you so much for sharing this plugin!
An error occurs when a markdown line is converted to DraftJS with one or multiple #
symbols that is not followed by regular characters. A header block is created, but since it does not have a text
attribute, it's length cannot be calculated.
Uncaught TypeError: Cannot read property 'length' of undefined
at decodeInlineStyleRanges (webpack:///./~/draft-js/lib/decodeInlineStyleRanges.js?:30:26)
at eval (webpack:///./~/draft-js/lib/convertFromRawToDraftState.js?:66:24)
at Array.map (native)
at Object.convertFromRawToDraftState [as convertFromRaw] (webpack:///./~/draft-js/lib/convertFromRawToDraftState.js?:50:30)
at createDraftFromMarkdown (webpack:///./app/helpers/markdownHelper.js?:20:76)
at reducer (webpack:///./app/state/markdownEditor/reducer.js?:50:106)
at eval (webpack:///./~/redux-immutable/dist/combineReducers.js?:37:31)
at Array.forEach (native)
at eval (webpack:///./~/redux-immutable/dist/combineReducers.js?:34:19)
at Map.withMutations (webpack:///./~/immutable/dist/immutable.js?:1355:7)
The bug can be replicated like this
Draft.EditorState.createWithContent(Draft.convertFromRaw(markdownToDraft('#')))
If we take the constructed object, and add a text
attribute string to the header block, there are no errors.
var object = markdownToDraft('#');
object.blocks[0].text = 'test'
Draft.EditorState.createWithContent(Draft.convertFromRaw(object))
Perhaps the header block should contain an empty string as its text
attribute.
If I type into the draft editor: abcXYZabc where XYZ is italic , it will render the markdown as abc_XYZ_abc
(this is fine). When that gets converted back into DraftJS, the text is rendered as abc_XYZ_abc
.
#hashtag
is not considered as heading in markdown, as there is no space after #
.
We should not escape it like this: \#hashtag
, when converting from DraftJS to markdown.
Hi, I was checking out the demo: http://www.roserobertson.me/markdown-draft-js/ and noticed that if I end a line in the markdown with two spaces and a new-line then the next line is just appended on to the first in the draft-js.
This is intended?
I'm finding it hard to understand this:
preserveNewlines can be passed in to preserve empty whitespace newlines. By default, markdown rules specify that blank whitespace is collapsed, but in the interest in maintaining 1:1 parity with draft appearance-wise, this option can be turned on if you like :)
Does collapsing newlines mean that only a max of one empty line is kept (two new-line characters are retained when there are many new-line characters) or that NO empty line is kept (only one new-line character is ever kept)
When the initial value is blank (which is very likely in my particular case), markdownToDraft
throws:
markdownToDraft('')
// Uncaught TypeError: Cannot read property 'getKey' of undefined
Markdown like this comes out wrong:
__*hello* world__
Here the inlineStyleRanges should range from 0
to 5
and 0
to 11
respectively.
Instead, the bold style range comes out as 0-11
and the italic style length stays at 0
o_O
Hi Rosey,
Thank you for the work on this great plugin. Would it be possible to provide the code to the remarkableMentionPlugin
in the docs? I'm trying to create a plugin to convert the htmltag to DraftJS, but I can't figure out how to write the plugin. The remarkable plugin docs are very cryptic.
In your code snippet, where does blockEntities.mention_open
come from? Is this something created in your plugin?
What in the world is the item argument passed to the mention_open
method?
I know you're very busy, but if you have the time to dump the code for the plugin somewhere, it would be super helpful to understanding how the conversion from markdownToDraft can be extended.
Thank you :)
When the user has bold enabled and starts typing, this will result in invalid markdown every time the user types a space:
some words before bold, **some words in bold **and some words after bold
Because the space after the word "bold" is before the two stars instead of after them, this will result in a plain text (containing the actual stars).
First up, I just wanted to say thanks for this project and especially for making the interactive demo of it so easily available. It looks like it's going to be a big help for me. It seems to have much better support for escaping markdown special characters than some alternatives I've also tried, which sets it apart. Also, thanks for setting expectations on turnaround for any discussion or a fix. I know that these are highly unusual times and would not ever want to cause any distress by this, so please only respond if or when you feel able to do so comfortably.
That said, I was playing around with the interactive tool and noticed a seemingly small quirk in the way bold and italics are handled that I can reproduce reliably:
**bold_both_**_italics_
Manually entering the following markdown seems to generate the correct formatting in the draftjs editor however: __bold__***both***_italics_
I'm not sure if this is a hard fix or an easy one, but I thought I'd record it here since I found a good way to reproduce.
(As a side note, I'll also mention that GitHub themselves seem to have a very similar issue generating correct markdown for this formatting. That suggests this might be a tough problem. If you use the formatting buttons in the GitHub editor to create boldbothitalics, you end up with the following markdown: **bold_both**italics_
which renders as bold_bothitalics_.)
Hi,
I was upgrading draft-js from 0.10.5 to 0.11.4 and then I received some errors in the console and my react-app crashed.
invariant.js:40 Uncaught Invariant Violation: block is not a BlockNode at invariant (http://localhost:3000/static/js/0.chunk.js:54726:15) at insertRawBlock (http://localhost:3000/static/js/0.chunk.js:35067:50) at http://localhost:3000/static/js/0.chunk.js:35109:5 at http://localhost:3000/static/js/0.chunk.js:112326:23 at List.__iterate (http://localhost:3000/static/js/0.chunk.js:111793:11) at OrderedMap.__iterate (http://localhost:3000/static/js/0.chunk.js:112325:23) at OrderedMap.forEach (http://localhost:3000/static/js/0.chunk.js:114185:19) at encodeRawBlocks (http://localhost:3000/static/js/0.chunk.js:35088:30) at convertFromDraftStateToRaw (http://localhost:3000/static/js/0.chunk.js:35143:26) at Object.DraftJsEditor.onChange (http://localhost:3000/static/js/main.chunk.js:5599:92) at Object.MediumDraftEditor._this.onChange (http://localhost:3000/static/js/0.chunk.js:95439:19) at DraftEditor._this.update (http://localhost:3000/static/js/0.chunk.js:98651:19) at editOnFocus (http://localhost:3000/static/js/0.chunk.js:104621:12)
and
The above error occurred in the <DraftJsEditor> component: in DraftJsEditor (at MessageForm.tsx:209) in form (created by Form) in Form (at MessageForm.tsx:208) in div (created by Segment) in Segment (at MessageForm.tsx:207) in MessageEditForm (created by ConnectFunction) in ConnectFunction (created by withI18nextTranslation(Connect(MessageEditForm))) in withI18nextTranslation(Connect(MessageEditForm)) (at Messages/index.tsx:513) in div (at Messages/index.tsx:511)
Does anyone have an idea what happened there? The error depends on the version and nodejs packages but I don't get it...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.