Skip to content
This repository was archived by the owner on Oct 11, 2022. It is now read-only.

Commit b45cf44

Browse files
committed
merge
2 parents dc08cba + d0c5dcb commit b45cf44

28 files changed

+393
-363
lines changed

README.md

Lines changed: 79 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,64 @@ A [DraftJS] plugin for supporting Markdown syntax shortcuts in DraftJS. This plu
1717
npm i --save draft-js-markdown-plugin
1818
```
1919

20+
## Usage
21+
22+
```js
23+
import React, { Component } from 'react';
24+
import Editor from 'draft-js-plugins-editor';
25+
import createMarkdownPlugin from 'draft-js-markdown-plugin';
26+
import { EditorState } from 'draft-js';
27+
28+
export default class DemoEditor extends Component {
29+
30+
state = {
31+
editorState: EditorState.createEmpty(),
32+
plugins: [createMarkdownPlugin()]
33+
};
34+
35+
onChange = (editorState) => {
36+
this.setState({
37+
editorState,
38+
});
39+
};
40+
41+
render() {
42+
return (
43+
<Editor
44+
editorState={this.state.editorState}
45+
onChange={this.onChange}
46+
plugins={this.state.plugins}
47+
/>
48+
);
49+
}
50+
}
51+
```
52+
53+
### Add code block syntax highlighting
54+
55+
Using the [`draft-js-prism-plugin`](https://github.com/withspectrum/draft-js-prism-plugin) you can easily add syntax highlighting support to your code blocks!
56+
57+
```JS
58+
// Install prismjs and draft-js-prism-plugin
59+
import Prism from 'prismjs';
60+
import createPrismPlugin from 'draft-js-prism-plugin';
61+
62+
class Editor extends Component {
63+
state = {
64+
plugins: [
65+
// Add the Prism plugin to the plugins array
66+
createPrismPlugin({
67+
prism: Prism
68+
}),
69+
createMarkdownPlugin()
70+
]
71+
}
72+
}
73+
```
74+
2075
## Options
21-
The `draft-js-markdown-plugin` is configurable. Just pass a config object. Here are the available options:
2276

77+
The `draft-js-markdown-plugin` is configurable. Just pass a config object. Here are the available options:
2378

2479
### `renderLanguageSelect`
2580

@@ -57,6 +112,7 @@ const markdownPlugin = createMarkdownPlugin({ renderLanguageSelect })
57112
```
58113

59114
### `languages`
115+
60116
Dictionary for languages available to code block switcher
61117

62118
#### Example:
@@ -70,6 +126,7 @@ const markdownPlugin = createMarkdownPlugin({ languages })
70126
```
71127

72128
### `features`
129+
73130
A list of enabled features, by default all features are turned on.
74131

75132
```js
@@ -79,7 +136,7 @@ features = {
79136
}
80137
```
81138

82-
#### Example
139+
#### Example:
83140

84141
```
85142
// this will only enable BOLD for inline and CODE
@@ -125,60 +182,29 @@ import { CHECKABLE_LIST_ITEM } from "draft-js-checkable-list-item"
125182
]
126183
```
127184

185+
### `entityType`
128186

129-
## Usage
130-
131-
```js
132-
import React, { Component } from 'react';
133-
import Editor from 'draft-js-plugins-editor';
134-
import createMarkdownPlugin from 'draft-js-markdown-plugin';
135-
import { EditorState } from 'draft-js';
136-
137-
export default class DemoEditor extends Component {
138-
139-
state = {
140-
editorState: EditorState.createEmpty(),
141-
plugins: [createMarkdownPlugin()]
142-
};
143-
144-
onChange = (editorState) => {
145-
this.setState({
146-
editorState,
147-
});
148-
};
149-
150-
render() {
151-
return (
152-
<Editor
153-
editorState={this.state.editorState}
154-
onChange={this.onChange}
155-
plugins={this.state.plugins}
156-
/>
157-
);
158-
}
159-
}
160-
```
161-
162-
### Add code block syntax highlighting
163-
164-
Using the [`draft-js-prism-plugin`](https://github.com/withspectrum/draft-js-prism-plugin) you can easily add syntax highlighting support to your code blocks!
187+
To interoperate this plugin with other DraftJS plugins, i.e. [`draft-js-plugins`](https://github.com/draft-js-plugins/draft-js-plugins), you might need to customize the `LINK` and `IMAGE` entity type created by `draft-js-markdown-plugin`.
165188

166-
```JS
167-
// Install prismjs and draft-js-prism-plugin
168-
import Prism from 'prismjs';
169-
import createPrismPlugin from 'draft-js-prism-plugin';
189+
#### Example:
170190

