html-react-parser 1.4.1 → 1.4.5
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 -15
- package/dist/html-react-parser.js +111 -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 +29 -2
- package/lib/dom-to-react.js +18 -9
- package/lib/utilities.js +27 -1
- package/package.json +17 -17
- package/CHANGELOG.md +0 -561
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ const parse = require('html-react-parser');
|
|
|
25
25
|
parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
[
|
|
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)
|
|
29
29
|
|
|
30
30
|
<details>
|
|
31
31
|
<summary>Table of Contents</summary>
|
|
@@ -50,7 +50,6 @@ parse('<p>Hello, World!</p>'); // React.createElement('p', {}, 'Hello, World!')
|
|
|
50
50
|
- [Parser throws an error](#parser-throws-an-error)
|
|
51
51
|
- [Is SSR supported?](#is-ssr-supported)
|
|
52
52
|
- [Elements aren't nested correctly](#elements-arent-nested-correctly)
|
|
53
|
-
- [Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table](#warning-validatedomnesting-whitespace-text-nodes-cannot-appear-as-a-child-of-table)
|
|
54
53
|
- [Don't change case of tags](#dont-change-case-of-tags)
|
|
55
54
|
- [TS Error: Property 'attribs' does not exist on type 'DOMNode'](#ts-error-property-attribs-does-not-exist-on-type-domnode)
|
|
56
55
|
- [Can I enable `trim` for certain elements?](#can-i-enable-trim-for-certain-elements)
|
|
@@ -202,7 +201,7 @@ If you're having issues take a look at our [Create React App example](./examples
|
|
|
202
201
|
|
|
203
202
|
#### replace element and children
|
|
204
203
|
|
|
205
|
-
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)):
|
|
206
205
|
|
|
207
206
|
```jsx
|
|
208
207
|
import parse, { domToReact } from 'html-react-parser';
|
|
@@ -283,7 +282,7 @@ HTML output:
|
|
|
283
282
|
|
|
284
283
|
#### replace and remove element
|
|
285
284
|
|
|
286
|
-
[Exclude](https://
|
|
285
|
+
[Exclude](https://replit.com/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:
|
|
287
286
|
|
|
288
287
|
```jsx
|
|
289
288
|
parse('<p><br id="remove"></p>', {
|
|
@@ -351,16 +350,16 @@ By default, whitespace is preserved:
|
|
|
351
350
|
parse('<br>\n'); // [React.createElement('br'), '\n']
|
|
352
351
|
```
|
|
353
352
|
|
|
354
|
-
|
|
353
|
+
But certain elements like `<table>` will strip out invalid whitespace:
|
|
355
354
|
|
|
356
355
|
```js
|
|
357
|
-
parse('<
|
|
356
|
+
parse('<table>\n</table>'); // React.createElement('table')
|
|
358
357
|
```
|
|
359
358
|
|
|
360
|
-
|
|
359
|
+
To remove whitespace, enable the `trim` option:
|
|
361
360
|
|
|
362
|
-
```
|
|
363
|
-
|
|
361
|
+
```js
|
|
362
|
+
parse('<br>\n', { trim: true }); // React.createElement('br')
|
|
364
363
|
```
|
|
365
364
|
|
|
366
365
|
However, intentional whitespace may be stripped out:
|
|
@@ -415,7 +414,7 @@ If the parser throws an erorr, check if your arguments are valid. See ["Does inv
|
|
|
415
414
|
|
|
416
415
|
### Is SSR supported?
|
|
417
416
|
|
|
418
|
-
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).
|
|
419
418
|
|
|
420
419
|
### Elements aren't nested correctly
|
|
421
420
|
|
|
@@ -427,10 +426,6 @@ parse('<div /><div />'); // returns single element instead of array of elements
|
|
|
427
426
|
|
|
428
427
|
See [#158](https://github.com/remarkablemark/html-react-parser/issues/158).
|
|
429
428
|
|
|
430
|
-
### Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table
|
|
431
|
-
|
|
432
|
-
Enable the [trim](#trim) option. See [#155](https://github.com/remarkablemark/html-react-parser/issues/155).
|
|
433
|
-
|
|
434
429
|
### Don't change case of tags
|
|
435
430
|
|
|
436
431
|
Tags are lowercased by default. To prevent that from happening, pass the [htmlparser2 option](#htmlparser2):
|
|
@@ -450,7 +445,7 @@ parse('<CustomElement>', options); // React.createElement('CustomElement')
|
|
|
450
445
|
> Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
|
|
451
446
|
> ```
|
|
452
447
|
|
|
453
|
-
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).
|
|
454
449
|
|
|
455
450
|
### TS Error: Property 'attribs' does not exist on type 'DOMNode'
|
|
456
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;
|
|
@@ -1298,12 +1324,18 @@
|
|
|
1298
1324
|
var attributesToProps$2 = function attributesToProps(attributes) {
|
|
1299
1325
|
attributes = attributes || {};
|
|
1300
1326
|
|
|
1327
|
+
var valueOnlyInputs = {
|
|
1328
|
+
reset: true,
|
|
1329
|
+
submit: true
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1301
1332
|
var attributeName;
|
|
1302
1333
|
var attributeNameLowerCased;
|
|
1303
1334
|
var attributeValue;
|
|
1304
1335
|
var propName;
|
|
1305
1336
|
var propertyInfo;
|
|
1306
1337
|
var props = {};
|
|
1338
|
+
var inputIsValueOnly = attributes.type && valueOnlyInputs[attributes.type];
|
|
1307
1339
|
|
|
1308
1340
|
for (attributeName in attributes) {
|
|
1309
1341
|
attributeValue = attributes[attributeName];
|
|
@@ -1316,11 +1348,22 @@
|
|
|
1316
1348
|
|
|
1317
1349
|
// convert HTML/SVG attribute to React prop
|
|
1318
1350
|
attributeNameLowerCased = attributeName.toLowerCase();
|
|
1319
|
-
propName =
|
|
1351
|
+
propName = getPropName(attributeNameLowerCased);
|
|
1320
1352
|
|
|
1321
1353
|
if (propName) {
|
|
1322
|
-
props[propName] = attributeValue;
|
|
1323
1354
|
propertyInfo = reactProperty.getPropertyInfo(propName);
|
|
1355
|
+
|
|
1356
|
+
// convert attribute to uncontrolled component prop (e.g., `value` to `defaultValue`)
|
|
1357
|
+
// https://reactjs.org/docs/uncontrolled-components.html
|
|
1358
|
+
if (
|
|
1359
|
+
(propName === 'checked' || propName === 'value') &&
|
|
1360
|
+
!inputIsValueOnly
|
|
1361
|
+
) {
|
|
1362
|
+
propName = getPropName('default' + attributeNameLowerCased);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
props[propName] = attributeValue;
|
|
1366
|
+
|
|
1324
1367
|
switch (propertyInfo && propertyInfo.type) {
|
|
1325
1368
|
case reactProperty.BOOLEAN:
|
|
1326
1369
|
props[propName] = true;
|
|
@@ -1346,11 +1389,22 @@
|
|
|
1346
1389
|
return props;
|
|
1347
1390
|
};
|
|
1348
1391
|
|
|
1392
|
+
/**
|
|
1393
|
+
* Gets prop name from lowercased attribute name.
|
|
1394
|
+
*
|
|
1395
|
+
* @param {string} attributeName - Lowercased attribute name.
|
|
1396
|
+
* @return {string}
|
|
1397
|
+
*/
|
|
1398
|
+
function getPropName(attributeName) {
|
|
1399
|
+
return reactProperty.possibleStandardNames[attributeName];
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1349
1402
|
var React = require$$0__default["default"];
|
|
1350
1403
|
var attributesToProps$1 = attributesToProps$2;
|
|
1351
1404
|
var utilities$1 = utilities$3;
|
|
1352
1405
|
|
|
1353
1406
|
var setStyleProp = utilities$1.setStyleProp;
|
|
1407
|
+
var canTextBeChildOfNode = utilities$1.canTextBeChildOfNode;
|
|
1354
1408
|
|
|
1355
1409
|
/**
|
|
1356
1410
|
* Converts DOM nodes to JSX element(s).
|
|
@@ -1371,11 +1425,11 @@
|
|
|
1371
1425
|
|
|
1372
1426
|
var result = [];
|
|
1373
1427
|
var node;
|
|
1428
|
+
var isWhitespace;
|
|
1374
1429
|
var hasReplace = typeof options.replace === 'function';
|
|
1375
1430
|
var replaceElement;
|
|
1376
1431
|
var props;
|
|
1377
1432
|
var children;
|
|
1378
|
-
var data;
|
|
1379
1433
|
var trim = options.trim;
|
|
1380
1434
|
|
|
1381
1435
|
for (var i = 0, len = nodes.length; i < len; i++) {
|
|
@@ -1399,15 +1453,23 @@
|
|
|
1399
1453
|
}
|
|
1400
1454
|
|
|
1401
1455
|
if (node.type === 'text') {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1456
|
+
isWhitespace = !node.data.trim().length;
|
|
1457
|
+
|
|
1458
|
+
if (isWhitespace && node.parent && !canTextBeChildOfNode(node.parent)) {
|
|
1459
|
+
// We have a whitespace node that can't be nested in its parent
|
|
1460
|
+
// so skip it
|
|
1461
|
+
continue;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
if (trim && isWhitespace) {
|
|
1465
|
+
// Trim is enabled and we have a whitespace node
|
|
1466
|
+
// so skip it
|
|
1467
|
+
continue;
|
|
1410
1468
|
}
|
|
1469
|
+
|
|
1470
|
+
// We have a text node that's not whitespace and it can be nested
|
|
1471
|
+
// in its parent so add it to the results
|
|
1472
|
+
result.push(node.data);
|
|
1411
1473
|
continue;
|
|
1412
1474
|
}
|
|
1413
1475
|
|
|
@@ -1645,6 +1707,10 @@
|
|
|
1645
1707
|
}
|
|
1646
1708
|
Object.defineProperty(Node.prototype, "nodeType", {
|
|
1647
1709
|
// Read-only aliases
|
|
1710
|
+
/**
|
|
1711
|
+
* [DOM spec](https://dom.spec.whatwg.org/#dom-node-nodetype)-compatible
|
|
1712
|
+
* node {@link type}.
|
|
1713
|
+
*/
|
|
1648
1714
|
get: function () {
|
|
1649
1715
|
var _a;
|
|
1650
1716
|
return (_a = nodeTypes.get(this.type)) !== null && _a !== void 0 ? _a : 1;
|
|
@@ -1654,6 +1720,10 @@
|
|
|
1654
1720
|
});
|
|
1655
1721
|
Object.defineProperty(Node.prototype, "parentNode", {
|
|
1656
1722
|
// Read-write aliases for properties
|
|
1723
|
+
/**
|
|
1724
|
+
* Same as {@link parent}.
|
|
1725
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1726
|
+
*/
|
|
1657
1727
|
get: function () {
|
|
1658
1728
|
return this.parent;
|
|
1659
1729
|
},
|
|
@@ -1664,6 +1734,10 @@
|
|
|
1664
1734
|
configurable: true
|
|
1665
1735
|
});
|
|
1666
1736
|
Object.defineProperty(Node.prototype, "previousSibling", {
|
|
1737
|
+
/**
|
|
1738
|
+
* Same as {@link prev}.
|
|
1739
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1740
|
+
*/
|
|
1667
1741
|
get: function () {
|
|
1668
1742
|
return this.prev;
|
|
1669
1743
|
},
|
|
@@ -1674,6 +1748,10 @@
|
|
|
1674
1748
|
configurable: true
|
|
1675
1749
|
});
|
|
1676
1750
|
Object.defineProperty(Node.prototype, "nextSibling", {
|
|
1751
|
+
/**
|
|
1752
|
+
* Same as {@link next}.
|
|
1753
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1754
|
+
*/
|
|
1677
1755
|
get: function () {
|
|
1678
1756
|
return this.next;
|
|
1679
1757
|
},
|
|
@@ -1711,6 +1789,10 @@
|
|
|
1711
1789
|
return _this;
|
|
1712
1790
|
}
|
|
1713
1791
|
Object.defineProperty(DataNode.prototype, "nodeValue", {
|
|
1792
|
+
/**
|
|
1793
|
+
* Same as {@link data}.
|
|
1794
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1795
|
+
*/
|
|
1714
1796
|
get: function () {
|
|
1715
1797
|
return this.data;
|
|
1716
1798
|
},
|
|
@@ -1774,6 +1856,7 @@
|
|
|
1774
1856
|
}
|
|
1775
1857
|
Object.defineProperty(NodeWithChildren.prototype, "firstChild", {
|
|
1776
1858
|
// Aliases
|
|
1859
|
+
/** First child of the node. */
|
|
1777
1860
|
get: function () {
|
|
1778
1861
|
var _a;
|
|
1779
1862
|
return (_a = this.children[0]) !== null && _a !== void 0 ? _a : null;
|
|
@@ -1782,6 +1865,7 @@
|
|
|
1782
1865
|
configurable: true
|
|
1783
1866
|
});
|
|
1784
1867
|
Object.defineProperty(NodeWithChildren.prototype, "lastChild", {
|
|
1868
|
+
/** Last child of the node. */
|
|
1785
1869
|
get: function () {
|
|
1786
1870
|
return this.children.length > 0
|
|
1787
1871
|
? this.children[this.children.length - 1]
|
|
@@ -1791,6 +1875,10 @@
|
|
|
1791
1875
|
configurable: true
|
|
1792
1876
|
});
|
|
1793
1877
|
Object.defineProperty(NodeWithChildren.prototype, "childNodes", {
|
|
1878
|
+
/**
|
|
1879
|
+
* Same as {@link children}.
|
|
1880
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1881
|
+
*/
|
|
1794
1882
|
get: function () {
|
|
1795
1883
|
return this.children;
|
|
1796
1884
|
},
|
|
@@ -1838,6 +1926,10 @@
|
|
|
1838
1926
|
}
|
|
1839
1927
|
Object.defineProperty(Element.prototype, "tagName", {
|
|
1840
1928
|
// DOM Level 1 aliases
|
|
1929
|
+
/**
|
|
1930
|
+
* Same as {@link name}.
|
|
1931
|
+
* [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
|
|
1932
|
+
*/
|
|
1841
1933
|
get: function () {
|
|
1842
1934
|
return this.name;
|
|
1843
1935
|
},
|
|
@@ -1941,6 +2033,9 @@
|
|
|
1941
2033
|
var children = recursive ? cloneChildren(node.children) : [];
|
|
1942
2034
|
var clone_1 = new Element$1(node.name, __assign({}, node.attribs), children);
|
|
1943
2035
|
children.forEach(function (child) { return (child.parent = clone_1); });
|
|
2036
|
+
if (node.namespace != null) {
|
|
2037
|
+
clone_1.namespace = node.namespace;
|
|
2038
|
+
}
|
|
1944
2039
|
if (node["x-attribsNamespace"]) {
|
|
1945
2040
|
clone_1["x-attribsNamespace"] = __assign({}, node["x-attribsNamespace"]);
|
|
1946
2041
|
}
|
|
@@ -1974,10 +2069,13 @@
|
|
|
1974
2069
|
result = instruction;
|
|
1975
2070
|
}
|
|
1976
2071
|
else {
|
|
1977
|
-
throw new Error("Not implemented yet: "
|
|
2072
|
+
throw new Error("Not implemented yet: ".concat(node.type));
|
|
1978
2073
|
}
|
|
1979
2074
|
result.startIndex = node.startIndex;
|
|
1980
2075
|
result.endIndex = node.endIndex;
|
|
2076
|
+
if (node.sourceCodeLocation != null) {
|
|
2077
|
+
result.sourceCodeLocation = node.sourceCodeLocation;
|
|
2078
|
+
}
|
|
1981
2079
|
return result;
|
|
1982
2080
|
}
|
|
1983
2081
|
node.cloneNode = cloneNode;
|