Skip to content

Commit 9c3708d

Browse files
Merge pull request #182 from remarkablemark/refactor/style-to-js
refactor: replace `cssToJs` with `style-to-js` and remove `camelCase`
2 parents c3028a7 + a980df4 commit 9c3708d

File tree

6 files changed

+40
-137
lines changed

6 files changed

+40
-137
lines changed

lib/attributes-to-props.js

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
var reactProperty = require('react-property');
2-
var styleToObject = require('style-to-object');
2+
var styleToJS = require('style-to-js').default;
33
var utilities = require('./utilities');
44

5-
var camelCase = utilities.camelCase;
6-
75
var htmlProperties = reactProperty.html;
86
var svgProperties = reactProperty.svg;
97
var isCustomAttribute = reactProperty.isCustomAttribute;
108

119
var hasOwnProperty = Object.prototype.hasOwnProperty;
1210

11+
var styleToJSOptions = { reactCompat: true };
12+
1313
/**
1414
* Converts HTML/SVG DOM attributes to React props.
1515
*
@@ -61,31 +61,10 @@ function attributesToProps(attributes) {
6161

6262
// convert inline style to object
6363
if (attributes.style != null) {
64-
props.style = cssToJs(attributes.style);
64+
props.style = styleToJS(attributes.style, styleToJSOptions);
6565
}
6666

6767
return props;
6868
}
6969

70-
/**
71-
* Converts inline CSS style to POJO (Plain Old JavaScript Object).
72-
*
73-
* @param {String} style - The inline CSS style.
74-
* @return {Object} - The style object.
75-
*/
76-
function cssToJs(style) {
77-
var styleObject = {};
78-
79-
if (style) {
80-
styleToObject(style, function (property, value) {
81-
// skip CSS comment
82-
if (property && value) {
83-
styleObject[camelCase(property)] = value;
84-
}
85-
});
86-
}
87-
88-
return styleObject;
89-
}
90-
9170
module.exports = attributesToProps;

lib/utilities.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,4 @@
11
var React = require('react');
2-
var hyphenPatternRegex = /-([a-z])/g;
3-
var CUSTOM_PROPERTY_OR_NO_HYPHEN_REGEX = /^--[a-zA-Z0-9-]+$|^[^-]+$/;
4-
5-
/**
6-
* Converts a string to camelCase.
7-
*
8-
* @param {String} string - The string.
9-
* @return {String}
10-
*/
11-
function camelCase(string) {
12-
if (typeof string !== 'string') {
13-
throw new TypeError('First argument must be a string');
14-
}
15-
16-
// custom property or no hyphen found
17-
if (CUSTOM_PROPERTY_OR_NO_HYPHEN_REGEX.test(string)) {
18-
return string;
19-
}
20-
21-
// convert to camelCase
22-
return string
23-
.toLowerCase()
24-
.replace(hyphenPatternRegex, function (_, character) {
25-
return character.toUpperCase();
26-
});
27-
}
282

293
/**
304
* Swap key with value in an object.
@@ -104,7 +78,6 @@ var PRESERVE_CUSTOM_ATTRIBUTES = React.version.split('.')[0] >= 16;
10478

10579
module.exports = {
10680
PRESERVE_CUSTOM_ATTRIBUTES: PRESERVE_CUSTOM_ATTRIBUTES,
107-
camelCase: camelCase,
10881
invertObject: invertObject,
10982
isCustomComponent: isCustomComponent
11083
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"@types/htmlparser2": "3.10.1",
3636
"html-dom-parser": "0.3.0",
3737
"react-property": "1.0.1",
38-
"style-to-object": "0.3.0"
38+
"style-to-js": "1.1.0"
3939
},
4040
"devDependencies": {
4141
"@commitlint/cli": "^8.3.5",
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`attributes to props style parses CSS to JS 1`] = `
4+
Object {
5+
"style": Object {
6+
"--custom-property": "#f00",
7+
"MozBorderRadiusBottomleft": "20px'",
8+
"WebkitBorderTopRightRadius": "10rem",
9+
"background": "url(data:image/png; base64,ivborw0kggoaaaansaaaabgdbtueaalgpc/xhbqaaaafzmuexurczmzpf399fx1+bm5mzy9avzxbesmgces5/p8/t9furvcrmu73jwlzosgsiizurcjo/ad+eqjjb4hv8bft+idpqocx1wjosbfhh2xssxeiyn3uli/6mnree07uiwjev8u8czwyuqdlkpg1bkb4nnm+veanfhqn1k4+gpt6ugqcvu2h2ovuif)",
10+
"borderBottomLeftRadius": "1em",
11+
"borderRightStyle": "solid",
12+
"color": "#f00",
13+
"fontSize": "42px",
14+
"zIndex": "-1",
15+
},
16+
}
17+
`;

test/attributes-to-props.test.js

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -160,62 +160,30 @@ describe('attributes to props', () => {
160160

161161
// cssToJs
162162
describe('style', () => {
163-
it('parses empty inline style to object', () => {
164-
expect(attributesToProps({ style: '' })).toEqual({ style: {} });
163+
const propsEmptyStyle = { style: {} };
164+
165+
it.each([undefined, null])('does not parse invalid value: %s', style => {
166+
expect(attributesToProps({ style })).toEqual({ style });
165167
});
166168

167169
it('does not parse CSS comment', () => {
168-
expect(attributesToProps({ style: '/* comment */' })).toEqual({
169-
style: {}
170-
});
170+
const style = '/* comment */';
171+
expect(attributesToProps({ style })).toEqual(propsEmptyStyle);
171172
});
172173

