Skip to content

Commit a06f329

Browse files
author
vvo
committed
feat(deep): handle deeply set React elements
like <div a={{b: {c: {d: <div />}}}} />
1 parent ad21917 commit a06f329

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

index-test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,9 @@ describe(`reactElementToJSXString(ReactElement)`, () => {
182182
).toEqual(`<div a={{b: function noRefCheck() {}}} />`);
183183
});
184184

185+
it(`reactElementToJSXString(<div a={{b: {c: {d: <div />}}}} />`, () => {
186+
expect(
187+
reactElementToJSXString(<div a={{b: {c: {d: <div />}}}} />)
188+
).toEqual(`<div a={{b: {c: {d: <div />}}}} />`);
189+
});
185190
});

index.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import React from 'react';
22
import collapse from 'collapse-white-space';
33
import {isElement} from 'react-addons-test-utils';
4+
import isPlainObject from 'is-plain-object';
45
import stringify from 'stringify-object';
56
import sortobject from 'sortobject';
7+
import traverse from 'traverse';
68

79
export default function reactElementToJSXString(ReactElement) {
810
return toJSXString({ReactElement});
@@ -83,6 +85,8 @@ function formatProps(props) {
8385
return {
8486
name: propName,
8587
value: formatPropValue(props[propName])
88+
.replace(/'?<__reactElementToJSXString__ReactElement__>/g, '')
89+
.replace(/<\/__reactElementToJSXString__ReactElement__>'?/g, '')
8690
};
8791
});
8892
}
@@ -99,8 +103,17 @@ function formatValue(value) {
99103
if (typeof value === 'function') {
100104
return function noRefCheck() {};
101105
} else if (isElement(value)) {
102-
return toJSXString({ReactElement: value, inline: true});
103-
} else if (value && Object.keys(value).length > 0) {
106+
// we use this delimiter hack in cases where the react element is a property
107+
// of an object from a root prop
108+
// i.e.
109+
// reactElementToJSXString(<div a={{b: <div />}} />
110+
// // <div a={{b: <div />}} />
111+
// we then remove the whole wrapping
112+
// otherwise, the element would be surrounded by quotes: <div a={{b: '<div />'}} />
113+
return '<__reactElementToJSXString__ReactElement__>' +
114+
toJSXString({ReactElement: value, inline: true}) +
115+
'</__reactElementToJSXString__ReactElement__>';
116+
} else if (isPlainObject(value)) {
104117
return stringifyObject(value);
105118
}
106119

@@ -114,10 +127,13 @@ function recurse({lvl, inline}) {
114127
}
115128

116129
function stringifyObject(obj) {
117-
// sortobject fails on some types, like regex
118-
if (obj && Object.keys(obj).length > 0) {
119-
obj = sortobject(obj);
120-
}
130+
obj = traverse(obj).map(function(value) {
131+
if (isElement(value) || this.isLeaf) {
132+
this.update(formatValue(value));
133+
}
134+
});
135+
136+
obj = sortobject(obj);
121137

122138
return collapse(stringify(obj))
123139
.replace(/{ /g, '{')

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
},
3030
"dependencies": {
3131
"collapse-white-space": "^1.0.0",
32+
"is-plain-object": "^2.0.1",
3233
"react-addons-test-utils": "^0.14.0",
3334
"sortobject": "^1.0.0",
34-
"stringify-object": "^2.3.0"
35+
"stringify-object": "^2.3.0",
36+
"traverse": "^0.6.6"
3537
}
3638
}

0 commit comments

Comments
 (0)