UNPKG

html-react-parser

Version:
131 lines (112 loc) 3.6 kB
var React = require('react'); var attributesToProps = require('./attributes-to-props'); var utilities = require('./utilities'); var setStyleProp = utilities.setStyleProp; /** * Converts DOM nodes to JSX element(s). * * @param {DomElement[]} nodes - DOM nodes. * @param {object} [options={}] - Options. * @param {Function} [options.replace] - Replacer. * @param {object} [options.library] - Library (React/Preact/etc.). * @return {string|JSX.Element|JSX.Element[]} */ function domToReact(nodes, options) { options = options || {}; var library = options.library || React; var cloneElement = library.cloneElement; var createElement = library.createElement; var isValidElement = library.isValidElement; var result = []; var node; var hasReplace = typeof options.replace === 'function'; var replaceElement; var props; var children; var data; var trim = options.trim; for (var i = 0, len = nodes.length; i < len; i++) { node = nodes[i]; // replace with custom React element (if present) if (hasReplace) { replaceElement = options.replace(node); if (isValidElement(replaceElement)) { // set "key" prop for sibling elements // https://fb.me/react-warning-keys if (len > 1) { replaceElement = cloneElement(replaceElement, { key: replaceElement.key || i }); } result.push(replaceElement); continue; } } if (node.type === 'text') { // if trim option is enabled, skip whitespace text nodes if (trim) { data = node.data.trim(); if (data) { result.push(node.data); } } else { result.push(node.data); } continue; } props = node.attribs; if (skipAttributesToProps(node)) { setStyleProp(props.style, props); } else if (props) { props = attributesToProps(props); } children = null; switch (node.type) { case 'script': case 'style': // prevent text in <script> or <style> from being escaped // https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml if (node.children[0]) { props.dangerouslySetInnerHTML = { __html: node.children[0].data }; } break; case '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; } else if (node.children && node.children.length) { // continue recursion of creating React elements (if applicable) children = domToReact(node.children, options); } break; // skip all other cases (e.g., comment) default: continue; } // set "key" prop for sibling elements // https://fb.me/react-warning-keys if (len > 1) { props.key = i; } result.push(createElement(node.name, props, children)); } return result.length === 1 ? result[0] : result; } /** * Determines whether DOM element attributes should be transformed to props. * Web Components should not have their attributes transformed except for `style`. * * @param {DomElement} node * @return {boolean} */ function skipAttributesToProps(node) { return ( utilities.PRESERVE_CUSTOM_ATTRIBUTES && node.type === 'tag' && utilities.isCustomComponent(node.name, node.attribs) ); } module.exports = domToReact;