html-react-parser
Version:
HTML to React parser.
1,777 lines (1,717 loc) • 95.2 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 (require$$0) { 'use strict';
function _mergeNamespaces(n, m) {
m.forEach(function (e) {
e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
if (k !== 'default' && !(k in n)) {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
});
return Object.freeze(n);
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function getAugmentedNamespace(n) {
if (Object.prototype.hasOwnProperty.call(n, '__esModule')) return n;
var f = n.default;
if (typeof f == "function") {
var a = function a () {
var isInstance = false;
try {
isInstance = this instanceof a;
} catch {}
if (isInstance) {
return Reflect.construct(f, arguments, this.constructor);
}
return f.apply(this, arguments);
};
a.prototype = f.prototype;
} else a = {};
Object.defineProperty(a, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
var lib$1 = {};
var htmlToDom = {};
var hasRequiredHtmlToDom;
function requireHtmlToDom () {
if (hasRequiredHtmlToDom) return htmlToDom;
hasRequiredHtmlToDom = 1;
Object.defineProperty(htmlToDom, '__esModule', { value: true });
/** Types of elements found in htmlparser2's DOM */
var ElementType;
(function (ElementType) {
/** Type for the root element of a document */
ElementType["Root"] = "root";
/** Type for Text */
ElementType["Text"] = "text";
/** Type for <? ... ?> */
ElementType["Directive"] = "directive";
/** Type for <!-- ... --> */
ElementType["Comment"] = "comment";
/** Type for <script> tags */
ElementType["Script"] = "script";
/** Type for <style> tags */
ElementType["Style"] = "style";
/** Type for Any tag */
ElementType["Tag"] = "tag";
/** Type for <![CDATA[ ... ]]> */
ElementType["CDATA"] = "cdata";
/** Type for <!doctype ...> */
ElementType["Doctype"] = "doctype";
})(ElementType || (ElementType = {}));
/**
* Tests whether an element is a tag or not.
* @param element Element to test
* @param element.type Node type discriminator to check.
*/
function isTag$1(element) {
return (element.type === ElementType.Tag ||
element.type === ElementType.Script ||
element.type === ElementType.Style);
}
// Exports for backwards compatibility
/** Type for the root element of a document */
// eslint-disable-next-line prefer-destructuring
ElementType.Root;
/** Type for Text */
// eslint-disable-next-line prefer-destructuring
ElementType.Text;
/** Type for <? ... ?> */
// eslint-disable-next-line prefer-destructuring
ElementType.Directive;
/** Type for <!-- ... --> */
// eslint-disable-next-line prefer-destructuring
ElementType.Comment;
/** Type for <script> tags */
// eslint-disable-next-line prefer-destructuring
ElementType.Script;
/** Type for <style> tags */
// eslint-disable-next-line prefer-destructuring
ElementType.Style;
/** Type for Any tag */
// eslint-disable-next-line prefer-destructuring
ElementType.Tag;
/** Type for <![CDATA[ ... ]]> */
// eslint-disable-next-line prefer-destructuring
ElementType.CDATA;
/** Type for <!doctype ...> */
// eslint-disable-next-line prefer-destructuring
ElementType.Doctype;
/**
* This object will be used as the prototype for Nodes when creating a
* DOM-Level-1-compliant structure.
*/
class Node {
/** Parent of the node */
parent = null;
/** Previous sibling */
prev = null;
/** Next sibling */
next = null;
/** The start index of the node. Requires `withStartIndices` on the handler to be `true. */
startIndex = null;
/** The end index of the node. Requires `withEndIndices` on the handler to be `true. */
endIndex = null;
// Read-write aliases for properties
/**
* Same as {@link parent}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get parentNode() {
return this.parent;
}
set parentNode(parent) {
this.parent = parent;
}
/**
* Same as {@link prev}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get previousSibling() {
return this.prev;
}
set previousSibling(previous) {
this.prev = previous;
}
/**
* Same as {@link next}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get nextSibling() {
return this.next;
}
set nextSibling(next) {
this.next = next;
}
/**
* Clone this node, and optionally its children.
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
cloneNode(recursive = false) {
return cloneNode(this, recursive);
}
}
/**
* A node that contains some data.
*/
class DataNode extends Node {
data;
/**
* @param data The content of the data node
*/
constructor(data) {
super();
this.data = data;
}
/**
* Same as {@link data}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get nodeValue() {
return this.data;
}
set nodeValue(data) {
this.data = data;
}
}
/**
* Text within the document.
*/
class Text extends DataNode {
type = ElementType.Text;
get nodeType() {
return 3;
}
}
/**
* Comments within the document.
*/
class Comment extends DataNode {
type = ElementType.Comment;
get nodeType() {
return 8;
}
}
/**
* Processing instructions, including doc types.
*/
class ProcessingInstruction extends DataNode {
type = ElementType.Directive;
name;
constructor(name, data) {
super(data);
this.name = name;
}
get nodeType() {
return 1;
}
/** If this is a doctype, the document type name (parse5 only). */
"x-name";
/** If this is a doctype, the document type public identifier (parse5 only). */
"x-publicId";
/** If this is a doctype, the document type system identifier (parse5 only). */
"x-systemId";
}
/**
* A node that can have children.
*/
class NodeWithChildren extends Node {
children;
/**
* @param children Children of the node. Only certain node types can have children.
*/
constructor(children) {
super();
this.children = children;
}
// Aliases
/** First child of the node. */
get firstChild() {
return this.children[0] ?? null;
}
/** Last child of the node. */
get lastChild() {
return this.children.length > 0
? this.children[this.children.length - 1]
: null;
}
/**
* Same as {@link children}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get childNodes() {
return this.children;
}
set childNodes(children) {
this.children = children;
}
}
/**
* CDATA nodes.
*/
class CDATA extends NodeWithChildren {
type = ElementType.CDATA;
get nodeType() {
return 4;
}
}
/**
* The root node of the document.
*/
class Document extends NodeWithChildren {
type = ElementType.Root;
get nodeType() {
return 9;
}
}
/**
* An element within the DOM.
*/
class Element extends NodeWithChildren {
name;
attribs;
type;
/**
* @param name Name of the tag, eg. `div`, `span`.
* @param attribs Object mapping attribute names to attribute values.
* @param children Children of the node.
* @param type Node type used for the new node instance.
*/
constructor(name, attribs, children = [], type = name === "script"
? ElementType.Script
: name === "style"
? ElementType.Style
: ElementType.Tag) {
super(children);
this.name = name;
this.attribs = attribs;
this.type = type;
}
get nodeType() {
return 1;
}
// DOM Level 1 aliases
/**
* Same as {@link name}.
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
*/
get tagName() {
return this.name;
}
set tagName(name) {
this.name = name;
}
get attributes() {
return Object.keys(this.attribs).map((name) => ({
name,
value: this.attribs[name],
namespace: this["x-attribsNamespace"]?.[name],
prefix: this["x-attribsPrefix"]?.[name],
}));
}
/** Element namespace (parse5 only). */
namespace;
/** Element attribute namespaces (parse5 only). */
"x-attribsNamespace";
/** Element attribute namespace-related prefixes (parse5 only). */
"x-attribsPrefix";
}
/**
* Checks if `node` is an element node.
* @param node Node to check.
* @returns `true` if the node is an element node.
*/
function isTag(node) {
return isTag$1(node);
}
/**
* Checks if `node` is a CDATA node.
* @param node Node to check.
* @returns `true` if the node is a CDATA node.
*/
function isCDATA(node) {
return node.type === ElementType.CDATA;
}
/**
* Checks if `node` is a text node.
* @param node Node to check.
* @returns `true` if the node is a text node.
*/
function isText(node) {
return node.type === ElementType.Text;
}
/**
* Checks if `node` is a comment node.
* @param node Node to check.
* @returns `true` if the node is a comment node.
*/
function isComment(node) {
return node.type === ElementType.Comment;
}
/**
* Checks if `node` is a directive node.
* @param node Node to check.
* @returns `true` if the node is a directive node.
*/
function isDirective(node) {
return node.type === ElementType.Directive;
}
/**
* Checks if `node` is a document node.
* @param node Node to check.
* @returns `true` if the node is a document node.
*/
function isDocument(node) {
return node.type === ElementType.Root;
}
/**
* Clone a node, and optionally its children.
* @param node Node to clone.
* @param recursive Clone child nodes as well.
* @returns A clone of the node.
*/
function cloneNode(node, recursive = false) {
let result;
if (isText(node)) {
result = new Text(node.data);
}
else if (isComment(node)) {
result = new Comment(node.data);
}
else if (isTag(node)) {
const children = recursive ? cloneChildren(node.children) : [];
const clone = new Element(node.name, { ...node.attribs }, children);
for (const child of children) {
child.parent = clone;
}
if (node.namespace != null) {
clone.namespace = node.namespace;
}
if (node["x-attribsNamespace"]) {
clone["x-attribsNamespace"] = { ...node["x-attribsNamespace"] };
}
if (node["x-attribsPrefix"]) {
clone["x-attribsPrefix"] = { ...node["x-attribsPrefix"] };
}
result = clone;
}
else if (isCDATA(node)) {
const children = recursive ? cloneChildren(node.children) : [];
const clone = new CDATA(children);
for (const child of children) {
child.parent = clone;
}
result = clone;
}
else if (isDocument(node)) {
const children = recursive ? cloneChildren(node.children) : [];
const clone = new Document(children);
for (const child of children) {
child.parent = clone;
}
if (node["x-mode"]) {
clone["x-mode"] = node["x-mode"];
}
result = clone;
}
else if (isDirective(node)) {
const instruction = new ProcessingInstruction(node.name, node.data);
if (node["x-name"] != null) {
instruction["x-name"] = node["x-name"];
instruction["x-publicId"] = node["x-publicId"];
instruction["x-systemId"] = node["x-systemId"];
}
result = instruction;
}
else {
throw new Error(`Not implemented yet: ${node.type}`);
}
result.startIndex = node.startIndex;
result.endIndex = node.endIndex;
if (node.sourceCodeLocation != null) {
result.sourceCodeLocation = node.sourceCodeLocation;
}
return result;
}
/**
* Clone a list of child nodes.
* @param childs The child nodes to clone.
* @returns A list of cloned child nodes.
*/
function cloneChildren(childs) {
const children = childs.map((child) => cloneNode(child, true));
for (let index = 1; index < children.length; index++) {
children[index].prev = children[index - 1];
children[index - 1].next = children[index];
}
return children;
}
/**
* SVG elements are case-sensitive.
*
* @see 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',
'feGaussianBlur',
'feImage',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
'foreignObject',
'linearGradient',
'radialGradient',
'textPath',
];
var CASE_SENSITIVE_TAG_NAMES_MAP = CASE_SENSITIVE_TAG_NAMES.reduce(function (accumulator, tagName) {
accumulator[tagName.toLowerCase()] = tagName;
return accumulator;
}, {});
var CARRIAGE_RETURN = '\r';
var CARRIAGE_RETURN_REGEX = new RegExp(CARRIAGE_RETURN, 'g');
var CARRIAGE_RETURN_PLACEHOLDER = "__HTML_DOM_PARSER_CARRIAGE_RETURN_PLACEHOLDER_".concat(Date.now().toString(), "__");
var CARRIAGE_RETURN_PLACEHOLDER_REGEX = new RegExp(CARRIAGE_RETURN_PLACEHOLDER, 'g');
/**
* Gets case-sensitive tag name.
*
* @param tagName - Tag name in lowercase.
* @returns - Case-sensitive tag name.
*/
function getCaseSensitiveTagName(tagName) {
return CASE_SENSITIVE_TAG_NAMES_MAP[tagName];
}
/**
* Formats DOM attributes to a hash map.
*
* @param attributes - List of attributes.
* @returns - Map of attribute name to value.
*/
function formatAttributes(attributes) {
var map = {};
var index = 0;
var attributesLength = attributes.length;
// `NamedNodeMap` is array-like
for (; index < attributesLength; index++) {
var attribute = attributes[index];
map[attribute.name] = attribute.value;
}
return map;
}
/**
* Corrects the tag name if it is case-sensitive (SVG).
* Otherwise, returns the lowercase tag name (HTML).
*
* @param tagName - Lowercase tag name.
* @returns - Formatted tag name.
*/
function formatTagName(tagName) {
tagName = tagName.toLowerCase();
var caseSensitiveTagName = getCaseSensitiveTagName(tagName);
if (caseSensitiveTagName) {
return caseSensitiveTagName;
}
return tagName;
}
/**
* Checks if an HTML string contains an opening tag (case-insensitive).
*
* @param html - HTML string.
* @param tagName - Tag name to search for (e.g., 'head' or 'body').
* @returns - Whether the tag is found.
*/
function hasOpenTag(html, tagName) {
var openTag = '<' + tagName;
var index = html.toLowerCase().indexOf(openTag);
if (index === -1) {
return false;
}
var char = html[index + openTag.length];
// the character after the tag name must be '>' or whitespace (for attributes)
return (char === '>' ||
char === ' ' ||
char === '\t' ||
char === '\n' ||
char === '\r' ||
char === '/');
}
/**
* Escapes special characters before parsing.
*
* @param html - The HTML string.
* @returns - HTML string with escaped special characters.
*/
function escapeSpecialCharacters(html) {
return html.replace(CARRIAGE_RETURN_REGEX, CARRIAGE_RETURN_PLACEHOLDER);
}
/**
* Reverts escaped special characters back to actual characters.
*
* @param text - The text with escaped characters.
* @returns - Text with escaped characters reverted.
*/
function revertEscapedCharacters(text) {
return text.replace(CARRIAGE_RETURN_PLACEHOLDER_REGEX, CARRIAGE_RETURN);
}
/**
* Transforms DOM nodes to `domhandler` nodes.
*
* @param nodes - DOM nodes.
* @param parent - Parent node.
* @param directive - Directive.
* @returns - Nodes.
*/
function formatDOM(nodes, parent, directive) {
var _a, _b, _c, _d;
if (parent === void 0) { parent = null; }
var domNodes = [];
var current;
var index = 0;
var nodesLength = nodes.length;
for (; index < nodesLength; index++) {
var node = nodes[index];
// set the node data given the type
switch (node.nodeType) {
case 1: {
var tagName = formatTagName(node.nodeName);
// script, style, or tag
current = new Element(tagName, formatAttributes(node.attributes));
current.children = formatDOM(
// template children are on content
tagName === 'template'
? node.content.childNodes
: node.childNodes, current);
break;
}
/* v8 ignore start */
case 3:
current = new Text(revertEscapedCharacters((_a = node.nodeValue) !== null && _a !== void 0 ? _a : ''));
break;
case 8:
current = new Comment((_b = node.nodeValue) !== null && _b !== void 0 ? _b : '');
break;
/* v8 ignore stop */
default:
continue;
}
// set previous node next
var prev = (_c = domNodes[index - 1]) !== null && _c !== void 0 ? _c : null;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (prev) {
prev.next = current;
}
// set properties for current node
current.parent = parent;
current.prev = prev;
current.next = null;
domNodes.push(current);
}
if (directive) {
current = new ProcessingInstruction(directive.substring(0, directive.indexOf(' ')).toLowerCase(), directive);
current.next = (_d = domNodes[0]) !== null && _d !== void 0 ? _d : null;
current.parent = parent;
domNodes.unshift(current);
if (domNodes[1]) {
domNodes[1].prev = domNodes[0];
}
}
return domNodes;
}
// constants
var HTML = 'html';
var HEAD = 'head';
var BODY = 'body';
var FIRST_TAG_REGEX = /<([a-zA-Z]+[0-9]?)/; // e.g., <h1>
// falls back to `parseFromString` if `createHTMLDocument` cannot be used
/* eslint-disable @typescript-eslint/no-unused-vars */
/* v8 ignore start */
var parseFromDocument = function (html, tagName) {
throw new Error('This browser does not support `document.implementation.createHTMLDocument`');
};
var parseFromString = function (html, tagName) {
throw new Error('This browser does not support `DOMParser.prototype.parseFromString`');
};
var DOMParser = typeof window === 'object' && window.DOMParser;
/**
* DOMParser (performance: slow).
*
* @see https://developer.mozilla.org/docs/Web/API/DOMParser#Parsing_an_SVG_or_HTML_document
*/
if (typeof DOMParser === 'function') {
var domParser_1 = new DOMParser();
var mimeType_1 = 'text/html';
/**
* Creates an HTML document using `DOMParser.parseFromString`.
*
* @param html - The HTML string.
* @param tagName - The element to render the HTML (with 'body' as fallback).
* @returns - Document.
*/
parseFromString = function (html, tagName) {
if (tagName) {
html = "<".concat(tagName, ">").concat(html, "</").concat(tagName, ">");
}
return domParser_1.parseFromString(html, mimeType_1);
};
parseFromDocument = parseFromString;
}
/**
* DOMImplementation (performance: fair).
*
* @see https://developer.mozilla.org/docs/Web/API/DOMImplementation/createHTMLDocument
*/
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (typeof document === 'object' && document.implementation) {
var htmlDocument_1 = document.implementation.createHTMLDocument();
/**
* Use HTML document created by `document.implementation.createHTMLDocument`.
*
* @param html - The HTML string.
* @param tagName - The element to render the HTML (with 'body' as fallback).
* @returns - Document
*/
parseFromDocument = function (html, tagName) {
if (tagName) {
var element = htmlDocument_1.documentElement.querySelector(tagName);
if (element) {
element.innerHTML = html;
}
return htmlDocument_1;
}
htmlDocument_1.documentElement.innerHTML = html;
return htmlDocument_1;
};
}
/**
* Template (performance: fast).
*
* @see https://developer.mozilla.org/docs/Web/HTML/Element/template
*/
var template = typeof document === 'object' && document.createElement('template');
var parseFromTemplate;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (template && template.content) {
/**
* Uses a template element (content fragment) to parse HTML.
*
* @param html - HTML string.
* @returns - Nodes.
*/
parseFromTemplate = function (html) {
template.innerHTML = html;
return template.content.childNodes;
};
}
var createNodeList = function () { return document.createDocumentFragment().childNodes; };
/* v8 ignore stop */
/**
* Parses HTML string to DOM nodes.
*
* @param html - HTML markup.
* @returns - DOM nodes.
*/
function domparser(html) {
var _a, _b, _c, _d, _e, _f;
// Escape special characters before parsing
html = escapeSpecialCharacters(html);
var match = FIRST_TAG_REGEX.exec(html);
var firstTagName = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
switch (firstTagName) {
case HTML: {
var doc = parseFromString(html);
// the created document may come with filler head/body elements,
// so make sure to remove them if they don't actually exist
if (!hasOpenTag(html, HEAD)) {
var element = doc.querySelector(HEAD);
(_b = element === null || element === void 0 ? void 0 : element.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(element);
}
if (!hasOpenTag(html, BODY)) {
var element = doc.querySelector(BODY);
(_c = element === null || element === void 0 ? void 0 : element.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(element);
}
return doc.querySelectorAll(HTML);
}
case HEAD:
case BODY: {
var elements = parseFromDocument(html).querySelectorAll(firstTagName);
// if there's a sibling element, then return both elements
/* v8 ignore next */
if (hasOpenTag(html, BODY) && hasOpenTag(html, HEAD)) {
return (_e = (_d = elements[0].parentNode) === null || _d === void 0 ? void 0 : _d.childNodes) !== null && _e !== void 0 ? _e : createNodeList();
}
return elements;
}
// low-level tag or text
/* v8 ignore start */
default: {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (parseFromTemplate) {
return parseFromTemplate(html);
}
var element = parseFromDocument(html, BODY).querySelector(BODY);
return (_f = element === null || element === void 0 ? void 0 : element.childNodes) !== null && _f !== void 0 ? _f : createNodeList();
}
/* v8 ignore stop */
}
}
var DIRECTIVE_REGEX = /<(![a-zA-Z\s]+)>/; // e.g., <!doctype html>
/**
* Parses HTML string to DOM nodes in browser.
*
* @param html - HTML markup.
* @returns - DOM elements.
*/
function HTMLDOMParser(html) {
if (typeof html !== 'string') {
throw new TypeError('First argument must be a string');
}
if (!html) {
return [];
}
// match directive
var match = DIRECTIVE_REGEX.exec(html);
var directive = match ? match[1] : undefined;
return formatDOM(domparser(html), null, directive);
}
htmlToDom.default = HTMLDOMParser;
return htmlToDom;
}
var attributesToProps = {};
var lib = {};
var possibleStandardNamesOptimized = {};
var hasRequiredPossibleStandardNamesOptimized;
function requirePossibleStandardNamesOptimized () {
if (hasRequiredPossibleStandardNamesOptimized) return possibleStandardNamesOptimized;
hasRequiredPossibleStandardNamesOptimized = 1;
// An attribute in which the DOM/SVG standard name is the same as the React prop name (e.g., 'accept').
var SAME = 0;
possibleStandardNamesOptimized.SAME = SAME;
// An attribute in which the React prop name is the camelcased version of the DOM/SVG standard name (e.g., 'acceptCharset').
var CAMELCASE = 1;
possibleStandardNamesOptimized.CAMELCASE = CAMELCASE;
possibleStandardNamesOptimized.possibleStandardNames = {
accept: 0,
acceptCharset: 1,
'accept-charset': 'acceptCharset',
accessKey: 1,
action: 0,
allowFullScreen: 1,
alt: 0,
as: 0,
async: 0,
autoCapitalize: 1,
autoComplete: 1,
autoCorrect: 1,
autoFocus: 1,
autoPlay: 1,
autoSave: 1,
capture: 0,
cellPadding: 1,
cellSpacing: 1,
challenge: 0,
charSet: 1,
checked: 0,
children: 0,
cite: 0,
class: 'className',
classID: 1,
className: 1,
cols: 0,
colSpan: 1,
content: 0,
contentEditable: 1,
contextMenu: 1,
controls: 0,
controlsList: 1,
coords: 0,
crossOrigin: 1,
dangerouslySetInnerHTML: 1,
data: 0,
dateTime: 1,
default: 0,
defaultChecked: 1,
defaultValue: 1,
defer: 0,
dir: 0,
disabled: 0,
disablePictureInPicture: 1,
disableRemotePlayback: 1,
download: 0,
draggable: 0,
encType: 1,
enterKeyHint: 1,
for: 'htmlFor',
form: 0,
formMethod: 1,
formAction: 1,
formEncType: 1,
formNoValidate: 1,
formTarget: 1,
frameBorder: 1,
headers: 0,
height: 0,
hidden: 0,
high: 0,
href: 0,
hrefLang: 1,
htmlFor: 1,
httpEquiv: 1,
'http-equiv': 'httpEquiv',
icon: 0,
id: 0,
innerHTML: 1,
inputMode: 1,
integrity: 0,
is: 0,
itemID: 1,
itemProp: 1,
itemRef: 1,
itemScope: 1,
itemType: 1,
keyParams: 1,
keyType: 1,
kind: 0,
label: 0,
lang: 0,
list: 0,
loop: 0,
low: 0,
manifest: 0,
marginWidth: 1,
marginHeight: 1,
max: 0,
maxLength: 1,
media: 0,
mediaGroup: 1,
method: 0,
min: 0,
minLength: 1,
multiple: 0,
muted: 0,
name: 0,
noModule: 1,
nonce: 0,
noValidate: 1,
open: 0,
optimum: 0,
pattern: 0,
placeholder: 0,
playsInline: 1,
poster: 0,
preload: 0,
profile: 0,
radioGroup: 1,
readOnly: 1,
referrerPolicy: 1,
rel: 0,
required: 0,
reversed: 0,
role: 0,
rows: 0,
rowSpan: 1,
sandbox: 0,
scope: 0,
scoped: 0,
scrolling: 0,
seamless: 0,
selected: 0,
shape: 0,
size: 0,
sizes: 0,
span: 0,
spellCheck: 1,
src: 0,
srcDoc: 1,
srcLang: 1,
srcSet: 1,
start: 0,
step: 0,
style: 0,
summary: 0,
tabIndex: 1,
target: 0,
title: 0,
type: 0,
useMap: 1,
value: 0,
width: 0,
wmode: 0,
wrap: 0,
about: 0,
accentHeight: 1,
'accent-height': 'accentHeight',
accumulate: 0,
additive: 0,
alignmentBaseline: 1,
'alignment-baseline': 'alignmentBaseline',
allowReorder: 1,
alphabetic: 0,
amplitude: 0,
arabicForm: 1,
'arabic-form': 'arabicForm',
ascent: 0,
attributeName: 1,
attributeType: 1,
autoReverse: 1,
azimuth: 0,
baseFrequency: 1,
baselineShift: 1,
'baseline-shift': 'baselineShift',
baseProfile: 1,
bbox: 0,
begin: 0,
bias: 0,
by: 0,
calcMode: 1,
capHeight: 1,
'cap-height': 'capHeight',
clip: 0,
clipPath: 1,
'clip-path': 'clipPath',
clipPathUnits: 1,
clipRule: 1,
'clip-rule': 'clipRule',
color: 0,
colorInterpolation: 1,
'color-interpolation': 'colorInterpolation',
colorInterpolationFilters: 1,
'color-interpolation-filters': 'colorInterpolationFilters',
colorProfile: 1,
'color-profile': 'colorProfile',
colorRendering: 1,
'color-rendering': 'colorRendering',
contentScriptType: 1,
contentStyleType: 1,
cursor: 0,
cx: 0,
cy: 0,
d: 0,
datatype: 0,
decelerate: 0,
descent: 0,
diffuseConstant: 1,
direction: 0,
display: 0,
divisor: 0,
dominantBaseline: 1,
'dominant-baseline': 'dominantBaseline',
dur: 0,
dx: 0,
dy: 0,
edgeMode: 1,
elevation: 0,
enableBackground: 1,
'enable-background': 'enableBackground',
end: 0,
exponent: 0,
externalResourcesRequired: 1,
fill: 0,
fillOpacity: 1,
'fill-opacity': 'fillOpacity',
fillRule: 1,
'fill-rule': 'fillRule',
filter: 0,
filterRes: 1,
filterUnits: 1,
floodOpacity: 1,
'flood-opacity': 'floodOpacity',
floodColor: 1,
'flood-color': 'floodColor',
focusable: 0,
fontFamily: 1,
'font-family': 'fontFamily',
fontSize: 1,
'font-size': 'fontSize',
fontSizeAdjust: 1,
'font-size-adjust': 'fontSizeAdjust',
fontStretch: 1,
'font-stretch': 'fontStretch',
fontStyle: 1,
'font-style': 'fontStyle',
fontVariant: 1,
'font-variant': 'fontVariant',
fontWeight: 1,
'font-weight': 'fontWeight',
format: 0,
from: 0,
fx: 0,
fy: 0,
g1: 0,
g2: 0,
glyphName: 1,
'glyph-name': 'glyphName',
glyphOrientationHorizontal: 1,
'glyph-orientation-horizontal': 'glyphOrientationHorizontal',
glyphOrientationVertical: 1,
'glyph-orientation-vertical': 'glyphOrientationVertical',
glyphRef: 1,
gradientTransform: 1,
gradientUnits: 1,
hanging: 0,
horizAdvX: 1,
'horiz-adv-x': 'horizAdvX',
horizOriginX: 1,
'horiz-origin-x': 'horizOriginX',
ideographic: 0,
imageRendering: 1,
'image-rendering': 'imageRendering',
in2: 0,
in: 0,
inlist: 0,
intercept: 0,
k1: 0,
k2: 0,
k3: 0,
k4: 0,
k: 0,
kernelMatrix: 1,
kernelUnitLength: 1,
kerning: 0,
keyPoints: 1,
keySplines: 1,
keyTimes: 1,
lengthAdjust: 1,
letterSpacing: 1,
'letter-spacing': 'letterSpacing',
lightingColor: 1,
'lighting-color': 'lightingColor',
limitingConeAngle: 1,
local: 0,
markerEnd: 1,
'marker-end': 'markerEnd',
markerHeight: 1,
markerMid: 1,
'marker-mid': 'markerMid',
markerStart: 1,
'marker-start': 'markerStart',
markerUnits: 1,
markerWidth: 1,
mask: 0,
maskContentUnits: 1,
maskUnits: 1,
mathematical: 0,
mode: 0,
numOctaves: 1,
offset: 0,
opacity: 0,
operator: 0,
order: 0,
orient: 0,
orientation: 0,
origin: 0,
overflow: 0,
overlinePosition: 1,
'overline-position': 'overlinePosition',
overlineThickness: 1,
'overline-thickness': 'overlineThickness',
paintOrder: 1,
'paint-order': 'paintOrder',
panose1: 0,
'panose-1': 'panose1',
pathLength: 1,
patternContentUnits: 1,
patternTransform: 1,
patternUnits: 1,
pointerEvents: 1,
'pointer-events': 'pointerEvents',
points: 0,
pointsAtX: 1,
pointsAtY: 1,
pointsAtZ: 1,
prefix: 0,
preserveAlpha: 1,
preserveAspectRatio: 1,
primitiveUnits: 1,
property: 0,
r: 0,
radius: 0,
refX: 1,
refY: 1,
renderingIntent: 1,
'rendering-intent': 'renderingIntent',
repeatCount: 1,
repeatDur: 1,
requiredExtensions: 1,
requiredFeatures: 1,
resource: 0,
restart: 0,
result: 0,
results: 0,
rotate: 0,
rx: 0,
ry: 0,
scale: 0,
security: 0,
seed: 0,
shapeRendering: 1,
'shape-rendering': 'shapeRendering',
slope: 0,
spacing: 0,
specularConstant: 1,
specularExponent: 1,
speed: 0,
spreadMethod: 1,
startOffset: 1,
stdDeviation: 1,
stemh: 0,
stemv: 0,
stitchTiles: 1,
stopColor: 1,
'stop-color': 'stopColor',
stopOpacity: 1,
'stop-opacity': 'stopOpacity',
strikethroughPosition: 1,
'strikethrough-position': 'strikethroughPosition',
strikethroughThickness: 1,
'strikethrough-thickness': 'strikethroughThickness',
string: 0,
stroke: 0,
strokeDasharray: 1,
'stroke-dasharray': 'strokeDasharray',
strokeDashoffset: 1,
'stroke-dashoffset': 'strokeDashoffset',
strokeLinecap: 1,
'stroke-linecap': 'strokeLinecap',
strokeLinejoin: 1,
'stroke-linejoin': 'strokeLinejoin',
strokeMiterlimit: 1,
'stroke-miterlimit': 'strokeMiterlimit',
strokeWidth: 1,
'stroke-width': 'strokeWidth',
strokeOpacity: 1,
'stroke-opacity': 'strokeOpacity',
suppressContentEditableWarning: 1,
suppressHydrationWarning: 1,
surfaceScale: 1,
systemLanguage: 1,
tableValues: 1,
targetX: 1,
targetY: 1,
textAnchor: 1,
'text-anchor': 'textAnchor',
textDecoration: 1,
'text-decoration': 'textDecoration',
textLength: 1,
textRendering: 1,
'text-rendering': 'textRendering',
to: 0,
transform: 0,
typeof: 0,
u1: 0,
u2: 0,
underlinePosition: 1,
'underline-position': 'underlinePosition',
underlineThickness: 1,
'underline-thickness': 'underlineThickness',
unicode: 0,
unicodeBidi: 1,
'unicode-bidi': 'unicodeBidi',
unicodeRange: 1,
'unicode-range': 'unicodeRange',
unitsPerEm: 1,
'units-per-em': 'unitsPerEm',
unselectable: 0,
vAlphabetic: 1,
'v-alphabetic': 'vAlphabetic',
values: 0,
vectorEffect: 1,
'vector-effect': 'vectorEffect',
version: 0,
vertAdvY: 1,
'vert-adv-y': 'vertAdvY',
vertOriginX: 1,
'vert-origin-x': 'vertOriginX',
vertOriginY: 1,
'vert-origin-y': 'vertOriginY',
vHanging: 1,
'v-hanging': 'vHanging',
vIdeographic: 1,
'v-ideographic': 'vIdeographic',
viewBox: 1,
viewTarget: 1,
visibility: 0,
vMathematical: 1,
'v-mathematical': 'vMathematical',
vocab: 0,
widths: 0,
wordSpacing: 1,
'word-spacing': 'wordSpacing',
writingMode: 1,
'writing-mode': 'writingMode',
x1: 0,
x2: 0,
x: 0,
xChannelSelector: 1,
xHeight: 1,
'x-height': 'xHeight',
xlinkActuate: 1,
'xlink:actuate': 'xlinkActuate',
xlinkArcrole: 1,
'xlink:arcrole': 'xlinkArcrole',
xlinkHref: 1,
'xlink:href': 'xlinkHref',
xlinkRole: 1,
'xlink:role': 'xlinkRole',
xlinkShow: 1,
'xlink:show': 'xlinkShow',
xlinkTitle: 1,
'xlink:title': 'xlinkTitle',
xlinkType: 1,
'xlink:type': 'xlinkType',
xmlBase: 1,
'xml:base': 'xmlBase',
xmlLang: 1,
'xml:lang': 'xmlLang',
xmlns: 0,
'xml:space': 'xmlSpace',
xmlnsXlink: 1,
'xmlns:xlink': 'xmlnsXlink',
xmlSpace: 1,
y1: 0,
y2: 0,
y: 0,
yChannelSelector: 1,
z: 0,
zoomAndPan: 1
};
return possibleStandardNamesOptimized;
}
var hasRequiredLib$1;
function requireLib$1 () {
if (hasRequiredLib$1) return lib;
hasRequiredLib$1 = 1;
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
// A reserved attribute.
// It is handled by React separately and shouldn't be written to the DOM.
const RESERVED = 0;
// A simple string attribute.
// Attributes that aren't in the filter are presumed to have this type.
const STRING = 1;
// A string attribute that accepts booleans in React. In HTML, these are called
// "enumerated" attributes with "true" and "false" as possible values.
// When true, it should be set to a "true" string.
// When false, it should be set to a "false" string.
const BOOLEANISH_STRING = 2;
// A real boolean attribute.
// When true, it should be present (set either to an empty string or its name).
// When false, it should be omitted.
const BOOLEAN = 3;
// An attribute that can be used as a flag as well as with a value.
// When true, it should be present (set either to an empty string or its name).
// When false, it should be omitted.
// For any other value, should be present with that value.
const OVERLOADED_BOOLEAN = 4;
// An attribute that must be numeric or parse as a numeric.
// When falsy, it should be removed.
const NUMERIC = 5;
// An attribute that must be positive numeric or parse as a positive numeric.
// When falsy, it should be removed.
const POSITIVE_NUMERIC = 6;
function getPropertyInfo(name) {
return properties.hasOwnProperty(name) ? properties[name] : null;
}
function PropertyInfoRecord(
name,
type,
mustUseProperty,
attributeName,
attributeNamespace,
sanitizeURL,
removeEmptyString,
) {
this.acceptsBooleans =
type === BOOLEANISH_STRING ||
type === BOOLEAN ||
type === OVERLOADED_BOOLEAN;
this.attributeName = attributeName;
this.attributeNamespace = attributeNamespace;
this.mustUseProperty = mustUseProperty;
this.propertyName = name;
this.type = type;
this.sanitizeURL = sanitizeURL;
this.removeEmptyString = removeEmptyString;
}
// When adding attributes to this list, be sure to also add them to
// the `possibleStandardNames` module to ensure casing and incorrect
// name warnings.
const properties = {};
// These props are reserved by React. They shouldn't be written to the DOM.
const reservedProps = [
'children',
'dangerouslySetInnerHTML',
// TODO: This prevents the assignment of defaultValue to regular
// elements (not just inputs). Now that ReactDOMInput assigns to the
// defaultValue property -- do we need this?
'defaultValue',
'defaultChecked',
'innerHTML',
'suppressContentEditableWarning',
'suppressHydrationWarning',
'style',
];
reservedProps.forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
RESERVED,
false, // mustUseProperty
name, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// A few React string attributes have a different name.
// This is a mapping from React prop names to the attribute names.
[
['acceptCharset', 'accept-charset'],
['className', 'class'],
['htmlFor', 'for'],
['httpEquiv', 'http-equiv'],
].forEach(([name, attributeName]) => {
properties[name] = new PropertyInfoRecord(
name,
STRING,
false, // mustUseProperty
attributeName, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are "enumerated" HTML attributes that accept "true" and "false".
// In React, we let users pass `true` and `false` even though technically
// these aren't boolean attributes (they are coerced to strings).
['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
BOOLEANISH_STRING,
false, // mustUseProperty
name.toLowerCase(), // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are "enumerated" SVG attributes that accept "true" and "false".
// In React, we let users pass `true` and `false` even though technically
// these aren't boolean attributes (they are coerced to strings).
// Since these are SVG attributes, their attribute names are case-sensitive.
[
'autoReverse',
'externalResourcesRequired',
'focusable',
'preserveAlpha',
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
BOOLEANISH_STRING,
false, // mustUseProperty
name, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are HTML boolean attributes.
[
'allowFullScreen',
'async',
// Note: there is a special case that prevents it from being written to the DOM
// on the client side because the browsers are inconsistent. Instead we call focus().
'autoFocus',
'autoPlay',
'controls',
'default',
'defer',
'disabled',
'disablePictureInPicture',
'disableRemotePlayback',
'formNoValidate',
'hidden',
'loop',
'noModule',
'noValidate',
'open',
'playsInline',
'readOnly',
'required',
'reversed',
'scoped',
'seamless',
// Microdata
'itemScope',
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
BOOLEAN,
false, // mustUseProperty
name.toLowerCase(), // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are the few React props that we set as DOM properties
// rather than attributes. These are all booleans.
[
'checked',
// Note: `option.selected` is not updated if `select.multiple` is
// disabled with `removeAttribute`. We have special logic for handling this.
'multiple',
'muted',
'selected',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
BOOLEAN,
true, // mustUseProperty
name, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are HTML attributes that are "overloaded booleans": they behave like
// booleans, but can also accept a string value.
[
'capture',
'download',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
OVERLOADED_BOOLEAN,
false, // mustUseProperty
name, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are HTML attributes that must be positive numbers.
[
'cols',
'rows',
'size',
'span',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
POSITIVE_NUMERIC,
false, // mustUseProperty
name, // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// These are HTML attributes that must be numbers.
['rowSpan', 'start'].forEach(name => {
properties[name] = new PropertyInfoRecord(
name,
NUMERIC,
false, // mustUseProperty
name.toLowerCase(), // attributeName
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
const CAMELIZE = /[\-\:]([a-z])/g;
const capitalize = token => token[1].toUpperCase();
// This is a list of all SVG attributes that need special casing, namespacing,
// or boolean value assignment. Regular attributes that just accept strings
// and have the same names are omitted, just like in the HTML attribute filter.
// Some of these attributes can be hard to find. This list was created by
// scraping the MDN documentation.
[
'accent-height',
'alignment-baseline',
'arabic-form',
'baseline-shift',
'cap-height',
'clip-path',
'clip-rule',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'dominant-baseline',
'enable-background',
'fill-opacity',
'fill-rule',
'flood-color',
'flood-opacity',
'font-family',
'font-size',
'font-size-adjust',
'font-stretch',
'font-style',
'font-variant',
'font-weight',
'glyph-name',
'glyph-orientation-horizontal',
'glyph-orientation-vertical',
'horiz-adv-x',
'horiz-origin-x',
'image-rendering',
'letter-spacing',
'lighting-color',
'marker-end',
'marker-mid',
'marker-start',
'overline-position',
'overline-thickness',
'paint-order',
'panose-1',
'pointer-events',
'rendering-intent',
'shape-rendering',
'stop-color',
'stop-opacity',
'strikethrough-position',
'strikethrough-thickness',
'stroke-dasharray',
'stroke-dashoffset',
'stroke-linecap',
'stroke-linejoin',
'stroke-miterlimit',
'stroke-opacity',
'stroke-width',
'text-anchor',
'text-decoration',
'text-rendering',
'underline-position',
'underline-thickness',
'unicode-bidi',
'unicode-range',
'units-per-em',
'v-alphabetic',
'v-hanging',
'v-ideographic',
'v-mathematical',
'vector-effect',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'word-spacing',
'writing-mode',
'xmlns:xlink',
'x-height',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(attributeName => {
const name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(
name,
STRING,
false, // mustUseProperty
attributeName,
null, // attributeNamespace
false, // sanitizeURL
false, // removeEmptyString
);
});
// String SVG attributes with the xlink namespace.
[
'xlink:actuate',
'xlink:arcrole',
'xlink:role',
'xlink:show',
'xlink:title',
'xlink:type',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(attributeName => {
const name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(
name,
STRING,
false, // mustUseProperty
attributeName,
'http://www.w3.org/1999/xlink',
false, // sanitizeURL
false, // removeEmptyString
);
});
// String SVG attributes with the xml namespace.
[
'xml:base',
'xml:lang',
'xml:space',
// NOTE: if you add a camelCased prop to this list,
// you'll need to set attributeName to name.toLowerCase()
// instead in the assignment below.
].forEach(attributeName => {
const name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(
name,
STRING,
false, // mustUseProperty
attributeName,
'http://www.w3.org/XML/1998/namespace',
false, // sanitizeURL
false, // removeEmptyString
);
});
// These attribute exists both in HTML and SVG.
// The attribute name is case-sensitive in SVG so we can't just use
// the React name like we do for attributes that exist only in HTML.
['tabIndex', 'crossOrigin'].forEach(attributeName => {
properties[attributeName] = new Prop