html-react-parser
Version:
HTML to React parser.
122 lines • 5.08 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = domToReact;
var react_1 = require("react");
var attributes_to_props_1 = __importDefault(require("./attributes-to-props"));
var utilities_1 = require("./utilities");
var React = {
cloneElement: react_1.cloneElement,
createElement: react_1.createElement,
isValidElement: react_1.isValidElement,
};
/**
* Converts DOM nodes to JSX element(s).
*
* @param nodes - DOM nodes.
* @param options - Options.
* @returns - String or JSX element(s).
*/
function domToReact(nodes, options) {
if (options === void 0) { options = {}; }
var reactElements = [];
var hasReplace = typeof options.replace === 'function';
var transform = options.transform || utilities_1.returnFirstArg;
var _a = options.library || React, cloneElement = _a.cloneElement, createElement = _a.createElement, isValidElement = _a.isValidElement;
var nodesLength = nodes.length;
for (var index = 0; index < nodesLength; index++) {
var node = nodes[index];
// replace with custom React element (if present)
if (hasReplace) {
var replaceElement = options.replace(node, index);
if (isValidElement(replaceElement)) {
// set "key" prop for sibling elements
// https://react.dev/learn/rendering-lists#rules-of-keys
if (nodesLength > 1) {
replaceElement = cloneElement(replaceElement, {
key: replaceElement.key || index,
});
}
reactElements.push(transform(replaceElement, node, index));
continue;
}
}
if (node.type === 'text') {
var isWhitespace = !node.data.trim().length;
// We have a whitespace node that can't be nested in its parent
// so skip it
if (isWhitespace &&
node.parent &&
!(0, utilities_1.canTextBeChildOfNode)(node.parent)) {
continue;
}
// Trim is enabled and we have a whitespace node
// so skip it
if (options.trim && isWhitespace) {
continue;
}
// We have a text node that's not whitespace and it can be nested
// in its parent so add it to the results
reactElements.push(transform(node.data, node, index));
continue;
}
var element = node;
var props = {};
if (skipAttributesToProps(element)) {
(0, utilities_1.setStyleProp)(element.attribs.style, element.attribs);
props = element.attribs;
}
else if (element.attribs) {
props = (0, attributes_to_props_1.default)(element.attribs, element.name);
}
var children = void 0;
switch (node.type) {
case 'script':
case 'style':
// prevent text in <script> or <style> from being escaped
// https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html
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://react.dev/reference/react-dom/components/textarea#caveats
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://react.dev/learn/rendering-lists#rules-of-keys
if (nodesLength > 1) {
props.key = index;
}
reactElements.push(transform(createElement(node.name, props, children), node, index));
}
return reactElements.length === 1 ? reactElements[0] : reactElements;
}
/**
* Determines whether DOM element attributes should be transformed to props.
* Web Components should not have their attributes transformed except for `style`.
*
* @param node - Element node.
* @returns - Whether the node attributes should be converted to props.
*/
function skipAttributesToProps(node) {
return (utilities_1.PRESERVE_CUSTOM_ATTRIBUTES &&
node.type === 'tag' &&
(0, utilities_1.isCustomComponent)(node.name, node.attribs));
}
//# sourceMappingURL=dom-to-react.js.map
;