html-react-parser 1.4.0 → 1.4.4
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 +10 -16
- package/dist/html-react-parser.js +102 -13
- 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/attributes-to-props.js +20 -2
- package/lib/dom-to-react.js +18 -9
- package/lib/utilities.js +27 -1
- package/package.json +20 -20
- package/CHANGELOG.md +0 -554
package/README.md
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/html-react-parser)
|
|
6
6
|
[](https://github.com/remarkablemark/html-react-parser/actions?query=workflow%3Abuild)
|
|
7
7
|
[](https://codecov.io/gh/remarkablemark/html-react-parser)
|
|
8
|
-
[](https://david-dm.org/remarkablemark/html-react-parser)
|
|
9
8
|
[](https://www.npmjs.com/package/html-react-parser)
|
|
10
9
|
[](https://discord.gg/njExwXdrRJ)
|
|
11
10
|
|
|
@@ -26,7 +25,7 @@ const parse = require('html-react-parser');
|
|
|
26
25
|
parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
[
|
|
28
|
+
[Replit](https://replit.com/@remarkablemark/html-react-parser) | [JSFiddle](https://jsfiddle.net/remarkablemark/7v86d800/) | [CodeSandbox](https://codesandbox.io/s/940pov1l4w) | [TypeScript](https://codesandbox.io/s/html-react-parser-z0kp6) | [Examples](https://github.com/remarkablemark/html-react-parser/tree/master/examples)
|
|
30
29
|
|
|
31
30
|
<details>
|
|
32
31
|
<summary>Table of Contents</summary>
|
|
@@ -51,7 +50,6 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
|
|
|
51
50
|
- [Parser throws an error](#parser-throws-an-error)
|
|
52
51
|
- [Is SSR supported?](#is-ssr-supported)
|
|
53
52
|
- [Elements aren't nested correctly](#elements-arent-nested-correctly)
|
|
54
|
-
- [Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table](#warning-validatedomnesting-whitespace-text-nodes-cannot-appear-as-a-child-of-table)
|
|
55
53
|
- [Don't change case of tags](#dont-change-case-of-tags)
|
|
56
54
|
- [TS Error: Property 'attribs' does not exist on type 'DOMNode'](#ts-error-property-attribs-does-not-exist-on-type-domnode)
|
|
57
55
|
- [Can I enable `trim` for certain elements?](#can-i-enable-trim-for-certain-elements)
|
|
@@ -203,7 +201,7 @@ If you're having issues take a look at our [Create React App example](./examples
|
|
|
203
201
|
|
|
204
202
|
#### replace element and children
|
|
205
203
|
|
|
206
|
-
Replace the element and its children (see [demo](https://
|
|
204
|
+
Replace the element and its children (see [demo](https://replit.com/@remarkablemark/html-react-parser-replace-example)):
|
|
207
205
|
|
|
208
206
|
```jsx
|
|
209
207
|
import parse, { domToReact } from 'html-react-parser';
|
|
@@ -284,7 +282,7 @@ HTML output:
|
|
|
284
282
|
|
|
285
283
|
#### replace and remove element
|
|
286
284
|
|
|
287
|
-
[Exclude](https://
|
|
285
|
+
[Exclude](https://replit.com/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:
|
|
288
286
|
|
|
289
287
|
```jsx
|
|
290
288
|
parse('<p><br id="remove"></p>', {
|
|
@@ -352,16 +350,16 @@ By default, whitespace is preserved:
|
|
|
352
350
|
parse('<br>\n'); // [React.createElement('br'), '\n']
|
|
353
351
|
```
|
|
354
352
|
|
|
355
|
-
|
|
353
|
+
But certain elements like `<table>` will strip out invalid whitespace:
|
|
356
354
|
|
|
357
355
|
```js
|
|
358
|
-
parse('<
|
|
356
|
+
parse('<table>\n</table>'); // React.createElement('table')
|
|
359
357
|
```
|
|
360
358
|
|
|
361
|
-
|
|
359
|
+
To remove whitespace, enable the `trim` option:
|
|
362
360
|
|
|
363
|
-
```
|
|
364
|
-
|
|
361
|
+
```js
|
|
362
|
+
parse('<br>\n', { trim: true }); // React.createElement('br')
|
|
365
363
|
```
|
|
366
364
|
|
|
367
365
|
However, intentional whitespace may be stripped out:
|
|
@@ -416,7 +414,7 @@ If the parser throws an erorr, check if your arguments are valid. See ["Does inv
|
|
|
416
414
|
|
|
417
415
|
### Is SSR supported?
|
|
418
416
|
|
|
419
|
-
Yes, server-side rendering on Node.js is supported by this library. See [demo](https://
|
|
417
|
+
Yes, server-side rendering on Node.js is supported by this library. See [demo](https://replit.com/@remarkablemark/html-react-parser-SSR).
|
|
420
418
|
|
|
421
419
|
### Elements aren't nested correctly
|
|
422
420
|
|
|
@@ -428,10 +426,6 @@ parse('<div /><div />'); // returns single element instead of array of elements
|
|
|
428
426
|
|
|
429
427
|
See [#158](https://github.com/remarkablemark/html-react-parser/issues/158).
|
|
430
428
|
|
|
431
|
-
### Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table
|
|
432
|
-
|
|
433
|
-
Enable the [trim](#trim) option. See [#155](https://github.com/remarkablemark/html-react-parser/issues/155).
|
|
434
|
-
|
|
435
429
|
### Don't change case of tags
|
|
436
430
|
|
|
437
431
|
Tags are lowercased by default. To prevent that from happening, pass the [htmlparser2 option](#htmlparser2):
|
|
@@ -451,7 +445,7 @@ parse('<CustomElement>', options); // React.createElement('CustomElement')
|
|
|
451
445
|
> Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
|
|
452
446
|
> ```
|
|
453
447
|
|
|
454
|
-
See [#62](https://github.com/remarkablemark/html-react-parser/issues/62) and [example](https://
|
|
448
|
+
See [#62](https://github.com/remarkablemark/html-react-parser/issues/62) and [example](https://replit.com/@remarkablemark/html-react-parser-62).
|
|
455
449
|
|
|
456
450
|
### TS Error: Property 'attribs' does not exist on type 'DOMNode'
|
|
457
451
|
|
|
@@ -1279,11 +1279,37 @@
|
|
|
1279
1279
|
*/
|
|
1280
1280
|
var PRESERVE_CUSTOM_ATTRIBUTES = React$1.version.split('.')[0] >= 16;
|
|
1281
1281
|
|
|
1282
|
+
// Taken from
|
|
1283
|
+
// https://github.com/facebook/react/blob/cae635054e17a6f107a39d328649137b83f25972/packages/react-dom/src/client/validateDOMNesting.js#L213
|
|
1284
|
+
var elementsWithNoTextChildren = new Set([
|
|
1285
|
+
'tr',
|
|
1286
|
+
'tbody',
|
|
1287
|
+
'thead',
|
|
1288
|
+
'tfoot',
|
|
1289
|
+
'colgroup',
|
|
1290
|
+
'table',
|
|
1291
|
+
'head',
|
|
1292
|
+
'html',
|
|
1293
|
+
'frameset'
|
|
1294
|
+
]);
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* Checks if the given node can contain text nodes
|
|
1298
|
+
*
|
|
1299
|
+
* @param {DomElement} node
|
|
1300
|
+
* @returns {boolean}
|
|
1301
|
+
*/
|
|
1302
|
+
function canTextBeChildOfNode$1(node) {
|
|
1303
|
+
return !elementsWithNoTextChildren.has(node.name);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1282
1306
|
var utilities$3 = {
|
|
1283
1307
|
PRESERVE_CUSTOM_ATTRIBUTES: PRESERVE_CUSTOM_ATTRIBUTES,
|
|
1284
1308
|
invertObject: invertObject,
|
|
1285
1309
|
isCustomComponent: isCustomComponent,
|
|
1286
|
-
setStyleProp: setStyleProp$1
|
|
1310
|
+
setStyleProp: setStyleProp$1,
|
|
1311
|
+
canTextBeChildOfNode: canTextBeChildOfNode$1,
|
|
1312
|
+
elementsWithNoTextChildren: elementsWithNoTextChildren
|
|
1287
1313
|
};
|
|
1288
1314
|
|
|
1289
1315
|
var reactProperty = lib$1;
|
|
@@ -1316,11 +1342,19 @@
|
|
|
1316
1342
|
|
|
1317
1343
|
// convert HTML/SVG attribute to React prop
|
|
1318
1344
|
attributeNameLowerCased = attributeName.toLowerCase();
|
|
1319
|
-
propName =
|
|
1345
|
+
propName = getPropName(attributeNameLowerCased);
|
|
1320
1346
|
|
|
1321
1347
|
if (propName) {
|
|
1322
|
-
props[propName] = attributeValue;
|
|
1323
1348
|
propertyInfo = reactProperty.getPropertyInfo(propName);
|
|
1349
|
+
|
|
1350
|
+
// convert attribute to uncontrolled component prop (e.g., `value` to `defaultValue`)
|
|
1351
|
+
// https://reactjs.org/docs/uncontrolled-components.html
|
|
1352
|
+
if (propName === 'checked' || propName === 'value') {
|
|
1353
|
+
propName = getPropName('default' + attributeNameLowerCased);
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
props[propName] = attributeValue;
|
|
1357
|
+
|
|
1324
1358
|
switch (propertyInfo && propertyInfo.type) {
|
|
1325
1359
|
case reactProperty.BOOLEAN:
|
|
1326
1360
|
props[propName] = true;
|
|
@@ -1346,11 +1380,22 @@
|
|
|
1346
1380
|
return props;
|
|
1347
1381
|
};
|
|
1348
1382
|
|
|
1383
|
+
/**
|
|
1384
|
+
* Gets prop name from lowercased attribute name.
|
|
1385
|
+
*
|
|
1386
|
+
* @param {string} attributeName - Lowercased attribute name.
|
|
1387
|
+
* @return {string}
|
|
1388
|
+
*/
|
|
1389
|
+
function getPropName(attributeName) {
|
|
1390
|
+
return reactProperty.possibleStandardNames[attributeName];
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1349
1393
|
var React = require$$0__default["default"];
|
|
1350
1394
|
var attributesToProps$1 = attributesToProps$2;
|
|
1351
1395
|
var utilities$1 = utilities$3;
|
|
1352
1396
|
|
|
1353
1397
|
var setStyleProp = utilities$1.setStyleProp;
|
|
1398
|
+
var canTextBeChildOfNode = utilities$1.canTextBeChildOfNode;
|
|
1354
1399
|
|
|
1355
1400
|
/**
|
|
1356
1401
|
* Converts DOM nodes to JSX element(s).
|
|
@@ -1371,11 +1416,11 @@
|
|
|
1371
1416
|
|
|
1372
1417
|
var result = [];
|
|
1373
1418
|
var node;
|
|
1419
|
+
var isWhitespace;
|
|
1374
1420
|
var hasReplace = typeof options.replace === 'function';
|
|
1375
1421
|
var replaceElement;
|
|
1376
1422
|
var props;
|
|
1377
1423
|
var children;
|
|
1378
|
-
var data;
|
|
1379
1424
|
var trim = options.trim;
|
|
1380
1425
|
|
|
1381
1426
|
for (var i = 0, len = nodes.length; i < len; i++) {
|
|
@@ -1399,15 +1444,23 @@
|
|
|
1399
1444
|
}
|
|
1400
1445
|
|
|
1401
1446
|
if (node.type === 'text') {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
} else {
|
|
1409
|
-
result.push(node.data);
|
|
1447
|
+
isWhitespace = !node.data.trim().length;
|
|
1448
|
+
|
|
1449
|
+
if (isWhitespace && node.parent && !canTextBeChildOfNode(node.parent)) {
|
|
1450
|
+
// We have a whitespace node that can't be nested in its parent
|
|
1451
|
+
// so skip it
|
|
1452
|
+
continue;
|
|
1410
1453
|
}
|
|
1454
|
+
|
|
1455
|
+
if (trim && isWhitespace) {
|
|
1456
|
+
// Trim is enabled and we have a whitespace node
|
|
1457
|
+
// so skip it
|
|
1458
|
+
continue;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// We have a text node that's not whitespace and it can be nested
|
|
1462
|
+
// in its parent so add it to the results
|
|
1463
|
+
result.push(node.data);
|
|
1411
1464
|
continue;
|
|
1412
1465
|
}
|
|
1413
1466
|
|
|
@@ -1645,6 +1698,10 @@
|
|
|
1645
1698
|
}
|
|
1646
1699
|
Object.defineProperty(Node.prototype, "nodeType", {
|
|
1647
1700
|
// Read-only aliases
|
|
1701
|
+
/**
|
|
1702
|
+
* [DOM spec](https://dom.spec.whatwg.org/#dom-node-nodetype)-compatible
|
|
1703
|
+
* node {@link type}.
|
|
1704
|
+
*/
|
|
1648
1705
|
get: function () {
|
|
1649
1706
|
var _a;
|
|
1650
1707
|
return (_a = nodeTypes.get(this.type)) !== null && _a !== void 0 ? _a : 1;
|
|
@@ -1654,6 +1711,10 @@
|
|
|
1654
1711
|
});
|
|
1655
1712
|
Object.defineProperty(Node.prototype, "parentNode", {
|
|
1656
1713
|
// Read-write aliases for properties
|
|
1714
|
+
/**
|
|
1715
|
+
* Same as {@link parent}.
|
|
1716
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1717
|
+
*/
|
|
1657
1718
|
get: function () {
|
|
1658
1719
|
return this.parent;
|
|
1659
1720
|
},
|
|
@@ -1664,6 +1725,10 @@
|
|
|
1664
1725
|
configurable: true
|
|
1665
1726
|
});
|
|
1666
1727
|
Object.defineProperty(Node.prototype, "previousSibling", {
|
|
1728
|
+
/**
|
|
1729
|
+
* Same as {@link prev}.
|
|
1730
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1731
|
+
*/
|
|
1667
1732
|
get: function () {
|
|
1668
1733
|
return this.prev;
|
|
1669
1734
|
},
|
|
@@ -1674,6 +1739,10 @@
|
|
|
1674
1739
|
configurable: true
|
|
1675
1740
|
});
|
|
1676
1741
|
Object.defineProperty(Node.prototype, "nextSibling", {
|
|
1742
|
+
/**
|
|
1743
|
+
* Same as {@link next}.
|
|
1744
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1745
|
+
*/
|
|
1677
1746
|
get: function () {
|
|
1678
1747
|
return this.next;
|
|
1679
1748
|
},
|
|
@@ -1711,6 +1780,10 @@
|
|
|
1711
1780
|
return _this;
|
|
1712
1781
|
}
|
|
1713
1782
|
Object.defineProperty(DataNode.prototype, "nodeValue", {
|
|
1783
|
+
/**
|
|
1784
|
+
* Same as {@link data}.
|
|
1785
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1786
|
+
*/
|
|
1714
1787
|
get: function () {
|
|
1715
1788
|
return this.data;
|
|
1716
1789
|
},
|
|
@@ -1774,6 +1847,7 @@
|
|
|
1774
1847
|
}
|
|
1775
1848
|
Object.defineProperty(NodeWithChildren.prototype, "firstChild", {
|
|
1776
1849
|
// Aliases
|
|
1850
|
+
/** First child of the node. */
|
|
1777
1851
|
get: function () {
|
|
1778
1852
|
var _a;
|
|
1779
1853
|
return (_a = this.children[0]) !== null && _a !== void 0 ? _a : null;
|
|
@@ -1782,6 +1856,7 @@
|
|
|
1782
1856
|
configurable: true
|
|
1783
1857
|
});
|
|
1784
1858
|
Object.defineProperty(NodeWithChildren.prototype, "lastChild", {
|
|
1859
|
+
/** Last child of the node. */
|
|
1785
1860
|
get: function () {
|
|
1786
1861
|
return this.children.length > 0
|
|
1787
1862
|
? this.children[this.children.length - 1]
|
|
@@ -1791,6 +1866,10 @@
|
|
|
1791
1866
|
configurable: true
|
|
1792
1867
|
});
|
|
1793
1868
|
Object.defineProperty(NodeWithChildren.prototype, "childNodes", {
|
|
1869
|
+
/**
|
|
1870
|
+
* Same as {@link children}.
|
|
1871
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1872
|
+
*/
|
|
1794
1873
|
get: function () {
|
|
1795
1874
|
return this.children;
|
|
1796
1875
|
},
|
|
@@ -1838,6 +1917,10 @@
|
|
|
1838
1917
|
}
|
|
1839
1918
|
Object.defineProperty(Element.prototype, "tagName", {
|
|
1840
1919
|
// DOM Level 1 aliases
|
|
1920
|
+
/**
|
|
1921
|
+
* Same as {@link name}.
|
|
1922
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1923
|
+
*/
|
|
1841
1924
|
get: function () {
|
|
1842
1925
|
return this.name;
|
|
1843
1926
|
},
|
|
@@ -1941,6 +2024,9 @@
|
|
|
1941
2024
|
var children = recursive ? cloneChildren(node.children) : [];
|
|
1942
2025
|
var clone_1 = new Element$1(node.name, __assign({}, node.attribs), children);
|
|
1943
2026
|
children.forEach(function (child) { return (child.parent = clone_1); });
|
|
2027
|
+
if (node.namespace != null) {
|
|
2028
|
+
clone_1.namespace = node.namespace;
|
|
2029
|
+
}
|
|
1944
2030
|
if (node["x-attribsNamespace"]) {
|
|
1945
2031
|
clone_1["x-attribsNamespace"] = __assign({}, node["x-attribsNamespace"]);
|
|
1946
2032
|
}
|
|
@@ -1974,10 +2060,13 @@
|
|
|
1974
2060
|
result = instruction;
|
|
1975
2061
|
}
|
|
1976
2062
|
else {
|
|
1977
|
-
throw new Error("Not implemented yet: "
|
|
2063
|
+
throw new Error("Not implemented yet: ".concat(node.type));
|
|
1978
2064
|
}
|
|
1979
2065
|
result.startIndex = node.startIndex;
|
|
1980
2066
|
result.endIndex = node.endIndex;
|
|
2067
|
+
if (node.sourceCodeLocation != null) {
|
|
2068
|
+
result.sourceCodeLocation = node.sourceCodeLocation;
|
|
2069
|
+
}
|
|
1981
2070
|
return result;
|
|
1982
2071
|
}
|
|
1983
2072
|
node.cloneNode = cloneNode;
|