173-
it('parses inline style to object', () => {
174-
expect(
175-
attributesToProps({
176-
style:
177-
'color: #f00; font-size: 42px; z-index: -1; -moz-border-radius-topright: 10px; background: url(data:image/png; base64,ivborw0kggoaaaansaaaabgdbtueaalgpc/xhbqaaaafzmuexurczmzpf399fx1+bm5mzy9avzxbesmgces5/p8/t9furvcrmu73jwlzosgsiizurcjo/ad+eqjjb4hv8bft+idpqocx1wjosbfhh2xssxeiyn3uli/6mnree07uiwjev8u8czwyuqdlkpg1bkb4nnm+veanfhqn1k4+gpt6ugqcvu2h2ovuif)'
178-
})
179-
).toEqual({
180-
style: {
181-
color: '#f00',
182-
fontSize: '42px',
183-
zIndex: '-1',
184-
MozBorderRadiusTopright: '10px',
185-
background:
186-
'url(data:image/png; base64,ivborw0kggoaaaansaaaabgdbtueaalgpc/xhbqaaaafzmuexurczmzpf399fx1+bm5mzy9avzxbesmgces5/p8/t9furvcrmu73jwlzosgsiizurcjo/ad+eqjjb4hv8bft+idpqocx1wjosbfhh2xssxeiyn3uli/6mnree07uiwjev8u8czwyuqdlkpg1bkb4nnm+veanfhqn1k4+gpt6ugqcvu2h2ovuif)'
187-
}
188-
});
189-
190-
expect(
191-
attributesToProps({
192-
style:
193-
'border-bottom-left-radius:1em;border-right-style:solid;Z-Index:-1;-moz-border-radius-bottomleft:20px'
194-
})
195-
).toEqual({
196-
style: {
197-
borderBottomLeftRadius: '1em',
198-
borderRightStyle: 'solid',
199-
zIndex: '-1',
200-
MozBorderRadiusBottomleft: '20px'
201-
}
202-
});
203-
204-
expect(
205-
attributesToProps({
206-
style: null
207-
})
208-
).toEqual({
209-
style: null
210-
});
174+
it('parses "" to {}', () => {
175+
const style = '';
176+
expect(attributesToProps({ style })).toEqual(propsEmptyStyle);
177+
});
211178

212-
expect(
213-
attributesToProps({
214-
style: undefined
215-
})
216-
).toEqual({
217-
style: undefined
218-
});
179+
it('parses CSS to JS', () => {
180+
const style = `
181+
color: #f00; font-size: 42px; z-index: -1; -webkit-border-top-right-radius: 10rem; background: url(data:image/png; base64,ivborw0kggoaaaansaaaabgdbtueaalgpc/xhbqaaaafzmuexurczmzpf399fx1+bm5mzy9avzxbesmgces5/p8/t9furvcrmu73jwlzosgsiizurcjo/ad+eqjjb4hv8bft+idpqocx1wjosbfhh2xssxeiyn3uli/6mnree07uiwjev8u8czwyuqdlkpg1bkb4nnm+veanfhqn1k4+gpt6ugqcvu2h2ovuif);
182+
/* display: block; */
183+
--custom-property: #f00;
184+
border-bottom-left-radius:1em;border-right-style:solid;Z-Index:-1;-moz-border-radius-bottomleft:20px'
185+
`;
186+
expect(attributesToProps({ style })).toMatchSnapshot();
219187
});
220188
});
221189

test/utilities.test.js

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,11 @@
11
const React = require('react');
22
const {
33
PRESERVE_CUSTOM_ATTRIBUTES,
4-
camelCase,
54
invertObject,
65
isCustomComponent
76
} = require('../lib/utilities');
87

98
describe('utilities', () => {
10-
describe('camelCase', () => {
11-
it.each([undefined, null, {}, [], 0, 1, () => {}, new Date()])(
12-
'throws an error if first argument is %p',
13-
input => {
14-
expect(() => {
15-
camelCase(input);
16-
}).toThrow(TypeError);
17-
}
18-
);
19-
20-
it.each([
21-
['', ''],
22-
['foo', 'foo'],
23-
['fooBar', 'fooBar'],
24-
['--fooBar', '--fooBar'],
25-
['--foo-bar', '--foo-bar'],
26-
['--foo-100', '--foo-100']
27-
])(
28-
'does not modify string if it does not need to be camelCased',
29-
(input, expected) => {
30-
expect(camelCase(input)).toBe(expected);
31-
}
32-
);
33-
34-
it.each([
35-
['foo-bar', 'fooBar'],
36-
['foo-bar-baz', 'fooBarBaz'],
37-
['CAMEL-CASE', 'camelCase']
38-
])('camelCases a string', (input, expected) => {
39-
expect(camelCase(input)).toBe(expected);
40-
});
41-
});
42-
439
describe('invertObject', () => {
4410
it.each([undefined, null, 'string', 0, 1, () => {}])(
4511
`throws an error if the first argument is %p`,

0 commit comments

Comments
 (0)