171-
class Editor extends Component {
172-
state = {
173-
plugins: [
174-
// Add the Prism plugin to the plugins array
175-
createPrismPlugin({
176-
prism: Prism
177-
}),
178-
createMarkdownPlugin()
179-
]
180-
}
181-
}
191+
```js
192+
import createMarkdownPlugin from "draft-js-markdown-plugin";
193+
import createFocusPlugin from "draft-js-focus-plugin";
194+
import createImagePlugin from "draft-js-image-plugin";
195+
196+
const entityType = {
197+
IMAGE: "IMAGE",
198+
};
199+
200+
const focusPlugin = createFocusPlugin();
201+
const imagePlugin = createImagePlugin({
202+
decorator: focusPlugin.decorator,
203+
});
204+
// For `draft-js-image-plugin` to work, the entity type of an image must be `IMAGE`.
205+
const markdownPlugin = createMarkdownPlugin({ entityType });
206+
207+
const editorPlugins = [focusPlugin, imagePlugin, markdownPlugin];
182208
```
183209

184210
## Why fork the `markdown-shortcuts-plugin`?

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "draft-js-markdown-plugin",
3-
"version": "1.4.1",
3+
"version": "2.0.2",
44
"description": "A DraftJS plugin for supporting Markdown syntax shortcuts, fork of draft-js-markdown-shortcuts-plugin",
55
"main": "lib/index.js",
66
"scripts": {

src/__test__/plugin.test.js

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import {
44
CheckableListItemUtils,
55
} from "draft-js-checkable-list-item";
66

7-
import { defaultInlineWhitelist, defaultBlockWhitelist } from "../constants";
7+
import {
8+
defaultInlineWhitelist,
9+
defaultBlockWhitelist,
10+
ENTITY_TYPE,
11+
} from "../constants";
812

913
import { Map, List } from "immutable";
1014
import createMarkdownPlugin from "../";
@@ -224,37 +228,6 @@ describe("draft-js-markdown-plugin", () => {
224228
expect(store.setEditorState).toHaveBeenCalledWith(newEditorState);
225229
});
226230

227-
it("adds list item and transforms markdown", () => {
228-
// createMarkdownPlugin.__Rewire__("leaveList", modifierSpy); // eslint-disable-line no-underscore-dangle
229-
currentRawContentState = {
230-
entityMap: {},
231-
blocks: [
232-
{
233-
key: "item1",
234-
text: "**some bold text**",
235-
type: "unordered-list-item",
236-
depth: 0,
237-
inlineStyleRanges: [],
238-
entityRanges: [],
239-
data: {},
240-
},
241-
],
242-
};
243-
currentSelectionState = currentSelectionState.merge({
244-
focusOffset: 18,
245-
anchorOffset: 18,
246-
});
247-
expect(subject()).toBe("handled");
248-
// expect(modifierSpy).toHaveBeenCalledTimes(1);
249-
expect(store.setEditorState).toHaveBeenCalledTimes(1);
250-
newEditorState = store.setEditorState.mock.calls[0][0];
251-
const newRawContentState = Draft.convertToRaw(
252-
newEditorState.getCurrentContent()
253-
);
254-
expect(newRawContentState.blocks.length).toBe(2);
255-
expect(newEditorState.getCurrentInlineStyle().size).toBe(0);
256-
});
257-
258231
const emptyBlockTypes = [
259232
"blockquote",
260233
"header-one",
@@ -333,7 +306,6 @@ describe("draft-js-markdown-plugin", () => {
333306
event = new window.KeyboardEvent("keydown", props);
334307
});
335308
it("inserts new empty block", () => {
336-
createMarkdownPlugin.__Rewire__("insertEmptyBlock", modifierSpy); // eslint-disable-line no-underscore-dangle
337309
const text = "Hello";
338310
currentRawContentState = {
339311
entityMap: {},
@@ -349,9 +321,8 @@ describe("draft-js-markdown-plugin", () => {
349321
},
350322
],
351323
};
352-
expect(subject()).toBe("handled");
353-
expect(modifierSpy).toHaveBeenCalledTimes(1);
354-
expect(store.setEditorState).toHaveBeenCalledWith(newEditorState);
324+
expect(subject()).toBe("not-handled");
325+
expect(store.setEditorState).not.toHaveBeenCalled();
355326
});
356327
});
357328
});
@@ -516,14 +487,33 @@ describe("draft-js-markdown-plugin", () => {
516487
],
517488
};
518489
});
519-
["handleImage", "handleLink"].forEach(modifier => {
490+
["handleImage"].forEach(modifier => {
520491
describe(modifier, () => {
521492
beforeEach(() => {
522493
createMarkdownPlugin.__Rewire__(modifier, modifierSpy); // eslint-disable-line no-underscore-dangle
523494
});
524495
it("returns handled", () => {
525496
expect(subject()).toBe("handled");
526-
expect(modifierSpy).toHaveBeenCalledWith(currentEditorState, " ");
497+
expect(modifierSpy).toHaveBeenCalledWith(
498+
currentEditorState,
499+
" ",
500+
ENTITY_TYPE.IMAGE
501+
);
502+
});
503+
});
504+
});
505+
["handleLink"].forEach(modifier => {
506+
describe(modifier, () => {
507+
beforeEach(() => {
508+
createMarkdownPlugin.__Rewire__(modifier, modifierSpy); // eslint-disable-line no-underscore-dangle
509+
});
510+
it("returns handled", () => {
511+
expect(subject()).toBe("handled");
512+
expect(modifierSpy).toHaveBeenCalledWith(
513+
currentEditorState,
514+
" ",
515+
ENTITY_TYPE.LINK
516+
);
527517
});
528518
});
529519
});
@@ -615,6 +605,27 @@ describe("draft-js-markdown-plugin", () => {
615605
expect(subject()).toBe("not-handled");
616606
});
617607
});
608+
it("handles new code block on space", () => {
609+
createMarkdownPlugin.__Rewire__("handleNewCodeBlock", modifierSpy); // eslint-disable-line no-underscore-dangle
610+
currentRawContentState = {
611+
entityMap: {},
612+
blocks: [
613+
{
614+
key: "item1",
615+
text: "```",
616+
type: "unstyled",
617+
depth: 0,
618+
inlineStyleRanges: [],
619+
entityRanges: [],
620+
data: {},
621+
},
622+
],
623+
};
624+
character = " ";
625+
expect(subject()).toBe("handled");
626+
expect(modifierSpy).toHaveBeenCalledTimes(1);
627+
expect(store.setEditorState).toHaveBeenCalledWith(newEditorState);
628+
});
618629
});
619630
describe("handlePastedText", () => {
620631
let pastedText;

src/components/Code/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,16 @@ class CodeBlock extends PureComponent {
7373
const { setReadOnly } = this.props.blockProps;
7474
event.stopPropagation();
7575
setReadOnly(true);
76+
this.setState({
77+
isOpen: true,
78+
});
7679
};
7780

7881
onClickOutside = () => {
7982
if (this.state.isOpen === false) return;
83+
this.setState({
84+
isOpen: false,
85+
});
8086
const {
8187
getEditorState,
8288
setReadOnly,

src/constants.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@ import { CHECKABLE_LIST_ITEM } from "draft-js-checkable-list-item";
33
export const CODE_BLOCK_REGEX = /^```([\w-]+)?\s*$/;
44

55
export const inlineMatchers = {
6-
BOLD: [/\*\*(.+)\*\*$/g, /__(.+)__$/g],
7-
ITALIC: [/\*(.+)\*$/g, /_(.+)_$/g],
8-
CODE: [/`(.+)`$/g],
9-
STRIKETHROUGH: [/~~(.+)~~$/g],
6+
BOLD: [/\*(.+)\*$/g],
7+
ITALIC: [/_(.+)_$/g],
8+
CODE: [/`([^`]+)`$/g],
9+
STRIKETHROUGH: [/~(.+)~$/g],
1010
};
1111

1212
export const CODE_BLOCK_TYPE = "code-block";
1313

14+
export const ENTITY_TYPE = {
15+
IMAGE: "IMG",
16+
LINK: "LINK",
17+
};
18+
1419
export const defaultInlineWhitelist = [
1520
"BOLD",
1621
"ITALIC",

src/decorators/image/__test__/imageStrategy-test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Draft from "draft-js";
2+
import { ENTITY_TYPE } from "../../../constants";
23
import createImageStrategy from "../imageStrategy";
34

45
describe("imageStrategy", () => {
@@ -34,7 +35,9 @@ describe("imageStrategy", () => {
3435
});
3536
it("callbacks range", () => {
3637
const block = contentState.getBlockForKey("dtehj");
37-
const strategy = createImageStrategy();
38+
const strategy = createImageStrategy({
39+
entityType: ENTITY_TYPE.IMAGE,
40+
});
3841
const cb = jest.fn();
3942
expect(typeof block).toBe("object");
4043
strategy(block, cb, contentState);

src/decorators/image/imageStrategy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
const createImageStrategy = () => {
1+
const createImageStrategy = ({ entityType }) => {
22
const findImageEntities = (contentBlock, callback, contentState) => {
33
contentBlock.findEntityRanges(character => {
44
const entityKey = character.getEntity();
55
return (
66
entityKey !== null &&
7-
contentState.getEntity(entityKey).getType() === "IMG"
7+
contentState.getEntity(entityKey).getType() === entityType
88
);
99
}, callback);
1010
};

src/decorators/image/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import createImageStrategy from "./imageStrategy";
22
import Image from "../../components/Image";
33

4-
const createImageDecorator = () => ({
5-
strategy: createImageStrategy(),
4+
const createImageDecorator = ({ entityType }) => ({
5+
strategy: createImageStrategy({ entityType }),
66
component: Image,
77
});
88

0 commit comments

Comments
 (0)