html-react-parser 6.0.1 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -13
- package/dist/html-react-parser.js +186 -168
- package/dist/html-react-parser.js.map +1 -1
- package/dist/html-react-parser.min.js +1 -1
- package/dist/html-react-parser.min.js.map +1 -1
- package/lib/dom-to-react.d.ts.map +1 -1
- package/lib/dom-to-react.js +12 -0
- package/lib/dom-to-react.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +2 -1
- package/lib/types.d.ts.map +1 -1
- package/package.json +22 -22
- package/src/dom-to-react.ts +16 -0
- package/src/index.ts +6 -4
- package/src/types.ts +2 -1
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
|
|
|
43
43
|
- [library](#library)
|
|
44
44
|
- [htmlparser2](#htmlparser2)
|
|
45
45
|
- [trim](#trim)
|
|
46
|
+
- [trustedTypePolicy](#trustedtypepolicy)
|
|
46
47
|
- [Migration](#migration)
|
|
47
48
|
- [v5](#v5)
|
|
48
49
|
- [v4](#v4)
|
|
@@ -208,7 +209,7 @@ parse('<br>', {
|
|
|
208
209
|
|
|
209
210
|
> [!NOTE]
|
|
210
211
|
>
|
|
211
|
-
> The index will restart at 0 when traversing the node's children so don't rely on index being a unique key
|
|
212
|
+
> The index will restart at 0 when traversing the node's children so don't rely on index being a unique key (see [#1259](https://github.com/remarkablemark/html-react-parser/issues/1259#issuecomment-1889574133)).
|
|
212
213
|
|
|
213
214
|
#### replace with TypeScript
|
|
214
215
|
|
|
@@ -244,7 +245,7 @@ If you're having issues, take a look at our [Create React App example](./example
|
|
|
244
245
|
|
|
245
246
|
#### replace element and children
|
|
246
247
|
|
|
247
|
-
Replace the element and its children
|
|
248
|
+
Replace the element and its children:
|
|
248
249
|
|
|
249
250
|
```tsx
|
|
250
251
|
import parse, { domToReact } from 'html-react-parser';
|
|
@@ -335,7 +336,7 @@ parse(html, options);
|
|
|
335
336
|
|
|
336
337
|
#### replace and remove element
|
|
337
338
|
|
|
338
|
-
|
|
339
|
+
Exclude an element from rendering by replacing it with `<React.Fragment>`:
|
|
339
340
|
|
|
340
341
|
```tsx
|
|
341
342
|
parse('<p><br id="remove"></p>', {
|
|
@@ -443,6 +444,21 @@ However, intentional whitespace may be stripped out:
|
|
|
443
444
|
parse('<p> </p>', { trim: true }); // React.createElement('p')
|
|
444
445
|
```
|
|
445
446
|
|
|
447
|
+
### trustedTypePolicy
|
|
448
|
+
|
|
449
|
+
When running in a browser, you can pass a [Trusted Types](https://developer.mozilla.org/docs/Web/API/Trusted_Types_API) policy so the parser calls `trustedTypePolicy.createHTML` before assigning content to `innerHTML`:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
parse('<div>Hello</div>', {
|
|
453
|
+
trustedTypePolicy: window.trustedTypes?.createPolicy('my-policy', {
|
|
454
|
+
createHTML(input) {
|
|
455
|
+
// apply sanitization logic here
|
|
456
|
+
return DOMPurify.sanitize(input);
|
|
457
|
+
},
|
|
458
|
+
}),
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
446
462
|
## Migration
|
|
447
463
|
|
|
448
464
|
### v6
|
|
@@ -511,27 +527,27 @@ Since [v1.1.1](https://github.com/remarkablemark/html-react-parser/releases/tag/
|
|
|
511
527
|
|
|
512
528
|
### Is this XSS safe?
|
|
513
529
|
|
|
514
|
-
No, this library is
|
|
530
|
+
No, this library is **not** [XSS (cross-site scripting)](https://wikipedia.org/wiki/Cross-site_scripting) safe (see [#94](https://github.com/remarkablemark/html-react-parser/issues/94)). However, you can mitigate this risk by enforcing a Content Security Policy (CSP) with [Trusted Types](#trustedtypepolicy).
|
|
515
531
|
|
|
516
532
|
### Does invalid HTML get sanitized?
|
|
517
533
|
|
|
518
|
-
No, this library does
|
|
534
|
+
No, this library does **not** sanitize HTML (see [#124](https://github.com/remarkablemark/html-react-parser/issues/124), [#125](https://github.com/remarkablemark/html-react-parser/issues/125), and [#141](https://github.com/remarkablemark/html-react-parser/issues/141)).
|
|
519
535
|
|
|
520
536
|
### Are `<script>` tags parsed?
|
|
521
537
|
|
|
522
|
-
Although `<script>` tags and their contents are rendered on the server-side, they're not evaluated on the client-side
|
|
538
|
+
Although `<script>` tags and their contents are rendered on the server-side, they're not evaluated on the client-side (see [#98](https://github.com/remarkablemark/html-react-parser/issues/98)).
|
|
523
539
|
|
|
524
540
|
### Attributes aren't getting called
|
|
525
541
|
|
|
526
|
-
The reason why your HTML attributes aren't getting called is because [inline event handlers](https://developer.mozilla.org/docs/Web/Guide/Events/Event_handlers) (e.g., `onclick`) are parsed as a _string_ rather than a _function_
|
|
542
|
+
The reason why your HTML attributes aren't getting called is because [inline event handlers](https://developer.mozilla.org/docs/Web/Guide/Events/Event_handlers) (e.g., `onclick`) are parsed as a _string_ rather than a _function_ (see [#73](https://github.com/remarkablemark/html-react-parser/issues/73)).
|
|
527
543
|
|
|
528
544
|
### Parser throws an error
|
|
529
545
|
|
|
530
|
-
If the parser throws an error, check if your arguments are valid
|
|
546
|
+
If the parser throws an error, check if your arguments are valid (see ["Does invalid HTML get sanitized?"](#does-invalid-html-get-sanitized)).
|
|
531
547
|
|
|
532
548
|
### Is SSR supported?
|
|
533
549
|
|
|
534
|
-
Yes, server-side rendering on Node.js is supported by this library
|
|
550
|
+
Yes, server-side rendering on Node.js is supported by this library:
|
|
535
551
|
|
|
536
552
|
### Elements aren't nested correctly
|
|
537
553
|
|
|
@@ -564,15 +580,15 @@ parse('<CustomElement>', options); // React.createElement('CustomElement')
|
|
|
564
580
|
> Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
|
|
565
581
|
> ```
|
|
566
582
|
|
|
567
|
-
See [#62](https://github.com/remarkablemark/html-react-parser/issues/62)
|
|
583
|
+
See [#62](https://github.com/remarkablemark/html-react-parser/issues/62).
|
|
568
584
|
|
|
569
585
|
### TS Error: Property 'attribs' does not exist on type 'DOMNode'
|
|
570
586
|
|
|
571
|
-
The TypeScript error occurs because `DOMNode` needs to be an instance of domhandler's `Element
|
|
587
|
+
The TypeScript error occurs because `DOMNode` needs to be an instance of domhandler's `Element` (see [migration](#migration) or [#199](https://github.com/remarkablemark/html-react-parser/issues/199)).
|
|
572
588
|
|
|
573
589
|
### Can I enable `trim` for certain elements?
|
|
574
590
|
|
|
575
|
-
Yes, you can enable or disable [`trim`](#trim) for certain elements using the [`replace`](#replace) option
|
|
591
|
+
Yes, you can enable or disable [`trim`](#trim) for certain elements using the [`replace`](#replace) option (see [#205](https://github.com/remarkablemark/html-react-parser/issues/205)).
|
|
576
592
|
|
|
577
593
|
### Webpack build warnings
|
|
578
594
|
|
|
@@ -607,7 +623,7 @@ node_modules/htmlparser2/lib/index.d.ts:2:23 - error TS1005: ',' expected.
|
|
|
607
623
|
~~~~~~~~~~~~~
|
|
608
624
|
```
|
|
609
625
|
|
|
610
|
-
Then upgrade to the latest version of [typescript](https://www.npmjs.com/package/typescript)
|
|
626
|
+
Then upgrade to the latest version of [typescript](https://www.npmjs.com/package/typescript) (see [#748](https://github.com/remarkablemark/html-react-parser/issues/748)).
|
|
611
627
|
|
|
612
628
|
## Performance
|
|
613
629
|
|
|
@@ -674,13 +674,16 @@
|
|
|
674
674
|
var HEAD = 'head';
|
|
675
675
|
var BODY = 'body';
|
|
676
676
|
var FIRST_TAG_REGEX = /<([a-zA-Z]+[0-9]?)/; // e.g., <h1>
|
|
677
|
+
function getHTMLForInnerHTML(html, trustedTypePolicy) {
|
|
678
|
+
return trustedTypePolicy ? trustedTypePolicy.createHTML(html) : html;
|
|
679
|
+
}
|
|
677
680
|
// falls back to `parseFromString` if `createHTMLDocument` cannot be used
|
|
678
681
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
679
682
|
/* v8 ignore start */
|
|
680
|
-
var parseFromDocument = function (html, tagName) {
|
|
683
|
+
var parseFromDocument = function (html, tagName, trustedTypePolicy) {
|
|
681
684
|
throw new Error('This browser does not support `document.implementation.createHTMLDocument`');
|
|
682
685
|
};
|
|
683
|
-
var parseFromString = function (html, tagName) {
|
|
686
|
+
var parseFromString = function (html, tagName, trustedTypePolicy) {
|
|
684
687
|
throw new Error('This browser does not support `DOMParser.prototype.parseFromString`');
|
|
685
688
|
};
|
|
686
689
|
var DOMParser = typeof window === 'object' && window.DOMParser;
|
|
@@ -699,7 +702,7 @@
|
|
|
699
702
|
* @param tagName - The element to render the HTML (with 'body' as fallback).
|
|
700
703
|
* @returns - Document.
|
|
701
704
|
*/
|
|
702
|
-
parseFromString = function (html, tagName) {
|
|
705
|
+
parseFromString = function (html, tagName, trustedTypePolicy) {
|
|
703
706
|
if (tagName) {
|
|
704
707
|
html = "<".concat(tagName, ">").concat(html, "</").concat(tagName, ">");
|
|
705
708
|
}
|
|
@@ -722,15 +725,15 @@
|
|
|
722
725
|
* @param tagName - The element to render the HTML (with 'body' as fallback).
|
|
723
726
|
* @returns - Document
|
|
724
727
|
*/
|
|
725
|
-
parseFromDocument = function (html, tagName) {
|
|
728
|
+
parseFromDocument = function (html, tagName, trustedTypePolicy) {
|
|
726
729
|
if (tagName) {
|
|
727
730
|
var element = htmlDocument_1.documentElement.querySelector(tagName);
|
|
728
731
|
if (element) {
|
|
729
|
-
element.innerHTML = html;
|
|
732
|
+
element.innerHTML = getHTMLForInnerHTML(html, trustedTypePolicy);
|
|
730
733
|
}
|
|
731
734
|
return htmlDocument_1;
|
|
732
735
|
}
|
|
733
|
-
htmlDocument_1.documentElement.innerHTML = html;
|
|
736
|
+
htmlDocument_1.documentElement.innerHTML = getHTMLForInnerHTML(html, trustedTypePolicy);
|
|
734
737
|
return htmlDocument_1;
|
|
735
738
|
};
|
|
736
739
|
}
|
|
@@ -749,8 +752,8 @@
|
|
|
749
752
|
* @param html - HTML string.
|
|
750
753
|
* @returns - Nodes.
|
|
751
754
|
*/
|
|
752
|
-
parseFromTemplate = function (html) {
|
|
753
|
-
template.innerHTML = html;
|
|
755
|
+
parseFromTemplate = function (html, trustedTypePolicy) {
|
|
756
|
+
template.innerHTML = getHTMLForInnerHTML(html, trustedTypePolicy);
|
|
754
757
|
return template.content.childNodes;
|
|
755
758
|
};
|
|
756
759
|
}
|
|
@@ -760,9 +763,10 @@
|
|
|
760
763
|
* Parses HTML string to DOM nodes.
|
|
761
764
|
*
|
|
762
765
|
* @param html - HTML markup.
|
|
766
|
+
* @param trustedTypePolicy - Trusted Types policy.
|
|
763
767
|
* @returns - DOM nodes.
|
|
764
768
|
*/
|
|
765
|
-
function domparser(html) {
|
|
769
|
+
function domparser(html, trustedTypePolicy) {
|
|
766
770
|
var _a, _b, _c, _d, _e, _f;
|
|
767
771
|
// Escape special characters before parsing
|
|
768
772
|
html = escapeSpecialCharacters(html);
|
|
@@ -785,7 +789,7 @@
|
|
|
785
789
|
}
|
|
786
790
|
case HEAD:
|
|
787
791
|
case BODY: {
|
|
788
|
-
var elements = parseFromDocument(html).querySelectorAll(firstTagName);
|
|
792
|
+
var elements = parseFromDocument(html, undefined, trustedTypePolicy).querySelectorAll(firstTagName);
|
|
789
793
|
// if there's a sibling element, then return both elements
|
|
790
794
|
/* v8 ignore next */
|
|
791
795
|
if (hasOpenTag(html, BODY) && hasOpenTag(html, HEAD)) {
|
|
@@ -798,9 +802,9 @@
|
|
|
798
802
|
default: {
|
|
799
803
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
800
804
|
if (parseFromTemplate) {
|
|
801
|
-
return parseFromTemplate(html);
|
|
805
|
+
return parseFromTemplate(html, trustedTypePolicy);
|
|
802
806
|
}
|
|
803
|
-
var element = parseFromDocument(html, BODY).querySelector(BODY);
|
|
807
|
+
var element = parseFromDocument(html, BODY, trustedTypePolicy).querySelector(BODY);
|
|
804
808
|
return (_f = element === null || element === void 0 ? void 0 : element.childNodes) !== null && _f !== void 0 ? _f : createNodeList();
|
|
805
809
|
}
|
|
806
810
|
/* v8 ignore stop */
|
|
@@ -812,9 +816,10 @@
|
|
|
812
816
|
* Parses HTML string to DOM nodes in browser.
|
|
813
817
|
*
|
|
814
818
|
* @param html - HTML markup.
|
|
819
|
+
* @param options - Parser options.
|
|
815
820
|
* @returns - DOM elements.
|
|
816
821
|
*/
|
|
817
|
-
function HTMLDOMParser(html) {
|
|
822
|
+
function HTMLDOMParser(html, options) {
|
|
818
823
|
if (typeof html !== 'string') {
|
|
819
824
|
throw new TypeError('First argument must be a string');
|
|
820
825
|
}
|
|
@@ -824,7 +829,7 @@
|
|
|
824
829
|
// match directive
|
|
825
830
|
var match = DIRECTIVE_REGEX.exec(html);
|
|
826
831
|
var directive = match ? match[1] : undefined;
|
|
827
|
-
return formatDOM(domparser(html), null, directive);
|
|
832
|
+
return formatDOM(domparser(html, options === null || options === void 0 ? void 0 : options.trustedTypePolicy), null, directive);
|
|
828
833
|
}
|
|
829
834
|
|
|
830
835
|
htmlToDom.default = HTMLDOMParser;
|
|
@@ -2285,14 +2290,14 @@
|
|
|
2285
2290
|
function requireUtilities () {
|
|
2286
2291
|
if (hasRequiredUtilities) return utilities$1;
|
|
2287
2292
|
hasRequiredUtilities = 1;
|
|
2288
|
-
(function (exports
|
|
2293
|
+
(function (exports) {
|
|
2289
2294
|
var __importDefault = (utilities$1 && utilities$1.__importDefault) || function (mod) {
|
|
2290
2295
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
2291
2296
|
};
|
|
2292
|
-
Object.defineProperty(exports
|
|
2293
|
-
exports
|
|
2294
|
-
exports
|
|
2295
|
-
exports
|
|
2297
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2298
|
+
exports.returnFirstArg = exports.canTextBeChildOfNode = exports.ELEMENTS_WITH_NO_TEXT_CHILDREN = exports.PRESERVE_CUSTOM_ATTRIBUTES = void 0;
|
|
2299
|
+
exports.isCustomComponent = isCustomComponent;
|
|
2300
|
+
exports.setStyleProp = setStyleProp;
|
|
2296
2301
|
const react_1 = require$$0;
|
|
2297
2302
|
const style_to_js_1 = __importDefault(requireCjs());
|
|
2298
2303
|
const RESERVED_SVG_MATHML_ELEMENTS = new Set([
|
|
@@ -2355,11 +2360,11 @@
|
|
|
2355
2360
|
/**
|
|
2356
2361
|
* @see https://reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html
|
|
2357
2362
|
*/
|
|
2358
|
-
exports
|
|
2363
|
+
exports.PRESERVE_CUSTOM_ATTRIBUTES = Number(react_1.version.split('.')[0]) >= 16;
|
|
2359
2364
|
/**
|
|
2360
2365
|
* @see https://github.com/facebook/react/blob/cae635054e17a6f107a39d328649137b83f25972/packages/react-dom/src/client/validateDOMNesting.js#L213
|
|
2361
2366
|
*/
|
|
2362
|
-
exports
|
|
2367
|
+
exports.ELEMENTS_WITH_NO_TEXT_CHILDREN = new Set([
|
|
2363
2368
|
'tr',
|
|
2364
2369
|
'tbody',
|
|
2365
2370
|
'thead',
|
|
@@ -2376,8 +2381,8 @@
|
|
|
2376
2381
|
* @param node - Element node.
|
|
2377
2382
|
* @returns - Whether the node can contain text nodes.
|
|
2378
2383
|
*/
|
|
2379
|
-
const canTextBeChildOfNode = (node) => !exports
|
|
2380
|
-
exports
|
|
2384
|
+
const canTextBeChildOfNode = (node) => !exports.ELEMENTS_WITH_NO_TEXT_CHILDREN.has(node.name);
|
|
2385
|
+
exports.canTextBeChildOfNode = canTextBeChildOfNode;
|
|
2381
2386
|
/**
|
|
2382
2387
|
* Returns the first argument as is.
|
|
2383
2388
|
*
|
|
@@ -2385,7 +2390,7 @@
|
|
|
2385
2390
|
* @returns - The input argument `arg`.
|
|
2386
2391
|
*/
|
|
2387
2392
|
const returnFirstArg = (arg) => arg;
|
|
2388
|
-
exports
|
|
2393
|
+
exports.returnFirstArg = returnFirstArg;
|
|
2389
2394
|
|
|
2390
2395
|
} (utilities$1));
|
|
2391
2396
|
return utilities$1;
|
|
@@ -2473,138 +2478,6 @@
|
|
|
2473
2478
|
|
|
2474
2479
|
var domToReact = {};
|
|
2475
2480
|
|
|
2476
|
-
var hasRequiredDomToReact;
|
|
2477
|
-
|
|
2478
|
-
function requireDomToReact () {
|
|
2479
|
-
if (hasRequiredDomToReact) return domToReact;
|
|
2480
|
-
hasRequiredDomToReact = 1;
|
|
2481
|
-
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
|
|
2482
|
-
var __importDefault = (domToReact && domToReact.__importDefault) || function (mod) {
|
|
2483
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
2484
|
-
};
|
|
2485
|
-
Object.defineProperty(domToReact, "__esModule", { value: true });
|
|
2486
|
-
domToReact.default = domToReact$1;
|
|
2487
|
-
const react_1 = require$$0;
|
|
2488
|
-
const attributes_to_props_1 = __importDefault(requireAttributesToProps());
|
|
2489
|
-
const utilities_1 = requireUtilities();
|
|
2490
|
-
const React = {
|
|
2491
|
-
cloneElement: react_1.cloneElement,
|
|
2492
|
-
createElement: react_1.createElement,
|
|
2493
|
-
isValidElement: react_1.isValidElement,
|
|
2494
|
-
};
|
|
2495
|
-
/**
|
|
2496
|
-
* Converts DOM nodes to JSX element(s).
|
|
2497
|
-
*
|
|
2498
|
-
* @param nodes - DOM nodes.
|
|
2499
|
-
* @param options - Options.
|
|
2500
|
-
* @returns - String or JSX element(s).
|
|
2501
|
-
*/
|
|
2502
|
-
function domToReact$1(nodes, options = {}) {
|
|
2503
|
-
var _a, _b, _c, _d, _e;
|
|
2504
|
-
const reactElements = [];
|
|
2505
|
-
const hasReplace = typeof options.replace === 'function';
|
|
2506
|
-
const transform = (_a = options.transform) !== null && _a !== void 0 ? _a : utilities_1.returnFirstArg;
|
|
2507
|
-
const { cloneElement, createElement, isValidElement } = (_b = options.library) !== null && _b !== void 0 ? _b : React;
|
|
2508
|
-
const nodesLength = nodes.length;
|
|
2509
|
-
for (let index = 0; index < nodesLength; index++) {
|
|
2510
|
-
const node = nodes[index];
|
|
2511
|
-
// replace with custom React element (if present)
|
|
2512
|
-
if (hasReplace) {
|
|
2513
|
-
let replaceElement = (_c = options.replace) === null || _c === void 0 ? void 0 : _c.call(options, node, index);
|
|
2514
|
-
if (isValidElement(replaceElement)) {
|
|
2515
|
-
// set "key" prop for sibling elements
|
|
2516
|
-
// https://react.dev/learn/rendering-lists#rules-of-keys
|
|
2517
|
-
if (nodesLength > 1) {
|
|
2518
|
-
replaceElement = cloneElement(replaceElement, {
|
|
2519
|
-
key: (_d = replaceElement.key) !== null && _d !== void 0 ? _d : index,
|
|
2520
|
-
});
|
|
2521
|
-
}
|
|
2522
|
-
reactElements.push(transform(replaceElement, node, index));
|
|
2523
|
-
continue;
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
if (node.type === 'text') {
|
|
2527
|
-
const isWhitespace = !node.data.trim().length;
|
|
2528
|
-
// We have a whitespace node that can't be nested in its parent
|
|
2529
|
-
// so skip it
|
|
2530
|
-
if (isWhitespace &&
|
|
2531
|
-
node.parent &&
|
|
2532
|
-
!(0, utilities_1.canTextBeChildOfNode)(node.parent)) {
|
|
2533
|
-
continue;
|
|
2534
|
-
}
|
|
2535
|
-
// Trim is enabled and we have a whitespace node
|
|
2536
|
-
// so skip it
|
|
2537
|
-
if (options.trim && isWhitespace) {
|
|
2538
|
-
continue;
|
|
2539
|
-
}
|
|
2540
|
-
// We have a text node that's not whitespace and it can be nested
|
|
2541
|
-
// in its parent so add it to the results
|
|
2542
|
-
reactElements.push(transform(node.data, node, index));
|
|
2543
|
-
continue;
|
|
2544
|
-
}
|
|
2545
|
-
const element = node;
|
|
2546
|
-
let props = {};
|
|
2547
|
-
if (skipAttributesToProps(element)) {
|
|
2548
|
-
(0, utilities_1.setStyleProp)(element.attribs.style, element.attribs);
|
|
2549
|
-
props = element.attribs;
|
|
2550
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
2551
|
-
}
|
|
2552
|
-
else if (element.attribs) {
|
|
2553
|
-
props = (0, attributes_to_props_1.default)(element.attribs, element.name);
|
|
2554
|
-
}
|
|
2555
|
-
let children;
|
|
2556
|
-
switch (node.type) {
|
|
2557
|
-
case 'script':
|
|
2558
|
-
case 'style':
|
|
2559
|
-
// prevent text in <script> or <style> from being escaped
|
|
2560
|
-
// https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html
|
|
2561
|
-
if (node.children[0]) {
|
|
2562
|
-
props.dangerouslySetInnerHTML = {
|
|
2563
|
-
__html: node.children[0].data,
|
|
2564
|
-
};
|
|
2565
|
-
}
|
|
2566
|
-
break;
|
|
2567
|
-
case 'tag':
|
|
2568
|
-
// setting textarea value in children is an antipattern in React
|
|
2569
|
-
// https://react.dev/reference/react-dom/components/textarea#caveats
|
|
2570
|
-
if (node.name === 'textarea' && node.children[0]) {
|
|
2571
|
-
props.defaultValue = node.children[0].data;
|
|
2572
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
2573
|
-
}
|
|
2574
|
-
else if ((_e = node.children) === null || _e === void 0 ? void 0 : _e.length) {
|
|
2575
|
-
// continue recursion of creating React elements (if applicable)
|
|
2576
|
-
children = domToReact$1(node.children, options);
|
|
2577
|
-
}
|
|
2578
|
-
break;
|
|
2579
|
-
// skip all other cases (e.g., comment)
|
|
2580
|
-
default:
|
|
2581
|
-
continue;
|
|
2582
|
-
}
|
|
2583
|
-
// set "key" prop for sibling elements
|
|
2584
|
-
// https://react.dev/learn/rendering-lists#rules-of-keys
|
|
2585
|
-
if (nodesLength > 1) {
|
|
2586
|
-
props.key = index;
|
|
2587
|
-
}
|
|
2588
|
-
reactElements.push(transform(createElement(node.name, props, children), node, index));
|
|
2589
|
-
}
|
|
2590
|
-
return reactElements.length === 1 ? reactElements[0] : reactElements;
|
|
2591
|
-
}
|
|
2592
|
-
/**
|
|
2593
|
-
* Determines whether DOM element attributes should be transformed to props.
|
|
2594
|
-
* Web Components should not have their attributes transformed except for `style`.
|
|
2595
|
-
*
|
|
2596
|
-
* @param node - Element node.
|
|
2597
|
-
* @returns - Whether the node attributes should be converted to props.
|
|
2598
|
-
*/
|
|
2599
|
-
function skipAttributesToProps(node) {
|
|
2600
|
-
return (utilities_1.PRESERVE_CUSTOM_ATTRIBUTES &&
|
|
2601
|
-
node.type === 'tag' &&
|
|
2602
|
-
(0, utilities_1.isCustomComponent)(node.name, node.attribs));
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
|
-
return domToReact;
|
|
2606
|
-
}
|
|
2607
|
-
|
|
2608
2481
|
/** Types of elements found in htmlparser2's DOM */
|
|
2609
2482
|
var ElementType;
|
|
2610
2483
|
(function (ElementType) {
|
|
@@ -3202,29 +3075,173 @@
|
|
|
3202
3075
|
|
|
3203
3076
|
var require$$3 = /*@__PURE__*/getAugmentedNamespace(dist);
|
|
3204
3077
|
|
|
3078
|
+
var hasRequiredDomToReact;
|
|
3079
|
+
|
|
3080
|
+
function requireDomToReact () {
|
|
3081
|
+
if (hasRequiredDomToReact) return domToReact;
|
|
3082
|
+
hasRequiredDomToReact = 1;
|
|
3083
|
+
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
|
|
3084
|
+
var __importDefault = (domToReact && domToReact.__importDefault) || function (mod) {
|
|
3085
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
3086
|
+
};
|
|
3087
|
+
Object.defineProperty(domToReact, "__esModule", { value: true });
|
|
3088
|
+
domToReact.default = domToReact$1;
|
|
3089
|
+
const domhandler_1 = require$$3;
|
|
3090
|
+
const react_1 = require$$0;
|
|
3091
|
+
const attributes_to_props_1 = __importDefault(requireAttributesToProps());
|
|
3092
|
+
const utilities_1 = requireUtilities();
|
|
3093
|
+
const React = {
|
|
3094
|
+
cloneElement: react_1.cloneElement,
|
|
3095
|
+
createElement: react_1.createElement,
|
|
3096
|
+
isValidElement: react_1.isValidElement,
|
|
3097
|
+
};
|
|
3098
|
+
/**
|
|
3099
|
+
* Converts DOM nodes to JSX element(s).
|
|
3100
|
+
*
|
|
3101
|
+
* @param nodes - DOM nodes.
|
|
3102
|
+
* @param options - Options.
|
|
3103
|
+
* @returns - String or JSX element(s).
|
|
3104
|
+
*/
|
|
3105
|
+
function domToReact$1(nodes, options = {}) {
|
|
3106
|
+
var _a, _b, _c, _d, _e;
|
|
3107
|
+
const reactElements = [];
|
|
3108
|
+
const hasReplace = typeof options.replace === 'function';
|
|
3109
|
+
const transform = (_a = options.transform) !== null && _a !== void 0 ? _a : utilities_1.returnFirstArg;
|
|
3110
|
+
const { cloneElement, createElement, isValidElement } = (_b = options.library) !== null && _b !== void 0 ? _b : React;
|
|
3111
|
+
const nodesLength = nodes.length;
|
|
3112
|
+
normalizeDOMNodes(nodes);
|
|
3113
|
+
for (let index = 0; index < nodesLength; index++) {
|
|
3114
|
+
const node = nodes[index];
|
|
3115
|
+
// replace with custom React element (if present)
|
|
3116
|
+
if (hasReplace) {
|
|
3117
|
+
let replaceElement = (_c = options.replace) === null || _c === void 0 ? void 0 : _c.call(options, node, index);
|
|
3118
|
+
if (isValidElement(replaceElement)) {
|
|
3119
|
+
// set "key" prop for sibling elements
|
|
3120
|
+
// https://react.dev/learn/rendering-lists#rules-of-keys
|
|
3121
|
+
if (nodesLength > 1) {
|
|
3122
|
+
replaceElement = cloneElement(replaceElement, {
|
|
3123
|
+
key: (_d = replaceElement.key) !== null && _d !== void 0 ? _d : index,
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
reactElements.push(transform(replaceElement, node, index));
|
|
3127
|
+
continue;
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
if (node.type === 'text') {
|
|
3131
|
+
const isWhitespace = !node.data.trim().length;
|
|
3132
|
+
// We have a whitespace node that can't be nested in its parent
|
|
3133
|
+
// so skip it
|
|
3134
|
+
if (isWhitespace &&
|
|
3135
|
+
node.parent &&
|
|
3136
|
+
!(0, utilities_1.canTextBeChildOfNode)(node.parent)) {
|
|
3137
|
+
continue;
|
|
3138
|
+
}
|
|
3139
|
+
// Trim is enabled and we have a whitespace node
|
|
3140
|
+
// so skip it
|
|
3141
|
+
if (options.trim && isWhitespace) {
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
// We have a text node that's not whitespace and it can be nested
|
|
3145
|
+
// in its parent so add it to the results
|
|
3146
|
+
reactElements.push(transform(node.data, node, index));
|
|
3147
|
+
continue;
|
|
3148
|
+
}
|
|
3149
|
+
const element = node;
|
|
3150
|
+
let props = {};
|
|
3151
|
+
if (skipAttributesToProps(element)) {
|
|
3152
|
+
(0, utilities_1.setStyleProp)(element.attribs.style, element.attribs);
|
|
3153
|
+
props = element.attribs;
|
|
3154
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3155
|
+
}
|
|
3156
|
+
else if (element.attribs) {
|
|
3157
|
+
props = (0, attributes_to_props_1.default)(element.attribs, element.name);
|
|
3158
|
+
}
|
|
3159
|
+
let children;
|
|
3160
|
+
switch (node.type) {
|
|
3161
|
+
case 'script':
|
|
3162
|
+
case 'style':
|
|
3163
|
+
// prevent text in <script> or <style> from being escaped
|
|
3164
|
+
// https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html
|
|
3165
|
+
if (node.children[0]) {
|
|
3166
|
+
props.dangerouslySetInnerHTML = {
|
|
3167
|
+
__html: node.children[0].data,
|
|
3168
|
+
};
|
|
3169
|
+
}
|
|
3170
|
+
break;
|
|
3171
|
+
case 'tag':
|
|
3172
|
+
// setting textarea value in children is an antipattern in React
|
|
3173
|
+
// https://react.dev/reference/react-dom/components/textarea#caveats
|
|
3174
|
+
if (node.name === 'textarea' && node.children[0]) {
|
|
3175
|
+
props.defaultValue = node.children[0].data;
|
|
3176
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
3177
|
+
}
|
|
3178
|
+
else if ((_e = node.children) === null || _e === void 0 ? void 0 : _e.length) {
|
|
3179
|
+
// continue recursion of creating React elements (if applicable)
|
|
3180
|
+
children = domToReact$1(node.children, options);
|
|
3181
|
+
}
|
|
3182
|
+
break;
|
|
3183
|
+
// skip all other cases (e.g., comment)
|
|
3184
|
+
default:
|
|
3185
|
+
continue;
|
|
3186
|
+
}
|
|
3187
|
+
// set "key" prop for sibling elements
|
|
3188
|
+
// https://react.dev/learn/rendering-lists#rules-of-keys
|
|
3189
|
+
if (nodesLength > 1) {
|
|
3190
|
+
props.key = index;
|
|
3191
|
+
}
|
|
3192
|
+
reactElements.push(transform(createElement(node.name, props, children), node, index));
|
|
3193
|
+
}
|
|
3194
|
+
return reactElements.length === 1 ? reactElements[0] : reactElements;
|
|
3195
|
+
}
|
|
3196
|
+
function normalizeDOMNodes(nodes) {
|
|
3197
|
+
for (const node of nodes) {
|
|
3198
|
+
if (node.type === 'tag' ||
|
|
3199
|
+
node.type === 'script' ||
|
|
3200
|
+
node.type === 'style') {
|
|
3201
|
+
Object.setPrototypeOf(node, domhandler_1.Element.prototype);
|
|
3202
|
+
normalizeDOMNodes(node.children);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
/**
|
|
3207
|
+
* Determines whether DOM element attributes should be transformed to props.
|
|
3208
|
+
* Web Components should not have their attributes transformed except for `style`.
|
|
3209
|
+
*
|
|
3210
|
+
* @param node - Element node.
|
|
3211
|
+
* @returns - Whether the node attributes should be converted to props.
|
|
3212
|
+
*/
|
|
3213
|
+
function skipAttributesToProps(node) {
|
|
3214
|
+
return (utilities_1.PRESERVE_CUSTOM_ATTRIBUTES &&
|
|
3215
|
+
node.type === 'tag' &&
|
|
3216
|
+
(0, utilities_1.isCustomComponent)(node.name, node.attribs));
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
return domToReact;
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3205
3222
|
var hasRequiredLib;
|
|
3206
3223
|
|
|
3207
3224
|
function requireLib () {
|
|
3208
3225
|
if (hasRequiredLib) return lib$1;
|
|
3209
3226
|
hasRequiredLib = 1;
|
|
3210
|
-
(function (exports
|
|
3227
|
+
(function (exports) {
|
|
3211
3228
|
var __importDefault = (lib$1 && lib$1.__importDefault) || function (mod) {
|
|
3212
3229
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
3213
3230
|
};
|
|
3214
|
-
Object.defineProperty(exports
|
|
3215
|
-
exports
|
|
3216
|
-
exports
|
|
3231
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3232
|
+
exports.htmlToDOM = exports.domToReact = exports.attributesToProps = exports.Text = exports.ProcessingInstruction = exports.Element = exports.Comment = void 0;
|
|
3233
|
+
exports.default = HTMLReactParser;
|
|
3217
3234
|
const html_dom_parser_1 = __importDefault(requireHtmlToDom());
|
|
3218
|
-
exports
|
|
3235
|
+
exports.htmlToDOM = html_dom_parser_1.default;
|
|
3219
3236
|
const attributes_to_props_1 = __importDefault(requireAttributesToProps());
|
|
3220
|
-
exports
|
|
3237
|
+
exports.attributesToProps = attributes_to_props_1.default;
|
|
3221
3238
|
const dom_to_react_1 = __importDefault(requireDomToReact());
|
|
3222
|
-
exports
|
|
3239
|
+
exports.domToReact = dom_to_react_1.default;
|
|
3223
3240
|
var domhandler_1 = require$$3;
|
|
3224
|
-
Object.defineProperty(exports
|
|
3225
|
-
Object.defineProperty(exports
|
|
3226
|
-
Object.defineProperty(exports
|
|
3227
|
-
Object.defineProperty(exports
|
|
3241
|
+
Object.defineProperty(exports, "Comment", { enumerable: true, get: function () { return domhandler_1.Comment; } });
|
|
3242
|
+
Object.defineProperty(exports, "Element", { enumerable: true, get: function () { return domhandler_1.Element; } });
|
|
3243
|
+
Object.defineProperty(exports, "ProcessingInstruction", { enumerable: true, get: function () { return domhandler_1.ProcessingInstruction; } });
|
|
3244
|
+
Object.defineProperty(exports, "Text", { enumerable: true, get: function () { return domhandler_1.Text; } });
|
|
3228
3245
|
const domParserOptions = { lowerCaseAttributeNames: false };
|
|
3229
3246
|
/**
|
|
3230
3247
|
* Converts HTML string to React elements.
|
|
@@ -3241,7 +3258,8 @@
|
|
|
3241
3258
|
if (!html) {
|
|
3242
3259
|
return [];
|
|
3243
3260
|
}
|
|
3244
|
-
|
|
3261
|
+
const htmlToDOMOptions = Object.assign(Object.assign({}, ((_a = options === null || options === void 0 ? void 0 : options.htmlparser2) !== null && _a !== void 0 ? _a : domParserOptions)), { trustedTypePolicy: options === null || options === void 0 ? void 0 : options.trustedTypePolicy });
|
|
3262
|
+
return (0, dom_to_react_1.default)((0, html_dom_parser_1.default)(html, htmlToDOMOptions), options);
|
|
3245
3263
|
}
|
|
3246
3264
|
|
|
3247
3265
|
} (lib$1));
|