Skip to content

Commit 59f148c

Browse files
committed
All decorated components inherit styles property that describes the CSS module and CSS class relation.
1 parent c268a18 commit 59f148c

File tree

8 files changed

+245
-6
lines changed

8 files changed

+245
-6
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is
1717
- [webpack](#webpack)
1818
- [Browserify](#browserify)
1919
- [Extending Component Styles](#extending-component-styles)
20+
- [Inheriting the Styles Object Through Properties](#inheriting-the-styles-object-through-properties)
2021
- [Decorator](#decorator)
2122
- [Options](#options)
2223
- [`allowMultiple`](#allowmultiple)
@@ -218,6 +219,42 @@ In this example, `table-custom-styles.css` selectively extends `table.css` (the
218219

219220
Refer to the [`UsingStylesProperty` example](https://github.com/gajus/react-css-modules-examples/tree/master/src/UsingStylesProperty) for an example of a working implementation.
220221

222+
### Inheriting the Styles Object Through Properties
223+
224+
`styleNames` cannot be used within a component to define styles of a `ReactElement` that will be generated by another component, e.g.
225+
226+
```js
227+
class extends React.Component {
228+
render () {
229+
let itemTemplate;
230+
231+
itemTemplate = (name) => {
232+
return <li styleName='foo'>{name}</li>;
233+
};
234+
235+
return <List itemTemplate={name} />;
236+
}
237+
}
238+
```
239+
240+
The original [issue](https://github.com/gajus/react-css-modules/issues/11) describing the use case.
241+
242+
For that purpose, the decorated class inherits `styles` property that you can use just as a regular CSS Modules object. The earlier example can be therefore rewritten to:
243+
244+
```js
245+
class extends React.Component {
246+
render () {
247+
let itemTemplate;
248+
249+
itemTemplate = (name) => {
250+
return <li styleName={this.props.styles.foo}>{name}</li>;
251+
};
252+
253+
return <List itemTemplate={name} />;
254+
}
255+
}
256+
```
257+
221258
### Decorator
222259

223260
```js

dist/extendReactClass.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ var _lodashLangIsObject2 = require('lodash/lang/isObject');
44

55
var _lodashLangIsObject3 = _interopRequireDefault(_lodashLangIsObject2);
66

7+
var _lodashObjectAssign2 = require('lodash/object/assign');
8+
9+
var _lodashObjectAssign3 = _interopRequireDefault(_lodashObjectAssign2);
10+
711
Object.defineProperty(exports, '__esModule', {
812
value: true
913
});
@@ -28,6 +32,12 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'd
2832

2933
var extendReactClass = undefined;
3034

35+
/**
36+
* @param {ReactClass} Component
37+
* @param {Object} defaultStyles
38+
* @param {Object} options
39+
* @returns {ReactClass}
40+
*/
3141
extendReactClass = function (Component, defaultStyles, options) {
3242
return (function (_Component) {
3343
_inherits(_class, _Component);
@@ -47,6 +57,10 @@ extendReactClass = function (Component, defaultStyles, options) {
4757
if (this.props.styles) {
4858
styles = this.props.styles;
4959
} else if ((0, _lodashLangIsObject3['default'])(defaultStyles)) {
60+
this.props = (0, _lodashObjectAssign3['default'])({}, this.props, {
61+
styles: defaultStyles
62+
});
63+
5064
styles = defaultStyles;
5165
} else {
5266
styles = {};

dist/linkClass.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ linkClass = function (element, styles, userConfiguration) {
4040
newProps = undefined,
4141
styleNames = undefined;
4242

43+
// @see https://github.com/gajus/react-css-modules/pull/30
4344
if (!element) {
4445
return element;
4546
}

dist/wrapStatelessFunction.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ var _lodashLangIsObject2 = require('lodash/lang/isObject');
44

55
var _lodashLangIsObject3 = _interopRequireDefault(_lodashLangIsObject2);
66

7+
var _lodashObjectAssign2 = require('lodash/object/assign');
8+
9+
var _lodashObjectAssign3 = _interopRequireDefault(_lodashObjectAssign2);
10+
711
Object.defineProperty(exports, '__esModule', {
812
value: true
913
});
@@ -20,24 +24,40 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'd
2024

2125
var wrapStatelessFunction = undefined;
2226

27+
/**
28+
* @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components
29+
* @param {function} Component
30+
* @param {Object} defaultStyles
31+
* @param {Object} options
32+
* @returns {function}
33+
*/
2334
wrapStatelessFunction = function (Component, defaultStyles, options) {
24-
return function (props) {
35+
return function () {
2536
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
2637
args[_key - 1] = arguments[_key];
2738
}
2839

40+
var props = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
41+
2942
var renderResult = undefined,
30-
styles = undefined;
43+
styles = undefined,
44+
useProps = undefined;
3145

3246
if (props.styles) {
47+
useProps = props;
3348
styles = props.styles;
3449
} else if ((0, _lodashLangIsObject3['default'])(defaultStyles)) {
50+
useProps = (0, _lodashObjectAssign3['default'])({}, props, {
51+
styles: defaultStyles
52+
});
53+
3554
styles = defaultStyles;
3655
} else {
56+
useProps = props;
3757
styles = {};
3858
}
3959

40-
renderResult = Component.apply(undefined, [props].concat(args));
60+
renderResult = Component.apply(undefined, [useProps].concat(args));
4161

4262
if (renderResult) {
4363
return (0, _linkClass2['default'])(renderResult, styles, options);

src/extendReactClass.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import _ from 'lodash';
44

55
let extendReactClass;
66

7+
/**
8+
* @param {ReactClass} Component
9+
* @param {Object} defaultStyles
10+
* @param {Object} options
11+
* @returns {ReactClass}
12+
*/
713
extendReactClass = (Component, defaultStyles, options) => {
814
return class extends Component {
915
render () {
@@ -13,6 +19,10 @@ extendReactClass = (Component, defaultStyles, options) => {
1319
if (this.props.styles) {
1420
styles = this.props.styles;
1521
} else if (_.isObject(defaultStyles)) {
22+
this.props = _.assign({}, this.props, {
23+
styles: defaultStyles
24+
});
25+
1626
styles = defaultStyles;
1727
} else {
1828
styles = {};

src/wrapStatelessFunction.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,34 @@ import _ from 'lodash';
44

55
let wrapStatelessFunction;
66

7+
/**
8+
* @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components
9+
* @param {function} Component
10+
* @param {Object} defaultStyles
11+
* @param {Object} options
12+
* @returns {function}
13+
*/
714
wrapStatelessFunction = (Component, defaultStyles, options) => {
8-
return (props, ...args) => {
15+
return (props = {}, ...args) => {
916
let renderResult,
10-
styles;
17+
styles,
18+
useProps;
1119

1220
if (props.styles) {
21+
useProps = props;
1322
styles = props.styles;
1423
} else if (_.isObject(defaultStyles)) {
24+
useProps = _.assign({}, props, {
25+
styles: defaultStyles
26+
});
27+
1528
styles = defaultStyles;
1629
} else {
30+
useProps = props;
1731
styles = {};
1832
}
1933

20-
renderResult = Component(props, ...args);
34+
renderResult = Component(useProps, ...args);
2135

2236
if (renderResult) {
2337
return linkClass(renderResult, styles, options);

test/extendReactClass.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* eslint-disable max-nested-callbacks */
2+
3+
import {
4+
expect
5+
} from 'chai';
6+
7+
import React from 'react';
8+
import TestUtils from 'react-addons-test-utils';
9+
import jsdom from 'jsdom';
10+
import extendReactClass from './../src/extendReactClass';
11+
12+
describe('extendReactClass', () => {
13+
beforeEach(() => {
14+
global.document = jsdom.jsdom(`
15+
<!DOCTYPE html>
16+
<html>
17+
<head>
18+
</head>
19+
<body>
20+
</body>
21+
</html>
22+
`);
23+
24+
global.window = document.defaultView;
25+
});
26+
27+
context('using default styles', () => {
28+
it('exposes styles through styles property', (done) => {
29+
let Component,
30+
styles;
31+
32+
Component = class extends React.Component {
33+
render () {
34+
expect(this.props.styles).to.equal(styles);
35+
done();
36+
}
37+
};
38+
39+
styles = {
40+
foo: 'foo-1'
41+
};
42+
43+
Component = extendReactClass(Component, styles);
44+
45+
TestUtils.renderIntoDocument(<Component />);
46+
});
47+
it('does not affect the other instance properties', (done) => {
48+
let Component,
49+
styles;
50+
51+
Component = class extends React.Component {
52+
render () {
53+
expect(this.props.bar).to.equal('baz');
54+
done();
55+
}
56+
};
57+
58+
styles = {
59+
foo: 'foo-1'
60+
};
61+
62+
Component = extendReactClass(Component, styles);
63+
64+
TestUtils.renderIntoDocument(<Component bar='baz' />);
65+
});
66+
});
67+
68+
context('using explicit styles', () => {
69+
it('exposes styles through styles property', (done) => {
70+
let Component,
71+
styles;
72+
73+
Component = class extends React.Component {
74+
render () {
75+
expect(this.props.styles).to.equal(styles);
76+
done();
77+
}
78+
};
79+
80+
styles = {
81+
foo: 'foo-1'
82+
};
83+
84+
Component = extendReactClass(Component);
85+
86+
TestUtils.renderIntoDocument(<Component styles={styles} />);
87+
});
88+
});
89+
});

test/wrapStatelessFunction.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* eslint-disable max-nested-callbacks */
2+
3+
import {
4+
expect
5+
} from 'chai';
6+
7+
import wrapStatelessFunction from './../src/wrapStatelessFunction';
8+
9+
describe('wrapStatelessFunction', () => {
10+
context('using default styles', () => {
11+
it('exposes styles through styles property', (done) => {
12+
let styles;
13+
14+
styles = {
15+
foo: 'foo-1'
16+
};
17+
18+
wrapStatelessFunction((props) => {
19+
expect(props.styles).to.equal(styles);
20+
done();
21+
}, styles)();
22+
});
23+
it('does not affect the other instance properties', (done) => {
24+
let styles;
25+
26+
styles = {
27+
foo: 'foo-1'
28+
};
29+
30+
wrapStatelessFunction((props) => {
31+
expect(props.bar).to.equal('baz');
32+
done();
33+
}, styles)({
34+
bar: 'baz'
35+
});
36+
});
37+
});
38+
context('using explicit styles', () => {
39+
it('exposes styles through styles property', (done) => {
40+
let styles;
41+
42+
styles = {
43+
foo: 'foo-1'
44+
};
45+
46+
wrapStatelessFunction((props) => {
47+
expect(props.styles).to.equal(styles);
48+
done();
49+
})({
50+
styles
51+
});
52+
});
53+
});
54+
});

0 commit comments

Comments
 (0)