feeles-ide
Version:
The hackable and serializable IDE to make learning material
203 lines (174 loc) • 6.78 kB
JavaScript
import _extends from 'babel-runtime/helpers/extends';
import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
// Copied from https://github.com/endaaman/markdown-react-js
import markdown from 'markdown-it';
// import React, { PropTypes } from 'react'
import React from 'react';
import PropTypes from 'prop-types';
// import isPlainObject from 'lodash/isPlainObject'
// import assign from 'lodash/assign'
// import reduce from 'lodash/reduce'
// import zipObject from 'lodash/zipObject'
// import sortBy from 'lodash/sortBy'
// import compact from 'lodash/compact'
// import camelCase from 'lodash/camelCase'
// import isString from 'lodash/isString'
// import fromPairs from 'lodash/fromPairs'
import { isPlainObject, assign, reduce, zipObject, sortBy, compact, camelCase, isString, fromPairs } from 'lodash';
var DEFAULT_TAGS = {
html: 'span'
};
var DEFAULT_RULES = {
image: function image(token, attrs, children) {
if (children.length) {
attrs = assign({}, attrs, { alt: children[0] });
}
return [[token.tag, attrs]];
},
codeInline: function codeInline(token, attrs) {
return [compact([token.tag, attrs, token.content])];
},
codeBlock: function codeBlock(token, attrs) {
return [['pre', compact([token.tag, attrs, token.content])]];
},
fence: function fence(token, attrs) {
if (token.info) {
var langName = token.info.trim().split(/\s+/g)[0];
attrs = assign({}, attrs, { 'data-language': langName });
}
return [['pre', compact([token.tag, attrs, token.content])]];
},
hardbreak: function hardbreak() {
return [['br']];
},
softbreak: function softbreak(token, attrs, children, options) {
return options.breaks ? [['br']] : '\n';
},
text: function text(token) {
return token.content;
},
htmlBlock: function htmlBlock(token) {
return token.content;
},
htmlInline: function htmlInline(token) {
return token.content;
},
inline: function inline(token, attrs, children) {
return children;
},
default: function _default(token, attrs, children, options, getNext) {
if (token.nesting === 1 && token.hidden) {
return getNext();
}
/* plugin-related */
if (!token.tag) {
return token.content;
}
if (token.info) {
attrs = assign({}, attrs, { 'data-info': token.info.trim() });
}
/* plugin-related */
return [compact([token.tag, attrs].concat(token.nesting === 1 && getNext()))];
}
};
function convertTree(tokens, convertRules, options) {
function convertBranch(tkns, nested) {
var branch = [];
if (!nested) {
branch.push('html');
}
function getNext() {
return convertBranch(tkns, true);
}
var token = tkns.shift();
while (token && token.nesting !== -1) {
var attrs = token.attrs && fromPairs(sortBy(token.attrs, 0));
var children = token.children && convertBranch(token.children.slice(), true);
var rule = convertRules[camelCase(token.type)] || convertRules.default;
branch = branch.concat(rule(token, attrs, children, options, getNext));
token = tkns.shift();
}
return branch;
}
return convertBranch(tokens, false);
}
function mdReactFactory() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var onIterate = options.onIterate,
_options$tags = options.tags,
tags = _options$tags === undefined ? DEFAULT_TAGS : _options$tags,
presetName = options.presetName,
markdownOptions = options.markdownOptions,
_options$enableRules = options.enableRules,
enableRules = _options$enableRules === undefined ? [] : _options$enableRules,
_options$disableRules = options.disableRules,
disableRules = _options$disableRules === undefined ? [] : _options$disableRules,
_options$plugins = options.plugins,
plugins = _options$plugins === undefined ? [] : _options$plugins,
_options$onGenerateKe = options.onGenerateKey,
onGenerateKey = _options$onGenerateKe === undefined ? function (tag, index) {
return 'mdrct-' + tag + '-' + index;
} : _options$onGenerateKe,
rootElementProps = _objectWithoutProperties(options, ['onIterate', 'tags', 'presetName', 'markdownOptions', 'enableRules', 'disableRules', 'plugins', 'onGenerateKey']);
var md = markdown(markdownOptions || presetName).enable(enableRules).disable(disableRules);
var convertRules = assign({}, DEFAULT_RULES, options.convertRules);
md = reduce(plugins, function (m, plugin) {
return plugin.plugin ? m.use.apply(m, [plugin.plugin].concat(_toConsumableArray(plugin.args))) : m.use(plugin);
}, md);
function renderChildren(tag) {
return ['img', 'hr', 'br'].indexOf(tag) < 0;
}
function iterateTree(tree) {
var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var tag = tree.shift();
var key = onGenerateKey(tag, index);
var props = tree.length && isPlainObject(tree[0]) ? assign(tree.shift(), { key: key }) : { key: key };
if (level === 0) {
props = _extends({}, props, rootElementProps);
}
var children = tree.map(function (branch, idx) {
return Array.isArray(branch) ? iterateTree(branch, level + 1, idx) : branch;
});
tag = tags[tag] || tag;
if (isString(props.style)) {
props.style = zipObject(props.style.split(';').map(function (prop) {
return prop.split(':');
}).map(function (keyVal) {
return [camelCase(keyVal[0].trim()), keyVal[1].trim()];
}));
}
if (typeof onIterate === 'function') {
var element = onIterate(tag, props, children, level);
if (element) {
return element;
}
}
return React.createElement(tag, props, renderChildren(tag) ? children : undefined);
}
return function (text) {
var tree = convertTree(md.parse(text, {}), convertRules, md.options);
return iterateTree(tree);
};
}
var MDReactComponent = function MDReactComponent(props) {
var text = props.text,
propsWithoutText = _objectWithoutProperties(props, ['text']);
return mdReactFactory(propsWithoutText)(text);
};
MDReactComponent.propTypes = {
text: PropTypes.string.isRequired,
onIterate: PropTypes.func,
onGenerateKey: PropTypes.func,
tags: PropTypes.object,
presetName: PropTypes.string,
markdownOptions: PropTypes.object,
enableRules: PropTypes.array,
disableRules: PropTypes.array,
convertRules: PropTypes.object,
plugins: PropTypes.array,
className: PropTypes.string
};
export default MDReactComponent;
export { mdReactFactory as mdReact };