improve visual/raw editor consistency
This commit is contained in:
parent
5cbc76da68
commit
cba631ba1a
@ -157,6 +157,7 @@
|
|||||||
"redux-notifications": "^2.1.1",
|
"redux-notifications": "^2.1.1",
|
||||||
"redux-optimist": "^0.0.2",
|
"redux-optimist": "^0.0.2",
|
||||||
"redux-thunk": "^1.0.3",
|
"redux-thunk": "^1.0.3",
|
||||||
|
"rehype-minify-whitespace": "^2.0.0",
|
||||||
"rehype-parse": "^3.1.0",
|
"rehype-parse": "^3.1.0",
|
||||||
"rehype-raw": "^1.0.0",
|
"rehype-raw": "^1.0.0",
|
||||||
"rehype-react": "^3.0.0",
|
"rehype-react": "^3.0.0",
|
||||||
|
@ -8,6 +8,7 @@ import htmlToRehype from 'rehype-parse';
|
|||||||
import rehypeToRemark from 'rehype-remark';
|
import rehypeToRemark from 'rehype-remark';
|
||||||
import remarkToMarkdown from 'remark-stringify';
|
import remarkToMarkdown from 'remark-stringify';
|
||||||
import rehypeSanitize from 'rehype-sanitize';
|
import rehypeSanitize from 'rehype-sanitize';
|
||||||
|
import rehypeMinifyWhitespace from 'rehype-minify-whitespace';
|
||||||
import rehypeReparse from 'rehype-raw';
|
import rehypeReparse from 'rehype-raw';
|
||||||
import CaretPosition from 'textarea-caret-position';
|
import CaretPosition from 'textarea-caret-position';
|
||||||
import TextareaAutosize from 'react-textarea-autosize';
|
import TextareaAutosize from 'react-textarea-autosize';
|
||||||
@ -41,6 +42,8 @@ function cleanupPaste(paste) {
|
|||||||
.use(rehypeSanitize)
|
.use(rehypeSanitize)
|
||||||
.use(rehypeReparse)
|
.use(rehypeReparse)
|
||||||
.use(rehypeToRemark)
|
.use(rehypeToRemark)
|
||||||
|
.use(rehypeSanitize)
|
||||||
|
.use(rehypeMinifyWhitespace)
|
||||||
.use(remarkToMarkdown, remarkStringifyConfig)
|
.use(remarkToMarkdown, remarkStringifyConfig)
|
||||||
.process(paste);
|
.process(paste);
|
||||||
}
|
}
|
||||||
@ -84,7 +87,7 @@ export default class RawEditor extends React.Component {
|
|||||||
const plugins = registry.getEditorComponents();
|
const plugins = registry.getEditorComponents();
|
||||||
this.state = {
|
this.state = {
|
||||||
value: unified()
|
value: unified()
|
||||||
.use(htmlToRehype, rehypeParseConfig)
|
.use(htmlToRehype)
|
||||||
.use(rehypeToRemark)
|
.use(rehypeToRemark)
|
||||||
.use(remarkToMarkdown, remarkStringifyConfig)
|
.use(remarkToMarkdown, remarkStringifyConfig)
|
||||||
.processSync(this.props.value)
|
.processSync(this.props.value)
|
||||||
@ -255,13 +258,17 @@ export default class RawEditor extends React.Component {
|
|||||||
|
|
||||||
handleChange = (e) => {
|
handleChange = (e) => {
|
||||||
// handleChange may receive an event or a value
|
// 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()
|
const html = unified()
|
||||||
.use(markdownToRemark, remarkParseConfig)
|
.use(markdownToRemark, remarkParseConfig)
|
||||||
.use(remarkToRehype)
|
.use(remarkToRehype)
|
||||||
|
.use(rehypeSanitize)
|
||||||
|
.use(rehypeMinifyWhitespace)
|
||||||
.use(rehypeToHtml, rehypeStringifyConfig)
|
.use(rehypeToHtml, rehypeStringifyConfig)
|
||||||
|
|
||||||
.processSync(value)
|
.processSync(value)
|
||||||
.contents;
|
.contents;
|
||||||
|
console.log(html);
|
||||||
this.props.onChange(html);
|
this.props.onChange(html);
|
||||||
this.updateHeight();
|
this.updateHeight();
|
||||||
this.setState({ value });
|
this.setState({ value });
|
||||||
|
@ -107,7 +107,7 @@ const BLOCK_TAGS = {
|
|||||||
h3: 'heading-three',
|
h3: 'heading-three',
|
||||||
h4: 'heading-four',
|
h4: 'heading-four',
|
||||||
h5: 'heading-five',
|
h5: 'heading-five',
|
||||||
h6: 'heading-six'
|
h6: 'heading-six',
|
||||||
}
|
}
|
||||||
|
|
||||||
const MARK_TAGS = {
|
const MARK_TAGS = {
|
||||||
@ -115,6 +115,7 @@ const MARK_TAGS = {
|
|||||||
em: 'italic',
|
em: 'italic',
|
||||||
u: 'underline',
|
u: 'underline',
|
||||||
s: 'strikethrough',
|
s: 'strikethrough',
|
||||||
|
del: 'strikethrough',
|
||||||
code: 'code'
|
code: 'code'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +132,12 @@ const BLOCK_COMPONENTS = {
|
|||||||
'heading-four': props => <h4 {...props.attributes}>{props.children}</h4>,
|
'heading-four': props => <h4 {...props.attributes}>{props.children}</h4>,
|
||||||
'heading-five': props => <h5 {...props.attributes}>{props.children}</h5>,
|
'heading-five': props => <h5 {...props.attributes}>{props.children}</h5>,
|
||||||
'heading-six': props => <h6 {...props.attributes}>{props.children}</h6>,
|
'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 = {
|
const NODE_COMPONENTS = {
|
||||||
@ -139,8 +146,7 @@ const NODE_COMPONENTS = {
|
|||||||
const href = props.node && props.node.getIn(['data', 'href']) || props.href;
|
const href = props.node && props.node.getIn(['data', 'href']) || props.href;
|
||||||
return <a href={href} {...props.attributes}>{props.children}</a>;
|
return <a href={href} {...props.attributes}>{props.children}</a>;
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const MARK_COMPONENTS = {
|
const MARK_COMPONENTS = {
|
||||||
bold: props => <strong>{props.children}</strong>,
|
bold: props => <strong>{props.children}</strong>,
|
||||||
@ -162,6 +168,9 @@ const RULES = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
serialize(entity, children) {
|
serialize(entity, children) {
|
||||||
|
if (['bulleted-list', 'numbered-list'].includes(entity.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const component = BLOCK_COMPONENTS[entity.type]
|
const component = BLOCK_COMPONENTS[entity.type]
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return;
|
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.
|
// Special case for links, to grab their href.
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
@ -229,6 +264,15 @@ const RULES = [
|
|||||||
return NODE_COMPONENTS.link(props);
|
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 });
|
const serializer = new SlateHtml({ rules: RULES });
|
||||||
@ -237,6 +281,7 @@ export default class Editor extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
const plugins = registry.getEditorComponents();
|
const plugins = registry.getEditorComponents();
|
||||||
|
console.log(this.props.value);
|
||||||
this.state = {
|
this.state = {
|
||||||
editorState: serializer.deserialize(this.props.value || '<p></p>'),
|
editorState: serializer.deserialize(this.props.value || '<p></p>'),
|
||||||
schema: {
|
schema: {
|
||||||
@ -271,6 +316,7 @@ export default class Editor extends Component {
|
|||||||
b: 'bold',
|
b: 'bold',
|
||||||
i: 'italic',
|
i: 'italic',
|
||||||
u: 'underlined',
|
u: 'underlined',
|
||||||
|
s: 'strikethrough',
|
||||||
'`': 'code',
|
'`': 'code',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export const remarkParseConfig = { fences: true };
|
export const remarkParseConfig = { fences: true };
|
||||||
export const remarkStringifyConfig = { fences: true };
|
export const remarkStringifyConfig = { listItemIndent: '1', fences: true };
|
||||||
export const rehypeParseConfig = { fragment: true };
|
export const rehypeParseConfig = { fragment: true };
|
||||||
export const rehypeStringifyConfig = {};
|
export const rehypeStringifyConfig = {};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user