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 +10 -15
- package/dist/html-react-parser.js +74 -12
- 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 +16 -12
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
|
|