diff --git a/conf/storybook/webpack.config.js b/conf/storybook/webpack.config.js
index 370d4ab..7dde8c8 100644
--- a/conf/storybook/webpack.config.js
+++ b/conf/storybook/webpack.config.js
@@ -6,5 +6,15 @@ module.exports = {
path.resolve( './src' ),
],
},
+ module: {
+ loaders: [
+ {
+ test: /plugin\.css$/,
+ loaders: [
+ 'style', 'css',
+ ],
+ },
+ ],
+ }
};
diff --git a/package.json b/package.json
index 6d7217c..f2d6db0 100644
--- a/package.json
+++ b/package.json
@@ -58,9 +58,11 @@
"babel-runtime": "^6.5.0",
"css-loader": "^0.23.1",
"debug": "^2.2.0",
- "draft-js": "0.9.0",
- "draft-js-mention-plugin": "1.1.0",
- "draft-js-plugins-editor": "1.1.0",
+ "draft-js": "0.9.1",
+ "draft-js-linkify-plugin": "^2.0.0-beta5",
+ "draft-js-mention-plugin": "2.0.0-beta5",
+ "draft-js-plugins-editor": "2.0.0-beta5",
+ "draft-js-undo-plugin": "^2.0.0-beta5",
"enzyme": "^2.4.1",
"express": "^4.13.4",
"falcor": "^0.1.16",
diff --git a/src/components/reference-editor/index.js b/src/components/reference-editor/index.js
new file mode 100644
index 0000000..bec2a86
--- /dev/null
+++ b/src/components/reference-editor/index.js
@@ -0,0 +1,54 @@
+import React, { PropTypes } from 'react';
+import reactStamp from 'react-stamp';
+
+import EditorFactory from 'components/editor';
+
+import createMentionPlugin, { defaultSuggestionsFilter } from 'draft-js-mention-plugin';
+import createUndoPlugin from 'draft-js-undo-plugin';
+import createLinkifyPlugin from 'draft-js-linkify-plugin';
+
+import 'draft-js-mention-plugin/lib/plugin.css';
+import 'draft-js-undo-plugin/lib/plugin.css';
+import 'draft-js-linkify-plugin/lib/plugin.css';
+
+import MentionComponent from './mention-text';
+import SuggestionsFactory from './suggestions';
+
+export default function ({
+ Editor = EditorFactory(React),
+ mentionPlugin = createMentionPlugin({ mentionComponent: MentionComponent }),
+ undoPlugin = createUndoPlugin(),
+ linkifyPlugin = createLinkifyPlugin(),
+} = {}) {
+ const { MentionSuggestions } = mentionPlugin;
+ const Suggestions = SuggestionsFactory(MentionSuggestions);
+
+ return (React, ...behaviours) => reactStamp(React).compose({
+ propTypes: {
+ onSearchChange: PropTypes.func,
+ searchSuggestions: PropTypes.arrayOf(PropTypes.shape({
+ type: PropTypes.oneOf(['character', 'element']).isRequired,
+ _id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ link: PropTypes.string.isRequired,
+ avatar: PropTypes.string.isRequired,
+ })).isRequired,
+ },
+
+ render() {
+ const { onSearchChange, searchSuggestions, plugins = [], ...rest } = this.props;
+ return (
+
+
+
+
+ );
+ },
+ });
+}
diff --git a/src/components/reference-editor/mention-text.js b/src/components/reference-editor/mention-text.js
new file mode 100644
index 0000000..bb578ec
--- /dev/null
+++ b/src/components/reference-editor/mention-text.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import { cyan700, green700 } from 'material-ui/lib/styles/colors';
+
+const MentionComponent = ({ mention, className, mentionPrefix, children }) => (
+
+ {mentionPrefix}{children}
+
+);
+
+export default MentionComponent;
diff --git a/src/components/reference-editor/spec.js b/src/components/reference-editor/spec.js
new file mode 100644
index 0000000..8c3d2af
--- /dev/null
+++ b/src/components/reference-editor/spec.js
@@ -0,0 +1,58 @@
+import React from 'react';
+import test from 'tape';
+import { shallow, mount } from 'enzyme';
+import spy, { createSpy } from '../../utils/spy';
+
+import {
+ EditorState,
+ ContentState,
+ ContentBlock,
+ CharacterMetadata,
+ convertToRaw,
+ convertFromRaw,
+ genKey,
+} from 'draft-js';
+
+import EditorFactory from './';
+import UpstreamEditorFactory from 'components/editor';
+
+const UpstreamEditor = UpstreamEditorFactory(React);
+
+test('ReferenceEditor', t => {
+ const mentionPlugin = { MentionSuggestions: () => () };
+ const undoPlugin = {};
+ const linkifyPlugin = {};
+
+ const Editor = EditorFactory({ Editor: UpstreamEditor, mentionPlugin, undoPlugin, linkifyPlugin })(React);
+ let instance, actual, expected;
+
+ const content = {};
+
+ instance = shallow();
+
+ {
+ const upstream = instance.find(UpstreamEditor).at(0);
+ t.ok(upstream, 'should render the editor');
+ }
+
+ {
+ const upstream = instance.find(UpstreamEditor).at(0);
+ const plugins = upstream.props().plugins;
+ t.notEquals(plugins.indexOf(mentionPlugin), -1, 'should manage mention plugin');
+ t.notEquals(plugins.indexOf(undoPlugin), -1, 'should manage undo plugin');
+ t.notEquals(plugins.indexOf(linkifyPlugin), -1, 'should manage linkify plugin');
+ }
+
+ {
+ const onSearchChange = () => {};
+ const searchSuggestions = [];
+ instance = shallow();
+ const suggestions = instance.children().at(1);
+
+ t.ok(suggestions, 'renders suggestion list');
+ t.equals(suggestions.props().onSearchChange, onSearchChange, 'passed search callback down');
+ t.equals(suggestions.props().suggestions, searchSuggestions, 'passes suggestion list down');
+ }
+
+ t.end();
+});
diff --git a/src/components/reference-editor/story.js b/src/components/reference-editor/story.js
new file mode 100644
index 0000000..195d982
--- /dev/null
+++ b/src/components/reference-editor/story.js
@@ -0,0 +1,44 @@
+import React from 'react';
+import { storiesOf, action } from '@kadira/storybook';
+
+import EditorFactory from './';
+
+const Editor = EditorFactory()(React);
+
+import {
+ EditorState,
+ ContentState,
+ ContentBlock,
+ CharacterMetadata,
+ convertToRaw,
+ convertFromRaw,
+ genKey,
+} from 'draft-js';
+import { is, fromJS, List, Repeat } from 'immutable';
+
+const genContent = (text) => {
+ const contentState = ContentState.createFromBlockArray([
+ new ContentBlock({
+ key: 'abc',
+ type: 'unstyled',
+ text,
+ characterList: List(Repeat(CharacterMetadata.EMPTY, text.length))
+ }),
+ ]);
+ return convertToRaw(contentState);
+};
+
+storiesOf('Reference Editor', module)
+ .add('default', () => {
+ const initialContent = genContent('Here we go');
+ return (
+
+ );
+ });
diff --git a/src/components/reference-editor/suggestions/entry.js b/src/components/reference-editor/suggestions/entry.js
new file mode 100644
index 0000000..e40d522
--- /dev/null
+++ b/src/components/reference-editor/suggestions/entry.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import ListItem from 'material-ui/lib/lists/list-item';
+import Avatar from 'material-ui/lib/avatar';
+
+const EntryComponent = ({ mention, className, ...props }) => (
+ }
+ {...props}
+ >
+ {mention.get('name')}
+
+);
+
+export default EntryComponent;
diff --git a/src/components/reference-editor/suggestions/index.js b/src/components/reference-editor/suggestions/index.js
new file mode 100644
index 0000000..b07a28a
--- /dev/null
+++ b/src/components/reference-editor/suggestions/index.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import { fromJS } from 'immutable';
+import EntryComponent from './entry';
+
+export default function (MentionSuggestions) {
+ return ({ suggestions, ...rest }) => (
+
+ );
+}