html-react-parser
Version:
An HTML to React parser.
102 lines (86 loc) • 2.89 kB
JavaScript
var React = require('react');
var attributesToProps = require('./attributes-to-props');
var utilities = require('./utilities');
/**
* Converts DOM nodes to React elements.
*
* @param {Array} nodes - The DOM nodes.
* @param {Object} [options] - The additional options.
* @param {Function} [options.replace] - The replace method.
* @return {ReactElement|Array}
*/
function domToReact(nodes, options) {
options = options || {};
var result = [];
var node;
var isReplacePresent = typeof options.replace === 'function';
var replacement;
var props;
var children;
for (var i = 0, len = nodes.length; i < len; i++) {
node = nodes[i];
// replace with custom React element (if applicable)
if (isReplacePresent) {
replacement = options.replace(node);
if (React.isValidElement(replacement)) {
// specify a "key" prop if element has siblings
// https://fb.me/react-warning-keys
if (len > 1) {
replacement = React.cloneElement(replacement, {
key: replacement.key || i
});
}
result.push(replacement);
continue;
}
}
if (node.type === 'text') {
result.push(node.data);
continue;
}
props = node.attribs;
if (!shouldPassAttributesUnaltered(node)) {
// update values
props = attributesToProps(node.attribs);
}
children = null;
// node type for <script> is "script"
// node type for <style> is "style"
if (node.type === 'script' || node.type === 'style') {
// prevent text in <script> or <style> from being escaped
// https://facebook.github.io/react/tips/dangerously-set-inner-html.html
if (node.children[0]) {
props.dangerouslySetInnerHTML = {
__html: node.children[0].data
};
}
} else if (node.type === 'tag') {
// setting textarea value in children is an antipattern in React
// https://reactjs.org/docs/forms.html#the-textarea-tag
if (node.name === 'textarea' && node.children[0]) {
props.defaultValue = node.children[0].data;
// continue recursion of creating React elements (if applicable)
} else if (node.children && node.children.length) {
children = domToReact(node.children, options);
}
// skip all other cases (e.g., comment)
} else {
continue;
}
// specify a "key" prop if element has siblings
// https://fb.me/react-warning-keys
if (len > 1) {
props.key = i;
}
result.push(React.createElement(node.name, props, children));
}
return result.length === 1 ? result[0] : result;
}
function shouldPassAttributesUnaltered(node) {
return (
utilities.PRESERVE_CUSTOM_ATTRIBUTES &&
node.type === 'tag' &&
utilities.isCustomComponent(node.name, node.attribs)
);
}
module.exports = domToReact;