html-react-parser
Version:
HTML to React parser.
1,822 lines (1,684 loc) • 55.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
typeof define === 'function' && define.amd ? define(['react'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.HTMLReactParser = factory(global.React));
}(this, (function (React) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var HTMLDOMPropertyConfig = {
Properties: {
autoFocus: 4,
accept: 0,
acceptCharset: 0,
accessKey: 0,
action: 0,
allowFullScreen: 4,
allowTransparency: 0,
alt: 0,
as: 0,
async: 4,
autoComplete: 0,
autoPlay: 4,
capture: 4,
cellPadding: 0,
cellSpacing: 0,
charSet: 0,
challenge: 0,
checked: 5,
cite: 0,
classID: 0,
className: 0,
cols: 24,
colSpan: 0,
content: 0,
contentEditable: 0,
contextMenu: 0,
controls: 4,
controlsList: 0,
coords: 0,
crossOrigin: 0,
data: 0,
dateTime: 0,
default: 4,
defer: 4,
dir: 0,
disabled: 4,
download: 32,
draggable: 0,
encType: 0,
form: 0,
formAction: 0,
formEncType: 0,
formMethod: 0,
formNoValidate: 4,
formTarget: 0,
frameBorder: 0,
headers: 0,
height: 0,
hidden: 4,
high: 0,
href: 0,
hrefLang: 0,
htmlFor: 0,
httpEquiv: 0,
icon: 0,
id: 0,
inputMode: 0,
integrity: 0,
is: 0,
keyParams: 0,
keyType: 0,
kind: 0,
label: 0,
lang: 0,
list: 0,
loop: 4,
low: 0,
manifest: 0,
marginHeight: 0,
marginWidth: 0,
max: 0,
maxLength: 0,
media: 0,
mediaGroup: 0,
method: 0,
min: 0,
minLength: 0,
multiple: 5,
muted: 5,
name: 0,
nonce: 0,
noValidate: 4,
open: 4,
optimum: 0,
pattern: 0,
placeholder: 0,
playsInline: 4,
poster: 0,
preload: 0,
profile: 0,
radioGroup: 0,
readOnly: 4,
referrerPolicy: 0,
rel: 0,
required: 4,
reversed: 4,
role: 0,
rows: 24,
rowSpan: 8,
sandbox: 0,
scope: 0,
scoped: 4,
scrolling: 0,
seamless: 4,
selected: 5,
shape: 0,
size: 24,
sizes: 0,
span: 24,
spellCheck: 0,
src: 0,
srcDoc: 0,
srcLang: 0,
srcSet: 0,
start: 8,
step: 0,
style: 0,
summary: 0,
tabIndex: 0,
target: 0,
title: 0,
type: 0,
useMap: 0,
value: 0,
width: 0,
wmode: 0,
wrap: 0,
about: 0,
datatype: 0,
inlist: 0,
prefix: 0,
property: 0,
resource: 0,
typeof: 0,
vocab: 0,
autoCapitalize: 0,
autoCorrect: 0,
autoSave: 0,
color: 0,
itemProp: 0,
itemScope: 4,
itemType: 0,
itemID: 0,
itemRef: 0,
results: 0,
security: 0,
unselectable: 0
},
DOMAttributeNames: {
acceptCharset: 'accept-charset',
className: 'class',
htmlFor: 'for',
httpEquiv: 'http-equiv'
}
};
var SVGDOMPropertyConfig = {
Properties: {
accentHeight: 0,
accumulate: 0,
additive: 0,
alignmentBaseline: 0,
allowReorder: 0,
alphabetic: 0,
amplitude: 0,
arabicForm: 0,
ascent: 0,
attributeName: 0,
attributeType: 0,
autoReverse: 0,
azimuth: 0,
baseFrequency: 0,
baseProfile: 0,
baselineShift: 0,
bbox: 0,
begin: 0,
bias: 0,
by: 0,
calcMode: 0,
capHeight: 0,
clip: 0,
clipPath: 0,
clipRule: 0,
clipPathUnits: 0,
colorInterpolation: 0,
colorInterpolationFilters: 0,
colorProfile: 0,
colorRendering: 0,
contentScriptType: 0,
contentStyleType: 0,
cursor: 0,
cx: 0,
cy: 0,
d: 0,
decelerate: 0,
descent: 0,
diffuseConstant: 0,
direction: 0,
display: 0,
divisor: 0,
dominantBaseline: 0,
dur: 0,
dx: 0,
dy: 0,
edgeMode: 0,
elevation: 0,
enableBackground: 0,
end: 0,
exponent: 0,
externalResourcesRequired: 0,
fill: 0,
fillOpacity: 0,
fillRule: 0,
filter: 0,
filterRes: 0,
filterUnits: 0,
floodColor: 0,
floodOpacity: 0,
focusable: 0,
fontFamily: 0,
fontSize: 0,
fontSizeAdjust: 0,
fontStretch: 0,
fontStyle: 0,
fontVariant: 0,
fontWeight: 0,
format: 0,
from: 0,
fx: 0,
fy: 0,
g1: 0,
g2: 0,
glyphName: 0,
glyphOrientationHorizontal: 0,
glyphOrientationVertical: 0,
glyphRef: 0,
gradientTransform: 0,
gradientUnits: 0,
hanging: 0,
horizAdvX: 0,
horizOriginX: 0,
ideographic: 0,
imageRendering: 0,
in: 0,
in2: 0,
intercept: 0,
k: 0,
k1: 0,
k2: 0,
k3: 0,
k4: 0,
kernelMatrix: 0,
kernelUnitLength: 0,
kerning: 0,
keyPoints: 0,
keySplines: 0,
keyTimes: 0,
lengthAdjust: 0,
letterSpacing: 0,
lightingColor: 0,
limitingConeAngle: 0,
local: 0,
markerEnd: 0,
markerMid: 0,
markerStart: 0,
markerHeight: 0,
markerUnits: 0,
markerWidth: 0,
mask: 0,
maskContentUnits: 0,
maskUnits: 0,
mathematical: 0,
mode: 0,
numOctaves: 0,
offset: 0,
opacity: 0,
operator: 0,
order: 0,
orient: 0,
orientation: 0,
origin: 0,
overflow: 0,
overlinePosition: 0,
overlineThickness: 0,
paintOrder: 0,
panose1: 0,
pathLength: 0,
patternContentUnits: 0,
patternTransform: 0,
patternUnits: 0,
pointerEvents: 0,
points: 0,
pointsAtX: 0,
pointsAtY: 0,
pointsAtZ: 0,
preserveAlpha: 0,
preserveAspectRatio: 0,
primitiveUnits: 0,
r: 0,
radius: 0,
refX: 0,
refY: 0,
renderingIntent: 0,
repeatCount: 0,
repeatDur: 0,
requiredExtensions: 0,
requiredFeatures: 0,
restart: 0,
result: 0,
rotate: 0,
rx: 0,
ry: 0,
scale: 0,
seed: 0,
shapeRendering: 0,
slope: 0,
spacing: 0,
specularConstant: 0,
specularExponent: 0,
speed: 0,
spreadMethod: 0,
startOffset: 0,
stdDeviation: 0,
stemh: 0,
stemv: 0,
stitchTiles: 0,
stopColor: 0,
stopOpacity: 0,
strikethroughPosition: 0,
strikethroughThickness: 0,
string: 0,
stroke: 0,
strokeDasharray: 0,
strokeDashoffset: 0,
strokeLinecap: 0,
strokeLinejoin: 0,
strokeMiterlimit: 0,
strokeOpacity: 0,
strokeWidth: 0,
surfaceScale: 0,
systemLanguage: 0,
tableValues: 0,
targetX: 0,
targetY: 0,
textAnchor: 0,
textDecoration: 0,
textRendering: 0,
textLength: 0,
to: 0,
transform: 0,
u1: 0,
u2: 0,
underlinePosition: 0,
underlineThickness: 0,
unicode: 0,
unicodeBidi: 0,
unicodeRange: 0,
unitsPerEm: 0,
vAlphabetic: 0,
vHanging: 0,
vIdeographic: 0,
vMathematical: 0,
values: 0,
vectorEffect: 0,
version: 0,
vertAdvY: 0,
vertOriginX: 0,
vertOriginY: 0,
viewBox: 0,
viewTarget: 0,
visibility: 0,
widths: 0,
wordSpacing: 0,
writingMode: 0,
x: 0,
xHeight: 0,
x1: 0,
x2: 0,
xChannelSelector: 0,
xlinkActuate: 0,
xlinkArcrole: 0,
xlinkHref: 0,
xlinkRole: 0,
xlinkShow: 0,
xlinkTitle: 0,
xlinkType: 0,
xmlBase: 0,
xmlns: 0,
xmlnsXlink: 0,
xmlLang: 0,
xmlSpace: 0,
y: 0,
y1: 0,
y2: 0,
yChannelSelector: 0,
z: 0,
zoomAndPan: 0
},
DOMAttributeNames: {
accentHeight: 'accent-height',
alignmentBaseline: 'alignment-baseline',
arabicForm: 'arabic-form',
baselineShift: 'baseline-shift',
capHeight: 'cap-height',
clipPath: 'clip-path',
clipRule: 'clip-rule',
colorInterpolation: 'color-interpolation',
colorInterpolationFilters: 'color-interpolation-filters',
colorProfile: 'color-profile',
colorRendering: 'color-rendering',
dominantBaseline: 'dominant-baseline',
enableBackground: 'enable-background',
fillOpacity: 'fill-opacity',
fillRule: 'fill-rule',
floodColor: 'flood-color',
floodOpacity: 'flood-opacity',
fontFamily: 'font-family',
fontSize: 'font-size',
fontSizeAdjust: 'font-size-adjust',
fontStretch: 'font-stretch',
fontStyle: 'font-style',
fontVariant: 'font-variant',
fontWeight: 'font-weight',
glyphName: 'glyph-name',
glyphOrientationHorizontal: 'glyph-orientation-horizontal',
glyphOrientationVertical: 'glyph-orientation-vertical',
horizAdvX: 'horiz-adv-x',
horizOriginX: 'horiz-origin-x',
imageRendering: 'image-rendering',
letterSpacing: 'letter-spacing',
lightingColor: 'lighting-color',
markerEnd: 'marker-end',
markerMid: 'marker-mid',
markerStart: 'marker-start',
overlinePosition: 'overline-position',
overlineThickness: 'overline-thickness',
paintOrder: 'paint-order',
panose1: 'panose-1',
pointerEvents: 'pointer-events',
renderingIntent: 'rendering-intent',
shapeRendering: 'shape-rendering',
stopColor: 'stop-color',
stopOpacity: 'stop-opacity',
strikethroughPosition: 'strikethrough-position',
strikethroughThickness: 'strikethrough-thickness',
strokeDasharray: 'stroke-dasharray',
strokeDashoffset: 'stroke-dashoffset',
strokeLinecap: 'stroke-linecap',
strokeLinejoin: 'stroke-linejoin',
strokeMiterlimit: 'stroke-miterlimit',
strokeOpacity: 'stroke-opacity',
strokeWidth: 'stroke-width',
textAnchor: 'text-anchor',
textDecoration: 'text-decoration',
textRendering: 'text-rendering',
underlinePosition: 'underline-position',
underlineThickness: 'underline-thickness',
unicodeBidi: 'unicode-bidi',
unicodeRange: 'unicode-range',
unitsPerEm: 'units-per-em',
vAlphabetic: 'v-alphabetic',
vHanging: 'v-hanging',
vIdeographic: 'v-ideographic',
vMathematical: 'v-mathematical',
vectorEffect: 'vector-effect',
vertAdvY: 'vert-adv-y',
vertOriginX: 'vert-origin-x',
vertOriginY: 'vert-origin-y',
wordSpacing: 'word-spacing',
writingMode: 'writing-mode',
xHeight: 'x-height',
xlinkActuate: 'xlink:actuate',
xlinkArcrole: 'xlink:arcrole',
xlinkHref: 'xlink:href',
xlinkRole: 'xlink:role',
xlinkShow: 'xlink:show',
xlinkTitle: 'xlink:title',
xlinkType: 'xlink:type',
xmlBase: 'xml:base',
xmlnsXlink: 'xmlns:xlink',
xmlLang: 'xml:lang',
xmlSpace: 'xml:space'
}
};
var injection = {
MUST_USE_PROPERTY: 1,
HAS_BOOLEAN_VALUE: 4,
HAS_NUMERIC_VALUE: 8,
HAS_POSITIVE_NUMERIC_VALUE: 24,
HAS_OVERLOADED_BOOLEAN_VALUE: 32
};
var MUST_USE_PROPERTY = injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = injection.HAS_BOOLEAN_VALUE;
var HAS_NUMERIC_VALUE = injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE = injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE = injection.HAS_OVERLOADED_BOOLEAN_VALUE;
/**
* @see https://github.com/facebook/react/blob/15-stable/src/renderers/dom/shared/DOMProperty.js#L14-L16
*
* @param {Number} value
* @param {Number} bitmask
* @return {Boolean}
*/
function checkMask(value, bitmask) {
return (value & bitmask) === bitmask;
}
/**
* @see https://github.com/facebook/react/blob/15-stable/src/renderers/dom/shared/DOMProperty.js#L57
*
* @param {Object} domPropertyConfig - HTMLDOMPropertyConfig or SVGDOMPropertyConfig
* @param {Object} config - The object to be mutated
* @param {Boolean} isSVG - Whether the injected config is HTML or SVG (it assumes the default is HTML)
*/
function injectDOMPropertyConfig(domPropertyConfig, config, isSVG) {
var Properties = domPropertyConfig.Properties;
var DOMAttributeNames = domPropertyConfig.DOMAttributeNames;
var attributeName;
var propertyName;
var propConfig;
for (propertyName in Properties) {
attributeName =
DOMAttributeNames[propertyName] ||
(isSVG ? propertyName : propertyName.toLowerCase());
propConfig = Properties[propertyName];
config[attributeName] = {
attributeName: attributeName,
propertyName: propertyName,
mustUseProperty: checkMask(propConfig, MUST_USE_PROPERTY),
hasBooleanValue: checkMask(propConfig, HAS_BOOLEAN_VALUE),
hasNumericValue: checkMask(propConfig, HAS_NUMERIC_VALUE),
hasPositiveNumericValue: checkMask(
propConfig,
HAS_POSITIVE_NUMERIC_VALUE
),
hasOverloadedBooleanValue: checkMask(
propConfig,
HAS_OVERLOADED_BOOLEAN_VALUE
)
};
}
}
/**
* HTML properties config.
*
* @type {Object}
*/
var html = {};
injectDOMPropertyConfig(HTMLDOMPropertyConfig, html);
/**
* SVG properties config.
*
* @type {Object}
*/
var svg = {};
injectDOMPropertyConfig(SVGDOMPropertyConfig, svg, true);
/**
* HTML and SVG properties config.
*
* @type {Object}
*/
var properties = {};
injectDOMPropertyConfig(HTMLDOMPropertyConfig, properties);
injectDOMPropertyConfig(SVGDOMPropertyConfig, properties, true);
var ATTRIBUTE_NAME_START_CHAR =
':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
var ATTRIBUTE_NAME_CHAR =
ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
var reactProperty = {
html: html,
svg: svg,
properties: properties,
/**
* Checks whether a property name is a custom attribute.
*
* @see https://github.com/facebook/react/blob/15-stable/src/renderers/dom/shared/HTMLDOMPropertyConfig.js#L23-L25
*
* @param {String}
* @return {Boolean}
*/
isCustomAttribute: RegExp.prototype.test.bind(
new RegExp('^(data|aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$')
)
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
// http://www.w3.org/TR/CSS21/grammar.html
// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027
var COMMENT_REGEX = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g;
var NEWLINE_REGEX = /\n/g;
var WHITESPACE_REGEX = /^\s*/;
// declaration
var PROPERTY_REGEX = /^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/;
var COLON_REGEX = /^:\s*/;
var VALUE_REGEX = /^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/;
var SEMICOLON_REGEX = /^[;\s]*/;
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
var TRIM_REGEX = /^\s+|\s+$/g;
// strings
var NEWLINE = '\n';
var FORWARD_SLASH = '/';
var ASTERISK = '*';
var EMPTY_STRING = '';
// types
var TYPE_COMMENT = 'comment';
var TYPE_DECLARATION = 'declaration';
/**
* @param {String} style
* @param {Object} [options]
* @return {Object[]}
* @throws {TypeError}
* @throws {Error}
*/
var inlineStyleParser = function(style, options) {
if (typeof style !== 'string') {
throw new TypeError('First argument must be a string');
}
if (!style) return [];
options = options || {};
/**
* Positional.
*/
var lineno = 1;
var column = 1;
/**
* Update lineno and column based on `str`.
*
* @param {String} str
*/
function updatePosition(str) {
var lines = str.match(NEWLINE_REGEX);
if (lines) lineno += lines.length;
var i = str.lastIndexOf(NEWLINE);
column = ~i ? str.length - i : column + str.length;
}
/**
* Mark position and patch `node.position`.
*
* @return {Function}
*/
function position() {
var start = { line: lineno, column: column };
return function(node) {
node.position = new Position(start);
whitespace();
return node;
};
}
/**
* Store position information for a node.
*
* @constructor
* @property {Object} start
* @property {Object} end
* @property {undefined|String} source
*/
function Position(start) {
this.start = start;
this.end = { line: lineno, column: column };
this.source = options.source;
}
/**
* Non-enumerable source string.
*/
Position.prototype.content = style;
/**
* Error `msg`.
*
* @param {String} msg
* @throws {Error}
*/
function error(msg) {
var err = new Error(
options.source + ':' + lineno + ':' + column + ': ' + msg
);
err.reason = msg;
err.filename = options.source;
err.line = lineno;
err.column = column;
err.source = style;
if (options.silent) ; else {
throw err;
}
}
/**
* Match `re` and return captures.
*
* @param {RegExp} re
* @return {undefined|Array}
*/
function match(re) {
var m = re.exec(style);
if (!m) return;
var str = m[0];
updatePosition(str);
style = style.slice(str.length);
return m;
}
/**
* Parse whitespace.
*/
function whitespace() {
match(WHITESPACE_REGEX);
}
/**
* Parse comments.
*
* @param {Object[]} [rules]
* @return {Object[]}
*/
function comments(rules) {
var c;
rules = rules || [];
while ((c = comment())) {
if (c !== false) {
rules.push(c);
}
}
return rules;
}
/**
* Parse comment.
*
* @return {Object}
* @throws {Error}
*/
function comment() {
var pos = position();
if (FORWARD_SLASH != style.charAt(0) || ASTERISK != style.charAt(1)) return;
var i = 2;
while (
EMPTY_STRING != style.charAt(i) &&
(ASTERISK != style.charAt(i) || FORWARD_SLASH != style.charAt(i + 1))
) {
++i;
}
i += 2;
if (EMPTY_STRING === style.charAt(i - 1)) {
return error('End of comment missing');
}
var str = style.slice(2, i - 2);
column += 2;
updatePosition(str);
style = style.slice(i);
column += 2;
return pos({
type: TYPE_COMMENT,
comment: str
});
}
/**
* Parse declaration.
*
* @return {Object}
* @throws {Error}
*/
function declaration() {
var pos = position();
// prop
var prop = match(PROPERTY_REGEX);
if (!prop) return;
comment();
// :
if (!match(COLON_REGEX)) return error("property missing ':'");
// val
var val = match(VALUE_REGEX);
var ret = pos({
type: TYPE_DECLARATION,
property: trim(prop[0].replace(COMMENT_REGEX, EMPTY_STRING)),
value: val
? trim(val[0].replace(COMMENT_REGEX, EMPTY_STRING))
: EMPTY_STRING
});
// ;
match(SEMICOLON_REGEX);
return ret;
}
/**
* Parse declarations.
*
* @return {Object[]}
*/
function declarations() {
var decls = [];
comments(decls);
// declarations
var decl;
while ((decl = declaration())) {
if (decl !== false) {
decls.push(decl);
comments(decls);
}
}
return decls;
}
whitespace();
return declarations();
};
/**
* Trim `str`.
*
* @param {String} str
* @return {String}
*/
function trim(str) {
return str ? str.replace(TRIM_REGEX, EMPTY_STRING) : EMPTY_STRING;
}
/**
* Parses inline style to object.
*
* @example
* // returns { 'line-height': '42' }
* StyleToObject('line-height: 42;');
*
* @param {String} style - The inline style.
* @param {Function} [iterator] - The iterator function.
* @return {null|Object}
*/
function StyleToObject(style, iterator) {
var output = null;
if (!style || typeof style !== 'string') {
return output;
}
var declaration;
var declarations = inlineStyleParser(style);
var hasIterator = typeof iterator === 'function';
var property;
var value;
for (var i = 0, len = declarations.length; i < len; i++) {
declaration = declarations[i];
property = declaration.property;
value = declaration.value;
if (hasIterator) {
iterator(property, value, declaration);
} else if (value) {
output || (output = {});
output[property] = value;
}
}
return output;
}
var styleToObject = StyleToObject;
var utilities = createCommonjsModule(function (module, exports) {
exports.__esModule = true;
exports.camelCase = void 0;
var CUSTOM_PROPERTY_REGEX = /^--[a-zA-Z0-9-]+$/;
var HYPHEN_REGEX = /-([a-z])/g;
var NO_HYPHEN_REGEX = /^[^-]+$/;
var VENDOR_PREFIX_REGEX = /^-(webkit|moz|ms|o|khtml)-/;
var skipCamelCase = function (property) {
return !property ||
NO_HYPHEN_REGEX.test(property) ||
CUSTOM_PROPERTY_REGEX.test(property);
};
var capitalize = function (match, character) {
return character.toUpperCase();
};
var trimHyphen = function (match, prefix) { return prefix + "-"; };
var camelCase = function (property, options) {
if (options === void 0) { options = {}; }
if (skipCamelCase(property)) {
return property;
}
property = property.toLowerCase();
if (!options.reactCompat) {
property = property.replace(VENDOR_PREFIX_REGEX, trimHyphen);
}
return property.replace(HYPHEN_REGEX, capitalize);
};
exports.camelCase = camelCase;
});
var cjs = createCommonjsModule(function (module, exports) {
var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var style_to_object_1 = __importDefault(styleToObject);
function StyleToJS(style, options) {
var output = {};
if (!style || typeof style !== 'string') {
return output;
}
style_to_object_1["default"](style, function (property, value) {
if (property && value) {
output[utilities.camelCase(property, options)] = value;
}
});
return output;
}
exports["default"] = StyleToJS;
});
var styleToJS = cjs.default;
/**
* Swap key with value in an object.
*
* @param {Object} obj - The object.
* @param {Function} [override] - The override method.
* @return {Object} - The inverted object.
*/
function invertObject(obj, override) {
if (!obj || typeof obj !== 'object') {
throw new TypeError('First argument must be an object');
}
var key;
var value;
var isOverridePresent = typeof override === 'function';
var overrides = {};
var result = {};
for (key in obj) {
value = obj[key];
if (isOverridePresent) {
overrides = override(key, value);
if (overrides && overrides.length === 2) {
result[overrides[0]] = overrides[1];
continue;
}
}
if (typeof value === 'string') {
result[value] = key;
}
}
return result;
}
/**
* Check if a given tag is a custom component.
*
* @see {@link https://github.com/facebook/react/blob/v16.6.3/packages/react-dom/src/shared/isCustomComponent.js}
*
* @param {string} tagName - The name of the html tag.
* @param {Object} props - The props being passed to the element.
* @return {boolean}
*/
function isCustomComponent(tagName, props) {
if (tagName.indexOf('-') === -1) {
return props && typeof props.is === 'string';
}
switch (tagName) {
// These are reserved SVG and MathML elements.
// We don't mind this whitelist too much because we expect it to never grow.
// The alternative is to track the namespace in a few places which is convoluted.
// https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts
case 'annotation-xml':
case 'color-profile':
case 'font-face':
case 'font-face-src':
case 'font-face-uri':
case 'font-face-format':
case 'font-face-name':
case 'missing-glyph':
return false;
default:
return true;
}
}
var styleToJSOptions = { reactCompat: true };
/**
* Sets style prop.
*
* @param {null|undefined|string} style
* @param {object} props
*/
function setStyleProp(style, props) {
if (style === null || style === undefined) {
return;
}
props.style = styleToJS(style, styleToJSOptions);
}
/**
* @constant {boolean}
* @see {@link https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html}
*/
var PRESERVE_CUSTOM_ATTRIBUTES = React__default['default'].version.split('.')[0] >= 16;
var utilities$1 = {
PRESERVE_CUSTOM_ATTRIBUTES: PRESERVE_CUSTOM_ATTRIBUTES,
invertObject: invertObject,
isCustomComponent: isCustomComponent,
setStyleProp: setStyleProp
};
var setStyleProp$1 = utilities$1.setStyleProp;
var htmlProperties = reactProperty.html;
var svgProperties = reactProperty.svg;
var isCustomAttribute = reactProperty.isCustomAttribute;
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Converts HTML/SVG DOM attributes to React props.
*
* @param {object} [attributes={}] - HTML/SVG DOM attributes.
* @return {object} - React props.
*/
function attributesToProps(attributes) {
attributes = attributes || {};
var attributeName;
var attributeNameLowerCased;
var attributeValue;
var property;
var props = {};
for (attributeName in attributes) {
attributeValue = attributes[attributeName];
// ARIA (aria-*) or custom data (data-*) attribute
if (isCustomAttribute(attributeName)) {
props[attributeName] = attributeValue;
continue;
}
// convert HTML attribute to React prop
attributeNameLowerCased = attributeName.toLowerCase();
if (hasOwnProperty.call(htmlProperties, attributeNameLowerCased)) {
property = htmlProperties[attributeNameLowerCased];
props[property.propertyName] =
property.hasBooleanValue ||
(property.hasOverloadedBooleanValue && !attributeValue)
? true
: attributeValue;
continue;
}
// convert SVG attribute to React prop
if (hasOwnProperty.call(svgProperties, attributeName)) {
property = svgProperties[attributeName];
props[property.propertyName] = attributeValue;
continue;
}
// preserve custom attribute if React >=16
if (utilities$1.PRESERVE_CUSTOM_ATTRIBUTES) {
props[attributeName] = attributeValue;
}
}
// transform inline style to object
setStyleProp$1(attributes.style, props);
return props;
}
var attributesToProps_1 = attributesToProps;
var setStyleProp$2 = utilities$1.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__default['default'];
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$2(props.style, props);
} else if (props) {
props = attributesToProps_1(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$1.PRESERVE_CUSTOM_ATTRIBUTES &&
node.type === 'tag' &&
utilities$1.isCustomComponent(node.name, node.attribs)
);
}
var domToReact_1 = domToReact;
/**
* SVG elements are case-sensitive.
*
* @see {@link https://developer.mozilla.org/docs/Web/SVG/Element#SVG_elements_A_to_Z}
*/
var CASE_SENSITIVE_TAG_NAMES = [
'animateMotion',
'animateTransform',
'clipPath',
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feDropShadow',
'feFlood',
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR',
'feGaussainBlur',
'feImage',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
'foreignObject',
'linearGradient',
'radialGradient',
'textPath'
];
var constants = {
CASE_SENSITIVE_TAG_NAMES: CASE_SENSITIVE_TAG_NAMES
};
var node = createCommonjsModule(function (module, exports) {
var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (commonjsGlobal && commonjsGlobal.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cloneNode = exports.Element = exports.Document = exports.NodeWithChildren = exports.ProcessingInstruction = exports.Comment = exports.Text = exports.DataNode = exports.Node = void 0;
var nodeTypes = new Map([
["tag" /* Tag */, 1],
["script" /* Script */, 1],
["style" /* Style */, 1],
["directive" /* Directive */, 1],
["text" /* Text */, 3],
["cdata" /* CDATA */, 4],
["comment" /* Comment */, 8],
["root" /* Root */, 9],
]);
/**
* This object will be used as the prototype for Nodes when creating a
* DOM-Level-1-compliant structure.
*/
var Node = /** @class */ (function () {
/**
*
* @param type The type of the node.
*/
function Node(type) {
this.type = type;
/** Parent of the node */
this.parent = null;
/** Previous sibling */
this.prev = null;
/** Next sibling */
this.next = null;
/** The start index of the node. Requires `withStartIndices` on the handler to be `true. */
this.startIndex = null;
/** The end index of the node. Requires `withEndIndices` on the handler to be `true. */
this.endIndex = null;
}
Object.defineProperty(Node.prototype, "nodeType", {
// Read-only aliases
get: function () {
var _a;
return (_a = nodeTypes.get(this.type)) !== null && _a !== void 0 ? _a : 1;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Node.prototype, "parentNode", {
// Read-write aliases for properties
get: function () {
return this.parent;
},
set: function (parent) {
this.parent = parent;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Node.prototype, "previousSibling", {
get: function () {
return this.prev;
},
set: function (prev) {
this.prev = prev;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Node.prototype, "nextSibling", {
get: function () {
return this.next;
},
set: function (next) {
this.next = next;
},
enumerable: false,
configurable: true
});
/**
* Clone this node, and optionally its children.
*
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
Node.prototype.cloneNode = function (recursive) {
if (recursive === void 0) { recursive = false; }
return cloneNode(this, recursive);
};
return Node;
}());
exports.Node = Node;
var DataNode = /** @class */ (function (_super) {
__extends(DataNode, _super);
/**
* @param type The type of the node
* @param data The content of the data node
*/
function DataNode(type, data) {
var _this = _super.call(this, type) || this;
_this.data = data;
return _this;
}
Object.defineProperty(DataNode.prototype, "nodeValue", {
get: function () {
return this.data;
},
set: function (data) {
this.data = data;
},
enumerable: false,
configurable: true
});
return DataNode;
}(Node));
exports.DataNode = DataNode;
var Text = /** @class */ (function (_super) {
__extends(Text, _super);
function Text(data) {
return _super.call(this, "text" /* Text */, data) || this;
}
return Text;
}(DataNode));
exports.Text = Text;
var Comment = /** @class */ (function (_super) {
__extends(Comment, _super);
function Comment(data) {
return _super.call(this, "comment" /* Comment */, data) || this;
}
return Comment;
}(DataNode));
exports.Comment = Comment;
var ProcessingInstruction = /** @class */ (function (_super) {
__extends(ProcessingInstruction, _super);
function ProcessingInstruction(name, data) {
var _this = _super.call(this, "directive" /* Directive */, data) || this;
_this.name = name;
return _this;
}
return ProcessingInstruction;
}(DataNode));
exports.ProcessingInstruction = ProcessingInstruction;
/**
* A `Node` that can have children.
*/
var NodeWithChildren = /** @class */ (function (_super) {
__extends(NodeWithChildren, _super);
/**
* @param type Type of the node.
* @param children Children of the node. Only certain node types can have children.
*/
function NodeWithChildren(type, children) {
var _this = _super.call(this, type) || this;
_this.children = children;
return _this;
}
Object.defineProperty(NodeWithChildren.prototype, "firstChild", {
// Aliases
get: function () {
var _a;
return (_a = this.children[0]) !== null && _a !== void 0 ? _a : null;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NodeWithChildren.prototype, "lastChild", {
get: function () {
return this.children.length > 0
? this.children[this.children.length - 1]
: null;
},
enumerable: false,
configurable: true
});
Object.defineProperty(NodeWithChildren.prototype, "childNodes", {
get: function () {
return this.children;
},
set: function (children) {
this.children = children;
},
enumerable: false,
configurable: true
});
return NodeWithChildren;
}(Node));
exports.NodeWithChildren = NodeWithChildren;
var Document = /** @class */ (function (_super) {
__extends(Document, _super);
function Document(children) {
return _super.call(this, "root" /* Root */, children) || this;
}
return Document;
}(NodeWithChildren));
exports.Document = Document;
var Element = /** @class */ (function (_super) {
__extends(Element, _super);
/**
* @param name Name of the tag, eg. `div`, `span`.
* @param attribs Object mapping attribute names to attribute values.
* @param children Children of the node.
*/
function Element(name, attribs, children) {
if (children === void 0) { children = []; }
var _this = _super.call(this, name === "script"
? "script" /* Script */
: name === "style"
? "style" /* Style */
: "tag" /* Tag */, children) || this;
_this.name = name;
_this.attribs = attribs;
_this.attribs = attribs;
return _this;
}
Object.defineProperty(Element.prototype, "tagName", {
// DOM Level 1 aliases
get: function () {
return this.name;
},
set: function (name) {
this.name = name;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Element.prototype, "attributes", {
get: function () {
var _this = this;
return Object.keys(this.attribs).map(function (name) {
var _a, _b;
return ({
name: name,
value: _this.attribs[name],
namespace: (_a = _this["x-attribsNamespace"]) === null || _a === void 0 ? void 0 : _a[name],
prefix: (_b = _this["x-attribsPrefix"]) === null || _b === void 0 ? void 0 : _b[name],
});
});
},
enumerable: false,
configurable: true
});
return Element;
}(NodeWithChildren));
exports.Element = Element;
/**
* Clone a node, and optionally its children.
*
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
function cloneNode(node, recursive) {
if (recursive === void 0) { recursive = false; }
var result;
switch (node.type) {
case "text" /* Text */:
result = new Text(node.data);
break;
case "directive" /* Directive */: {
var instr = node;
result = new ProcessingInstruction(instr.name, instr.data);
if (instr["x-name"] != null) {
result["x-name"] = instr["x-name"];
result["x-publicId"] = instr["x-publicId"];
result["x-systemId"] = instr["x-systemId"];
}
break;
}
case "comment" /* Comment */:
result = new Comment(node.data);
break;
case "tag" /* Tag */:
case "script" /* Script */:
case "style" /* Style */: {
var elem = node;
var children = recursive ? cloneChildren(elem.children) : [];
var clone_1 = new Element(elem.name, __assign({}, elem.attribs), children);
children.forEach(function (child) { return (child.parent = clone_1); });
if (elem["x-attribsNamespace"]) {
clone_1["x-attribsNamespace"] = __assign({}, elem["x-attribsNamespace"]);
}
if (elem["x-attribsPrefix"]) {
clone_1["x-attribsPrefix"] = __assign({}, elem["x-attribsPrefix"]);
}
result = clone_1;
break;
}
case "cdata" /* CDATA */: {
var cdata = node;
var children = recursive ? cloneChildren(cdata.children) : [];
var clone_2 = new NodeWithChildren(node.type, children);
children.forEach(function (child) { return (child.parent = clone_2); });
result = clone_2;
break;
}
case "root" /* Root */: {
var doc = node;
var children = recursive ? cloneChildren(doc.children) : [];
var clone_3 = new Document(children);
children.forEach(function (child) { return (child.parent = clone_3); });
if (doc["x-mode"]) {
clone_3["x-mode"] = doc["x-mode"];
}
result = clone_3;
break;
}
case "doctype" /* Doctype */: {
// This type isn't used yet.
throw new Error("Not implemented yet: ElementType.Doctype case");
}
}
result.startIndex = node.startIndex;
result.endIndex = node.endIndex;
return result;
}
exports.cloneNode = cloneNode;
function cloneChildren(childs) {
var children = childs.map(function (child) { return cloneNode(child, true); });
for (var i = 1; i < children.length; i++) {
children[i].prev = children[i - 1];
children[i - 1].next = children[i];
}
return children;
}
});
var CASE_SENSITIVE_TAG_NAMES$1 = constants.CASE_SENSITIVE_TAG_NAMES;
var Comment = node.Comment;
var Element = node.Element;
var ProcessingInstruction = node.ProcessingInstruction;
var Text = node.Text;
var caseSensitiveTagNamesMap = {};
var tagName;
for (var i = 0, len = CASE_SENSITIVE_TAG_NAMES$1.length; i < len; i++) {
tagName = CASE_SENSITIVE_TAG_NAMES$1[i];
caseSensitiveTagNamesMap[tagName.toLowerCase()] = tagName;
}
/**
* Gets case-sensitive tag name.
*
* @param {string} tagName - Tag name in lowercase.
* @return {string|undefined} - Case-sensitive tag name.
*/
function getCaseSensitiveTagName(tagName) {
return caseSensitiveTagNamesMap[tagName];
}
/**
* Formats DOM attributes to a hash map.
*
* @param {NamedNodeMap} attributes - List of attributes.
* @return {object} - Map of attribute name to value.
*/
function formatAttributes(attributes) {
var result = {};
var attribute;
// `NamedNodeMap` is array-like
for (var i = 0, len = attributes.length; i < len; i++) {
attribute = attributes[i];
result[attribute.name] = attribute.value;
}
return result;
}
/**
* Corrects the tag name if it is case-sensitive (SVG).
* Otherwise, returns the lowercase tag name (HTML).
*
* @param {string} tagName - Lowercase tag name.
* @return {string} - Formatted tag name.
*/
function formatTagName(tagName) {
tagName = tagName.toLowerCase();
var caseSensitiveTagName = getCaseSensitiveTagName(tagName);
if (caseSensitiveTagName) {
return caseSensitiveTagName;
}
return tagName;
}
/**
* Transforms DOM nodes to `domhandler` nodes.
*
* @param {NodeList} nodes - DOM nodes.
* @param {Element|null} [parent=null] - Parent node.
* @param {string} [directive] - Directive.
* @return {Array<Comment|Element|ProcessingInstruction|Text>}
*/
function formatDOM(nodes, parent, directive) {
parent = parent || null;
var result = [];
for (var index = 0, len = nodes.length; index < len; index++) {
var node = nodes[index];
var current;
// set the node data given the type
switch (node.nodeType) {
case 1:
// script, style, or tag
current = new Element(
formatTagName(node.nodeName),
formatAttributes(node.attributes)
);
current.children = formatDOM(node.childNodes, current);
break;
case 3:
current = new Text(node.nodeValue);
break;
case 8:
current = new Comment(node.nodeValue);
break;
default:
continue;
}
// set previous node next
var prev = result[index - 1] || null;
if (prev) {
prev.next = current;
}
// set properties for current node
current.parent = parent;
current.prev = prev;
current.next = null;
result.push(current);
}
if (directive) {
current = new ProcessingInstruction(
directive.substring(0, directive.indexOf(' ')).toLowerCase(),
directive
);
current.next = result[0] || null;
current.parent = parent;
result.unshift(current);
if (result[1]) {
result[1].prev = result[0];
}
}
return result;
}
/**
* Detects if browser is Internet Explorer.
*
* @return {boolean} - Whether IE is detected.
*/
function isIE() {
return /(MSIE |Trident\/|Edge\/)/.test(navigator.userAgent);
}
var utilities$2 = {
formatAttributes: formatAttributes,
formatDOM: formatDOM,
isIE: isIE
};
// constants
var HTML = 'html';
var HEAD = 'head';
var BODY = 'body';
var FIRST_TAG_REGEX = /<([a-zA-Z]+[0-9]?)/; // e.g., <h1>
var HEAD_TAG_REGEX = /<head.*>/i;
var BODY_TAG_REGEX = /<body.*>/i;
// falls back to `parseFromString` if `createHTMLDocument` cannot be used
var parseFromDocument = function () {
throw new Error(
'This browser does not support `document.implementation.createHTMLDocument`'
);
};
var parseFromString = function () {
throw new Error(
'This browser does not support `DOMParser.prototype.parseFromString`'
);
};
/**
* DOMParser (performance: slow).
*
* @see https://developer.mozilla.org/docs/Web/API/DOMParser#Parsing_an_SVG_or_HTML_document
*/
if (typeof window.DOMParser === 'function') {
var domParser = new window.DOMParser();
var mimeType = 'text/html';
/**
* Creates an HTML document using `DOMParser.parseFromString`.