html-react-parser 1.4.2 → 1.4.6

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