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 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
- [Repl.it](https://repl.it/@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)
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://repl.it/@remarkablemark/html-react-parser-replace-example)):
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://repl.it/@remarkablemark/html-react-parser-56) an element from rendering by replacing it with `<React.Fragment>`:
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
- To remove whitespace, enable the `trim` option:
353
+ But certain elements like `<table>` will strip out invalid whitespace:
355
354
 
356
355
  ```js
357
- parse('<br>\n', { trim: true }); // React.createElement('br')
356
+ parse('<table>\n</table>'); // React.createElement('table')
358
357
  ```
359
358
 
360
- This fixes the warning:
359
+ To remove whitespace, enable the `trim` option:
361
360
 
362
- ```
363
- Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of <table>. Make sure you don't have any extra whitespace between tags on each line of your source code.
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://repl.it/@remarkablemark/html-react-parser-SSR).
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://repl.it/@remarkablemark/html-react-parser-62).
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 = reactProperty.possibleStandardNames[attributeNameLowerCased];
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
- // if trim option is enabled, skip whitespace text nodes
1403
- if (trim) {
1404
- data = node.data.trim();
1405
- if (data) {
1406
- result.push(node.data);
1407
- }
1408
- } else {
1409
- result.push(node.data);
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: " + node.type);
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;