UNPKG

react-from-dom

Version:

Convert HTML/XML source code or DOM nodes to React elements

625 lines (622 loc) 18.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { convertFromNode: () => convertFromNode, convertFromString: () => convertFromString, default: () => convert }); module.exports = __toCommonJS(index_exports); var React = __toESM(require("react")); // src/helpers.ts var styleToObject = (input) => { if (typeof input !== "string") { return {}; } return input.split(/ ?; ?/).reduce((acc, item) => { const [key, value] = item.split(/ ?: ?/).map((d, index) => index === 0 ? d.replace(/\s+/g, "") : d.trim()); if (key && value) { const nextKey = key.replace(/(\w)-(\w)/g, (_$0, $1, $2) => `${$1}${$2.toUpperCase()}`); let nextValue = value.trim(); if (!Number.isNaN(Number(value))) { nextValue = Number(value); } acc[key.startsWith("-") ? key : nextKey] = nextValue; } return acc; }, {}); }; function randomString(length = 6) { const characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; let result = ""; for (let index = length; index > 0; --index) { result += characters[Math.round(Math.random() * (characters.length - 1))]; } return result; } var noTextChildNodes = [ "br", "col", "colgroup", "dl", "hr", "iframe", "img", "input", "link", "menuitem", "meta", "ol", "param", "select", "table", "tbody", "tfoot", "thead", "tr", "ul", "wbr" ]; var possibleStandardNames = { // HTML "accept-charset": "acceptCharset", acceptcharset: "acceptCharset", accesskey: "accessKey", allowfullscreen: "allowFullScreen", autocapitalize: "autoCapitalize", autocomplete: "autoComplete", autocorrect: "autoCorrect", autofocus: "autoFocus", autoplay: "autoPlay", autosave: "autoSave", cellpadding: "cellPadding", cellspacing: "cellSpacing", charset: "charSet", class: "className", classid: "classID", classname: "className", colspan: "colSpan", contenteditable: "contentEditable", contextmenu: "contextMenu", controlslist: "controlsList", crossorigin: "crossOrigin", dangerouslysetinnerhtml: "dangerouslySetInnerHTML", datetime: "dateTime", defaultchecked: "defaultChecked", defaultvalue: "defaultValue", enctype: "encType", for: "htmlFor", formmethod: "formMethod", formaction: "formAction", formenctype: "formEncType", formnovalidate: "formNoValidate", formtarget: "formTarget", frameborder: "frameBorder", hreflang: "hrefLang", htmlfor: "htmlFor", httpequiv: "httpEquiv", "http-equiv": "httpEquiv", icon: "icon", innerhtml: "innerHTML", inputmode: "inputMode", itemid: "itemID", itemprop: "itemProp", itemref: "itemRef", itemscope: "itemScope", itemtype: "itemType", keyparams: "keyParams", keytype: "keyType", marginwidth: "marginWidth", marginheight: "marginHeight", maxlength: "maxLength", mediagroup: "mediaGroup", minlength: "minLength", nomodule: "noModule", novalidate: "noValidate", playsinline: "playsInline", radiogroup: "radioGroup", readonly: "readOnly", referrerpolicy: "referrerPolicy", rowspan: "rowSpan", spellcheck: "spellCheck", srcdoc: "srcDoc", srclang: "srcLang", srcset: "srcSet", tabindex: "tabIndex", typemustmatch: "typeMustMatch", usemap: "useMap", // SVG accentheight: "accentHeight", "accent-height": "accentHeight", alignmentbaseline: "alignmentBaseline", "alignment-baseline": "alignmentBaseline", allowreorder: "allowReorder", arabicform: "arabicForm", "arabic-form": "arabicForm", attributename: "attributeName", attributetype: "attributeType", autoreverse: "autoReverse", basefrequency: "baseFrequency", baselineshift: "baselineShift", "baseline-shift": "baselineShift", baseprofile: "baseProfile", calcmode: "calcMode", capheight: "capHeight", "cap-height": "capHeight", clippath: "clipPath", "clip-path": "clipPath", clippathunits: "clipPathUnits", cliprule: "clipRule", "clip-rule": "clipRule", colorinterpolation: "colorInterpolation", "color-interpolation": "colorInterpolation", colorinterpolationfilters: "colorInterpolationFilters", "color-interpolation-filters": "colorInterpolationFilters", colorprofile: "colorProfile", "color-profile": "colorProfile", colorrendering: "colorRendering", "color-rendering": "colorRendering", contentscripttype: "contentScriptType", contentstyletype: "contentStyleType", diffuseconstant: "diffuseConstant", dominantbaseline: "dominantBaseline", "dominant-baseline": "dominantBaseline", edgemode: "edgeMode", enablebackground: "enableBackground", "enable-background": "enableBackground", externalresourcesrequired: "externalResourcesRequired", fillopacity: "fillOpacity", "fill-opacity": "fillOpacity", fillrule: "fillRule", "fill-rule": "fillRule", filterres: "filterRes", filterunits: "filterUnits", floodopacity: "floodOpacity", "flood-opacity": "floodOpacity", floodcolor: "floodColor", "flood-color": "floodColor", fontfamily: "fontFamily", "font-family": "fontFamily", fontsize: "fontSize", "font-size": "fontSize", fontsizeadjust: "fontSizeAdjust", "font-size-adjust": "fontSizeAdjust", fontstretch: "fontStretch", "font-stretch": "fontStretch", fontstyle: "fontStyle", "font-style": "fontStyle", fontvariant: "fontVariant", "font-variant": "fontVariant", fontweight: "fontWeight", "font-weight": "fontWeight", glyphname: "glyphName", "glyph-name": "glyphName", glyphorientationhorizontal: "glyphOrientationHorizontal", "glyph-orientation-horizontal": "glyphOrientationHorizontal", glyphorientationvertical: "glyphOrientationVertical", "glyph-orientation-vertical": "glyphOrientationVertical", glyphref: "glyphRef", gradienttransform: "gradientTransform", gradientunits: "gradientUnits", horizadvx: "horizAdvX", "horiz-adv-x": "horizAdvX", horizoriginx: "horizOriginX", "horiz-origin-x": "horizOriginX", imagerendering: "imageRendering", "image-rendering": "imageRendering", kernelmatrix: "kernelMatrix", kernelunitlength: "kernelUnitLength", keypoints: "keyPoints", keysplines: "keySplines", keytimes: "keyTimes", lengthadjust: "lengthAdjust", letterspacing: "letterSpacing", "letter-spacing": "letterSpacing", lightingcolor: "lightingColor", "lighting-color": "lightingColor", limitingconeangle: "limitingConeAngle", markerend: "markerEnd", "marker-end": "markerEnd", markerheight: "markerHeight", markermid: "markerMid", "marker-mid": "markerMid", markerstart: "markerStart", "marker-start": "markerStart", markerunits: "markerUnits", markerwidth: "markerWidth", maskcontentunits: "maskContentUnits", maskunits: "maskUnits", numoctaves: "numOctaves", overlineposition: "overlinePosition", "overline-position": "overlinePosition", overlinethickness: "overlineThickness", "overline-thickness": "overlineThickness", paintorder: "paintOrder", "paint-order": "paintOrder", "panose-1": "panose1", pathlength: "pathLength", patterncontentunits: "patternContentUnits", patterntransform: "patternTransform", patternunits: "patternUnits", pointerevents: "pointerEvents", "pointer-events": "pointerEvents", pointsatx: "pointsAtX", pointsaty: "pointsAtY", pointsatz: "pointsAtZ", preservealpha: "preserveAlpha", preserveaspectratio: "preserveAspectRatio", primitiveunits: "primitiveUnits", refx: "refX", refy: "refY", renderingintent: "renderingIntent", "rendering-intent": "renderingIntent", repeatcount: "repeatCount", repeatdur: "repeatDur", requiredextensions: "requiredExtensions", requiredfeatures: "requiredFeatures", shaperendering: "shapeRendering", "shape-rendering": "shapeRendering", specularconstant: "specularConstant", specularexponent: "specularExponent", spreadmethod: "spreadMethod", startoffset: "startOffset", stddeviation: "stdDeviation", stitchtiles: "stitchTiles", stopcolor: "stopColor", "stop-color": "stopColor", stopopacity: "stopOpacity", "stop-opacity": "stopOpacity", strikethroughposition: "strikethroughPosition", "strikethrough-position": "strikethroughPosition", strikethroughthickness: "strikethroughThickness", "strikethrough-thickness": "strikethroughThickness", strokedasharray: "strokeDasharray", "stroke-dasharray": "strokeDasharray", strokedashoffset: "strokeDashoffset", "stroke-dashoffset": "strokeDashoffset", strokelinecap: "strokeLinecap", "stroke-linecap": "strokeLinecap", strokelinejoin: "strokeLinejoin", "stroke-linejoin": "strokeLinejoin", strokemiterlimit: "strokeMiterlimit", "stroke-miterlimit": "strokeMiterlimit", strokewidth: "strokeWidth", "stroke-width": "strokeWidth", strokeopacity: "strokeOpacity", "stroke-opacity": "strokeOpacity", suppresscontenteditablewarning: "suppressContentEditableWarning", suppresshydrationwarning: "suppressHydrationWarning", surfacescale: "surfaceScale", systemlanguage: "systemLanguage", tablevalues: "tableValues", targetx: "targetX", targety: "targetY", textanchor: "textAnchor", "text-anchor": "textAnchor", textdecoration: "textDecoration", "text-decoration": "textDecoration", textlength: "textLength", textrendering: "textRendering", "text-rendering": "textRendering", underlineposition: "underlinePosition", "underline-position": "underlinePosition", underlinethickness: "underlineThickness", "underline-thickness": "underlineThickness", unicodebidi: "unicodeBidi", "unicode-bidi": "unicodeBidi", unicoderange: "unicodeRange", "unicode-range": "unicodeRange", unitsperem: "unitsPerEm", "units-per-em": "unitsPerEm", unselectable: "unselectable", valphabetic: "vAlphabetic", "v-alphabetic": "vAlphabetic", vectoreffect: "vectorEffect", "vector-effect": "vectorEffect", vertadvy: "vertAdvY", "vert-adv-y": "vertAdvY", vertoriginx: "vertOriginX", "vert-origin-x": "vertOriginX", vertoriginy: "vertOriginY", "vert-origin-y": "vertOriginY", vhanging: "vHanging", "v-hanging": "vHanging", videographic: "vIdeographic", "v-ideographic": "vIdeographic", viewbox: "viewBox", viewtarget: "viewTarget", vmathematical: "vMathematical", "v-mathematical": "vMathematical", wordspacing: "wordSpacing", "word-spacing": "wordSpacing", writingmode: "writingMode", "writing-mode": "writingMode", xchannelselector: "xChannelSelector", xheight: "xHeight", "x-height": "xHeight", xlinkactuate: "xlinkActuate", "xlink:actuate": "xlinkActuate", xlinkarcrole: "xlinkArcrole", "xlink:arcrole": "xlinkArcrole", xlinkhref: "xlinkHref", "xlink:href": "xlinkHref", xlinkrole: "xlinkRole", "xlink:role": "xlinkRole", xlinkshow: "xlinkShow", "xlink:show": "xlinkShow", xlinktitle: "xlinkTitle", "xlink:title": "xlinkTitle", xlinktype: "xlinkType", "xlink:type": "xlinkType", xmlbase: "xmlBase", "xml:base": "xmlBase", xmllang: "xmlLang", "xml:lang": "xmlLang", "xml:space": "xmlSpace", xmlnsxlink: "xmlnsXlink", "xmlns:xlink": "xmlnsXlink", xmlspace: "xmlSpace", ychannelselector: "yChannelSelector", zoomandpan: "zoomAndPan", // event handlers onblur: "onBlur", onchange: "onChange", onclick: "onClick", oncontextmenu: "onContextMenu", ondoubleclick: "onDoubleClick", ondrag: "onDrag", ondragend: "onDragEnd", ondragenter: "onDragEnter", ondragexit: "onDragExit", ondragleave: "onDragLeave", ondragover: "onDragOver", ondragstart: "onDragStart", ondrop: "onDrop", onerror: "onError", onfocus: "onFocus", oninput: "onInput", oninvalid: "onInvalid", onkeydown: "onKeyDown", onkeypress: "onKeyPress", onkeyup: "onKeyUp", onload: "onLoad", onmousedown: "onMouseDown", onmouseenter: "onMouseEnter", onmouseleave: "onMouseLeave", onmousemove: "onMouseMove", onmouseout: "onMouseOut", onmouseover: "onMouseOver", onmouseup: "onMouseUp", onscroll: "onScroll", onsubmit: "onSubmit", ontouchcancel: "onTouchCancel", ontouchend: "onTouchEnd", ontouchmove: "onTouchMove", ontouchstart: "onTouchStart", onwheel: "onWheel" }; // src/index.ts function getReactNode(node, options) { const { key, level, ...rest } = options; switch (node.nodeType) { case 1: { return React.createElement( parseName(node.nodeName), parseAttributes(node, key), parseChildren(node.childNodes, level, rest) ); } case 3: { const nodeText = node.nodeValue?.toString() ?? ""; if (!rest.allowWhiteSpaces && /^\s+$/.test(nodeText) && !/[\u00A0\u202F]/.test(nodeText)) { return null; } if (!node.parentNode) { return nodeText; } const parentNodeName = node.parentNode.nodeName.toLowerCase(); if (noTextChildNodes.includes(parentNodeName)) { if (/\S/.test(nodeText)) { console.warn( `A textNode is not allowed inside '${parentNodeName}'. Your text "${nodeText}" will be ignored` ); } return null; } return nodeText; } case 8: { return null; } case 11: { return parseChildren(node.childNodes, level, options); } /* c8 ignore next 3 */ default: { return null; } } } function parseAttributes(node, reactKey) { const attributes = { key: reactKey }; if (node instanceof Element) { const nodeClassNames = node.getAttribute("class"); if (nodeClassNames) { attributes.className = nodeClassNames; } [...node.attributes].forEach((d) => { switch (d.name) { // this is manually handled above, so break; case "class": break; case "style": attributes[d.name] = styleToObject(d.value); break; case "allowfullscreen": case "allowpaymentrequest": case "async": case "autofocus": case "autoplay": case "checked": case "controls": case "default": case "defer": case "disabled": case "formnovalidate": case "hidden": case "ismap": case "itemscope": case "loop": case "multiple": case "muted": case "nomodule": case "novalidate": case "open": case "readonly": case "required": case "reversed": case "selected": case "typemustmatch": attributes[possibleStandardNames[d.name] || d.name] = true; break; default: attributes[possibleStandardNames[d.name] || d.name] = d.value; } }); } return attributes; } function parseChildren(childNodeList, level, options) { const children = [...childNodeList].map( (node, index) => convertFromNode(node, { ...options, index, level: level + 1 }) ).filter(Boolean); if (!children.length) { return null; } return children; } function parseName(nodeName) { if (/[a-z]+[A-Z]+[a-z]+/.test(nodeName)) { return nodeName; } return nodeName.toLowerCase(); } function convert(input, options = {}) { if (typeof input === "string") { return convertFromString(input, options); } if (input instanceof Node) { return convertFromNode(input, options); } return null; } function convertFromNode(input, options = {}) { if (!input || !(input instanceof Node)) { return null; } const { actions = [], index = 0, level = 0, randomKey } = options; let node = input; let key = `${level}-${index}`; const result = []; if (randomKey && level === 0) { key = `${randomString()}-${key}`; } if (Array.isArray(actions)) { actions.forEach((action) => { if (action.condition(node, key, level)) { if (typeof action.pre === "function") { node = action.pre(node, key, level); if (!(node instanceof Node)) { node = input; if (process.env.NODE_ENV !== "production") { console.warn( "The `pre` method always must return a valid DomNode (instanceof Node) - your modification will be ignored (Hint: if you want to render a React-component, use the `post` method instead)" ); } } } if (typeof action.post === "function") { result.push(action.post(node, key, level)); } } }); } if (result.length) { return result; } return getReactNode(node, { key, level, ...options }); } function convertFromString(input, options = {}) { if (!input || typeof input !== "string") { return null; } const { includeAllNodes = false, nodeOnly = false, selector = "body > *", type = "text/html" } = options; try { const parser = new DOMParser(); const document = parser.parseFromString(input, type); if (includeAllNodes) { const { childNodes } = document.body; if (nodeOnly) { return childNodes; } return [...childNodes].map((node2) => convertFromNode(node2, options)); } const node = document.querySelector(selector) || document.body.childNodes[0]; if (!(node instanceof Node)) { throw new TypeError("Error parsing input"); } if (nodeOnly) { return node; } return convertFromNode(node, options); } catch (error) { if (process.env.NODE_ENV !== "production") { console.error(error); } } return null; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { convertFromNode, convertFromString }); //# sourceMappingURL=index.js.map