improve visual/raw editor consistency

This commit is contained in:
Shawn Erquhart 2017-06-27 12:21:34 -04:00
parent 5cbc76da68
commit cba631ba1a
5 changed files with 1943 additions and 1059 deletions

View File

@ -157,6 +157,7 @@
"redux-notifications": "^2.1.1",
"redux-optimist": "^0.0.2",
"redux-thunk": "^1.0.3",
"rehype-minify-whitespace": "^2.0.0",
"rehype-parse": "^3.1.0",
"rehype-raw": "^1.0.0",
"rehype-react": "^3.0.0",

View File

@ -8,6 +8,7 @@ import htmlToRehype from 'rehype-parse';
import rehypeToRemark from 'rehype-remark';
import remarkToMarkdown from 'remark-stringify';
import rehypeSanitize from 'rehype-sanitize';
import rehypeMinifyWhitespace from 'rehype-minify-whitespace';
import rehypeReparse from 'rehype-raw';
import CaretPosition from 'textarea-caret-position';
import TextareaAutosize from 'react-textarea-autosize';
@ -41,6 +42,8 @@ function cleanupPaste(paste) {
.use(rehypeSanitize)
.use(rehypeReparse)
.use(rehypeToRemark)
.use(rehypeSanitize)
.use(rehypeMinifyWhitespace)
.use(remarkToMarkdown, remarkStringifyConfig)
.process(paste);
}
@ -84,7 +87,7 @@ export default class RawEditor extends React.Component {
const plugins = registry.getEditorComponents();
this.state = {
value: unified()
.use(htmlToRehype, rehypeParseConfig)
.use(htmlToRehype)
.use(rehypeToRemark)
.use(remarkToMarkdown, remarkStringifyConfig)
.processSync(this.props.value)
@ -255,13 +258,17 @@ export default class RawEditor extends React.Component {
handleChange = (e) => {
// handleChange may receive an event or a value
const value = get(e, ['target', 'value']) || e;
const value = typeof e === 'object' ? e.target.value : e;
const html = unified()
.use(markdownToRemark, remarkParseConfig)
.use(remarkToRehype)
.use(rehypeSanitize)
.use(rehypeMinifyWhitespace)
.use(rehypeToHtml, rehypeStringifyConfig)
.processSync(value)
.contents;
console.log(html);
this.props.onChange(html);
this.updateHeight();
this.setState({ value });

View File

@ -107,7 +107,7 @@ const BLOCK_TAGS = {
h3: 'heading-three',
h4: 'heading-four',
h5: 'heading-five',
h6: 'heading-six'
h6: 'heading-six',
}
const MARK_TAGS = {
@ -115,6 +115,7 @@ const MARK_TAGS = {
em: 'italic',
u: 'underline',
s: 'strikethrough',
del: 'strikethrough',
code: 'code'
}
@ -131,6 +132,12 @@ const BLOCK_COMPONENTS = {
'heading-four': props => <h4 {...props.attributes}>{props.children}</h4>,
'heading-five': props => <h5 {...props.attributes}>{props.children}</h5>,
'heading-six': props => <h6 {...props.attributes}>{props.children}</h6>,
'image': props => {
const data = props.node && props.node.get('data');
const src = data && data.get('src', props.src);
const alt = data && data.get('alt', props.alt);
return <img src={src} alt={alt} {...props.attributes}/>;
},
};
const NODE_COMPONENTS = {
@ -139,8 +146,7 @@ const NODE_COMPONENTS = {
const href = props.node && props.node.getIn(['data', 'href']) || props.href;
return <a href={href} {...props.attributes}>{props.children}</a>;
},
}
};
const MARK_COMPONENTS = {
bold: props => <strong>{props.children}</strong>,
@ -162,6 +168,9 @@ const RULES = [
}
},
serialize(entity, children) {
if (['bulleted-list', 'numbered-list'].includes(entity.type)) {
return;
}
const component = BLOCK_COMPONENTS[entity.type]
if (!component) {
return;
@ -203,6 +212,32 @@ const RULES = [
}
},
},
{
deserialize(el, next) {
if (el.tagName != 'img') return
return {
kind: 'inline',
type: 'image',
nodes: [],
data: {
src: el.attribs.src,
alt: el.attribs.alt,
}
}
},
serialize(entity, children) {
if (entity.type !== 'image') {
return;
}
const data = entity.get('data');
const props = {
src: data.get('src'),
alt: data.get('alt'),
attributes: data.get('attributes'),
};
return NODE_COMPONENTS.image(props);
}
},
{
// Special case for links, to grab their href.
deserialize(el, next) {
@ -229,6 +264,15 @@ const RULES = [
return NODE_COMPONENTS.link(props);
}
},
{
serialize(entity, children) {
if (!['bulleted-list', 'unordered-list'].includes(entity.type)) {
return;
}
return NODE_COMPONENTS[entity.type]({ children });
}
}
]
const serializer = new SlateHtml({ rules: RULES });
@ -237,6 +281,7 @@ export default class Editor extends Component {
constructor(props) {
super(props);
const plugins = registry.getEditorComponents();
console.log(this.props.value);
this.state = {
editorState: serializer.deserialize(this.props.value || '<p></p>'),
schema: {
@ -271,6 +316,7 @@ export default class Editor extends Component {
b: 'bold',
i: 'italic',
u: 'underlined',
s: 'strikethrough',
'`': 'code',
};

View File

@ -1,4 +1,4 @@
export const remarkParseConfig = { fences: true };
export const remarkStringifyConfig = { fences: true };
export const remarkStringifyConfig = { listItemIndent: '1', fences: true };
export const rehypeParseConfig = { fragment: true };
export const rehypeStringifyConfig = {};

2936
yarn.lock

File diff suppressed because it is too large Load Diff