add inline image support for editor
This commit is contained in:
parent
e937e8e626
commit
70a4a51b97
@ -35,7 +35,6 @@ export const NODE_COMPONENTS = {
|
||||
'numbered-list': props =>
|
||||
<ol {...props.attributes} start={props.node.data.get('start') || 1}>{props.children}</ol>,
|
||||
'link': props => {
|
||||
// Need to wrap this in mark components for any marks found in data.
|
||||
const data = props.node.get('data');
|
||||
const marks = data.get('marks');
|
||||
const url = data.get('url');
|
||||
@ -47,6 +46,19 @@ export const NODE_COMPONENTS = {
|
||||
}, link);
|
||||
return result;
|
||||
},
|
||||
'image': props => {
|
||||
const data = props.node.get('data');
|
||||
const marks = data.get('marks');
|
||||
const url = data.get('url');
|
||||
const title = data.get('title');
|
||||
const alt = data.get('alt');
|
||||
const image = <img src={url} title={title} alt={alt} {...props.attributes}/>;
|
||||
const result = !marks ? image : marks.reduce((acc, mark) => {
|
||||
const MarkComponent = MARK_COMPONENTS[mark.type];
|
||||
return <MarkComponent>{acc}</MarkComponent>;
|
||||
}, image);
|
||||
return result;
|
||||
},
|
||||
'shortcode': props => {
|
||||
const { attributes, node, state: editorState } = props;
|
||||
const isSelected = editorState.selection.hasFocusIn(node);
|
||||
|
@ -28,4 +28,8 @@ describe('slate', () => {
|
||||
expect(process('**a**b**c**')).toEqual('**a**b**c**\n');
|
||||
expect(process('**a _b_ c**')).toEqual('**a _b_ c**\n');
|
||||
});
|
||||
|
||||
it('should parse inline images as images', () => {
|
||||
expect(process('a ![b](c)')).toEqual('a ![b](c)\n');
|
||||
});
|
||||
});
|
||||
|
@ -1,18 +1,26 @@
|
||||
/**
|
||||
* Images must be parsed as shortcodes for asset proxying. This plugin converts
|
||||
* MDAST image nodes back to text to allow shortcode pattern matching.
|
||||
* MDAST image nodes back to text to allow shortcode pattern matching. Note that
|
||||
* this transformation only occurs for images that are the sole child of a top
|
||||
* level paragraph - any other image is left alone and treated as an inline
|
||||
* image.
|
||||
*/
|
||||
export default function remarkImagesToText() {
|
||||
return transform;
|
||||
|
||||
function transform(node) {
|
||||
const children = node.children ? node.children.map(transform) : node.children;
|
||||
if (node.type === 'image') {
|
||||
const alt = node.alt || '';
|
||||
const url = node.url || '';
|
||||
const title = node.title ? ` "${node.title}"` : '';
|
||||
return { type: 'text', value: `![${alt}](${url}${title})` };
|
||||
const children = node.children.map(child => {
|
||||
if (
|
||||
child.type === 'paragraph'
|
||||
&& child.children.length === 1
|
||||
&& child.children[0].type === 'image'
|
||||
) {
|
||||
const { alt = '', url = '', title = '' } = child.children[0];
|
||||
const value = `![${alt}](${url}${title ? ' title' : ''})`;
|
||||
child.children = [{ type: 'text', value }];
|
||||
}
|
||||
return child;
|
||||
});
|
||||
return { ...node, children };
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ function createBlock(type, nodes, props = {}) {
|
||||
/**
|
||||
* Create a Slate Block node.
|
||||
*/
|
||||
function createInline(type, nodes, props = {}) {
|
||||
function createInline(type, props = {}, nodes) {
|
||||
return { kind: 'inline', type, nodes, ...props };
|
||||
}
|
||||
|
||||
@ -312,9 +312,23 @@ function convertNode(node, nodes) {
|
||||
case 'link': {
|
||||
const { title, url, data } = node;
|
||||
const newData = { ...data, title, url };
|
||||
return createInline(typeMap[type], nodes, { data: newData });
|
||||
return createInline(typeMap[type], { data: newData }, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Images
|
||||
*
|
||||
* Identical to link nodes except for the lack of child nodes and addition
|
||||
* of alt attribute data MDAST stores the link attributes directly on the
|
||||
* node, while our Slate schema references them in the data object.
|
||||
*/
|
||||
case 'image': {
|
||||
const { title, url, alt, data } = node;
|
||||
const newData = { ...data, title, alt, url };
|
||||
return createInline(typeMap[type], { isVoid: true, data: newData });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tables
|
||||
*
|
||||
|
@ -474,6 +474,21 @@ function convertNode(node, children, shortcodePlugins) {
|
||||
return u(typeMap[node.type], { url, title, data }, children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Images
|
||||
*
|
||||
* This transformation is almost identical to that of links, except for the
|
||||
* lack of child nodes and addition of `alt` attribute data. Currently the
|
||||
* CMS handles block images by shortcode, so this case will only apply to
|
||||
* inline images, which currently can only occur through raw markdown
|
||||
* insertion.
|
||||
*/
|
||||
case 'image': {
|
||||
const { url, title, alt, ...data } = get(node, 'data', {});
|
||||
return u(typeMap[node.type], { url, title, alt, data });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* No default case is supplied because an unhandled case should never
|
||||
* occur. In the event that it does, let the error throw (for now).
|
||||
|
Loading…
x
Reference in New Issue
Block a user