Skip to content

Commit ed12c02

Browse files
committed
V2 using moduleName.
1 parent 015c860 commit ed12c02

File tree

9 files changed

+198
-291
lines changed

9 files changed

+198
-291
lines changed

README.md

Lines changed: 57 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,27 @@
33
[![Travis build status](http://img.shields.io/travis/gajus/react-css-modules/master.svg?style=flat)](https://travis-ci.org/gajus/react-css-modules)
44
[![NPM version](http://img.shields.io/npm/v/react-css-modules.svg?style=flat)](https://www.npmjs.org/package/react-css-modules)
55

6-
React CSS Modules implement automatic mapping of class names to CSS modules. Every CSS class is assigned a local-scoped identifier with a global unique name. CSS Modules enable a modular and reusable CSS!
6+
React CSS Modules implement automatic mapping of CSS modules. Every CSS class is assigned a local-scoped identifier with a global unique name. CSS Modules enable a modular and reusable CSS!
77

88
- [What's the Problem?](#whats-the-problem)
9+
- [The Implementation](#theimplementation)
910
- [Usage](#usage)
1011
- [Module Bundler](#module-bundler)
1112
- [webpack](#webpack)
1213
- [Browserify](#browserify)
1314
- [Decorator](#decorator)
1415
- [Options](#options)
15-
- [`useModuleName`](#usemodulename)
1616
- [`allowMultiple`](#allowmultiple)
17-
- [`keepOriginal`](#keeporiginal)
18-
- [`errorNotFound`](#errornotfound)
17+
- [`errorWhenNotFound`](#errorwhennotfound)
1918
- [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors)
2019
- [Global CSS](#global-css)
2120
- [Multiple CSS Classes](#multiple-css-classes)
2221

2322
## What's the Problem?
2423

25-
[CSS modules](https://github.com/css-modules/css-modules) are awesome. If you are not familiar with CSS modules, it is a concept of using a module bundler such as [webpack](http://webpack.github.io/docs/) to load CSS scoped to a particular document. CSS modules loader will generate a unique name for a each CSS class at the time of loading the CSS. Refer to [webpack-demo](https://css-modules.github.io/webpack-demo/) for a full example.
24+
[CSS Modules](https://github.com/css-modules/css-modules) are awesome. If you are not familiar with CSS Modules, it is a concept of using a module bundler such as [webpack](http://webpack.github.io/docs/) to load CSS scoped to a particular document. CSS module loader will generate a unique name for a each CSS class at the time of loading the CSS document ([Interoperable CSS](https://github.com/css-modules/icss) to be precise). To see CSS Modules in practice, [webpack-demo](https://css-modules.github.io/webpack-demo/).
2625

27-
In the context of React, this looks like this:
26+
In the context of React, CSS Modules look like this:
2827

2928
```js
3029
import React from 'react';
@@ -43,9 +42,9 @@ export default class Car extends React.Component {
4342
Rendering the component will produce a markup similar to:
4443

4544
```js
46-
<div class="car__car___32osj" data-reactid=".0.0">
47-
<div class="car__front-door___2w27N" data-reactid=".0.0.$=10:0">front-door</div>
48-
<div class="car__back-door___1oVw5" data-reactid=".0.0.$=11:0">back-door</div>
45+
<div class="car__car___32osj">
46+
<div class="car__front-door___2w27N">front-door</div>
47+
<div class="car__back-door___1oVw5">back-door</div>
4948
</div>
5049
```
5150

@@ -57,8 +56,10 @@ However, this approach has several disadvantages:
5756

5857
* You have to use `camelCase` CSS class names.
5958
* You have to use `styles` object whenever constructing a `className`.
59+
* Mixing CSS Modules and global CSS classes is cumbersome.
60+
* Reference to an undefined CSS Module resolves to `undefined` without a warning.
6061

61-
React CSS Modules enables seamless CSS modules for React, e.g.
62+
React CSS Modules component automates loading of CSS Modules using `moduleName` property, e.g.
6263

6364
```js
6465
import React from 'react';
@@ -67,36 +68,49 @@ import CSSModules from 'react-css-modules';
6768

6869
class Car extends React.Component {
6970
render () {
70-
return <div className='car'>
71-
<div className='front-door'></div>
72-
<div className='back-door'></div>
71+
return <div moduleName='car'>
72+
<div moduleName='front-door'></div>
73+
<div moduleName='back-door'></div>
7374
</div>;
7475
}
7576
}
7677

7778
export default CSSModules(Car, styles);
7879
```
7980

80-
`CSSModules` extends `Car` `render` method. It will look for CSS classes in `./car.css` that match CSS class names in `ReactElement` `className` and will replace/append the matching unique class names to `className` declaration.
81+
Using `react-css-modules`:
82+
83+
* You are not forced to use the `camelCase` naming convention.
84+
* You do not need to refer to the `styles` object every time you use a CSS Module.
85+
* There is clear distinction between global CSS and CSS Modules, e.g.
86+
87+
```js
88+
<div className='global-css' moduleName='local-module'></div>
89+
```
90+
91+
* You are warned when `moduleName` refers to an undefined CSS Module ([`errorWhenNotFound`](#errorwhennotfound) option).
92+
* You can enforce use of a single CSS module per `ReactElement` ([`allowMultiple`](#allowmultiple) option).
8193

82-
Refer to the [react-css-modules-examples](https://github.com/gajus/react-css-modules-examples) repository for a complete usage example.
94+
## The Implementation
95+
96+
`react-css-modules` extends `render` method of the target component. It will use the value of `moduleName` to look for CSS Modules in the associated styles object and will append the matching unique CSS class names to the `ReactElement` `className` property value.
8397

8498
[Awesome!](https://twitter.com/intent/retweet?tweet_id=636497036603428864)
8599

86100
## Usage
87101

88102
Setup consists of:
89103

90-
* Setting up a module bundler to load your [ICSS](https://github.com/css-modules/icss).
104+
* Setting up a [module bundler](#modulebundler) to load the [Interoperable CSS](https://github.com/css-modules/icss).
91105
* [Decorating](#decorator) your component using `react-css-modules`.
92106

93107
### Module Bundler
94108

95109
#### webpack
96110

97111
* Install [`style-loader`](https://www.npmjs.com/package/style-loader) and [`css-loader`](https://www.npmjs.com/package/css-loader).
98-
* You will also need to use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to aggregate the CSS into a single file.
99-
* Setup a `/\.css$/` loader:
112+
* You need to use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to aggregate the CSS into a single file.
113+
* Setup `/\.css$/` loader:
100114

101115
```js
102116
{
@@ -113,7 +127,7 @@ new ExtractTextPlugin('app.css', {
113127
})
114128
```
115129

116-
Refer to [webpack-demo](https://github.com/css-modules/webpack-demo) or [react-css-modules-examples](https://github.com/gajus/react-css-modules-examples) for a complete setup.
130+
Refer to [webpack-demo](https://github.com/css-modules/webpack-demo) or [react-css-modules-examples](https://github.com/gajus/react-css-modules-examples) for an example of a complete setup.
117131

118132
#### Browserify
119133

@@ -124,16 +138,16 @@ Refer to [`css-modulesify`](https://github.com/css-modules/css-modulesify).
124138
```js
125139
/**
126140
* @typedef CSSModules~Options
127-
* @property {Boolean} allowMultiple Determines whether `className` can have multiple class names. Throws an error when the constrained is not met. Default: true.
128-
* @property {Boolean} keepOriginal Determines whether the original `className` value is kept in addition to the appended CSS modules styles CSS class name. Default: true.
129-
* @property {Boolean} errorNotFound Determines whether an error is raised if `className` defines a CSS class(es) that is not present in the CSS modules styles. Default: false.
141+
* @see {@link https://github.com/gajus/react-css-modules#options}
142+
* @property {Boolean} allowMultiple
143+
* @property {Boolean} errorWhenNotFound
130144
*/
131145

132146
/**
133-
* @param {ReactClass} Component
134-
* @param {Object} styles CSS modules class map.
147+
* @param {Function} Component
148+
* @param {Object} styles CSS Modules class map.
135149
* @param {CSSModules~Options} options
136-
* @return {ReactClass}
150+
* @return {Function}
137151
*/
138152
```
139153

@@ -178,6 +192,8 @@ export default class extends React.Component {
178192

179193
[Awesome!](https://twitter.com/intent/retweet?tweet_id=636497036603428864)
180194

195+
Refer to the [react-css-modules-examples](https://github.com/gajus/react-css-modules-examples) repository for an example of webpack setup.
196+
181197
### Options
182198

183199
Options are supplied as the third parameter to the `CSSModules` function.
@@ -186,57 +202,33 @@ Options are supplied as the third parameter to the `CSSModules` function.
186202
CSSModules(Component, styles, options);
187203
```
188204

189-
or as a second parameter when using `CSSModules` as a decorator:
205+
or as a second parameter to the decorator:
190206

191207
```js
192208
@CSSModules(styles, options);
193209
```
194210

195-
#### `useModuleName`
196-
197-
Default: `false`.
198-
199-
When enabled then CSS Modules are loaded using `moduleName` property and `className` is used only for global CSS, e.g.
200-
201-
```js
202-
<div className='global-css-class' moduleName='local-module-name' />
203-
```
204-
205211
#### `allowMultiple`
206212

207-
Default: `true`.
213+
Default: `false`.
208214

209-
Allows multiple CSS class names.
215+
Allows multiple CSS Module names.
210216

211217
When `false`, the following will cause an error:
212218

213219
```js
214-
<div className='foo bar' />
220+
<div moduleName='foo bar' />
215221
```
216222

217-
#### `keepOriginal`
223+
#### `errorWhenNotFound`
218224

219225
Default: `true`.
220226

221-
Keeps original CSS class name in addition to the names of the CSS Modules.
222-
223-
When `true`, the following `ReactElement`:
224-
225-
```js
226-
<div className='foo bar' />
227-
```
228-
229-
will be rendered with a `className` property `foo component__foo___2w27N bar component__bar__1oVw5`.
230-
231-
#### `errorNotFound`
232-
233-
Default: `false`.
234-
235-
Throws an error when class name cannot be mapped to a CSS Module.
227+
Throws an error when `moduleName` cannot be mapped to an existing CSS Module.
236228

237229
## SASS, SCSS, LESS and other CSS Preprocessors
238230

239-
[ICSS](https://github.com/css-modules/icss) is compatible with the CSS Preprocessors. All you need is to add the preprocessor to the chain of loaders, e.g. in the case of webpack it is as simple as installing `sass-loader` and adding `!sass` to the end of the `style-loader` loader chain declaration (loaders are processed from right to left):
231+
[Interoperable CSS](https://github.com/css-modules/icss) is compatible with the CSS Preprocessors. To use a preprocessor, all you need to do is add the preprocessor to the chain of loaders, e.g. in the case of webpack it is as simple as installing `sass-loader` and adding `!sass` to the end of the `style-loader` loader query (loaders are processed from right to left):
240232

241233
```js
242234
{
@@ -255,13 +247,11 @@ CSS Modules does not restrict you from using global CSS.
255247
}
256248
```
257249

258-
When using global CSS, you need to enable [`keepOriginal`](#keeporiginal) option.
250+
However, use global CSS with caution. With CSS Modules, there are only a handful of valid use cases for global CSS (e.g. [normalization](https://github.com/necolas/normalize.css/)).
259251

260-
Use global CSS with caution. With CSS Modules, there are only a handful of valid use cases for global CSS (e.g. [normalization](https://github.com/necolas/normalize.css/)).
252+
## Multiple CSS Modules
261253

262-
## Multiple CSS Classes
263-
264-
CSS modules promote composition pattern, i.e. every CSS class that is used in a component should define all properties required to describe the element, e.g.
254+
CSS Modules promote composition pattern, i.e. every CSS Module that is used in a component should define all properties required to describe an element, e.g.
265255

266256
```css
267257
.button {
@@ -281,9 +271,11 @@ CSS modules promote composition pattern, i.e. every CSS class that is used in a
281271
}
282272
```
283273

284-
To learn more about composing CSS rules, I suggest reading Glen Maddern article about [CSS Modules](http://glenmaddern.com/articles/css-modules) and the official [CSS modules spec](https://github.com/css-modules/css-modules).
274+
Composition promotes better separation of markup and style using semantics that would be hard to achieve without CSS Modules.
275+
276+
To learn more about composing CSS rules, I suggest reading Glen Maddern article about [CSS Modules](http://glenmaddern.com/articles/css-modules) and the official [spec of the CSS Modules](https://github.com/css-modules/css-modules).
285277

286-
Using React CSS Modules, you can map as many CSS classes to the element as you want. `CSSModules` will append a unique class name for every class name it matches in the `className` declaration, e.g.
278+
That said, if you enable [`allowMultiple`](#allowmultiple) option, you can map multiple CSS Modules to a single `ReactElement`. `react-css-modules` will append a unique class name for every CSS Module it matches in the `moduleName` declaration, e.g.
287279

288280
```css
289281
.button {
@@ -296,9 +288,7 @@ Using React CSS Modules, you can map as many CSS classes to the element as you w
296288
```
297289

298290
```js
299-
<div className='button active'></div>
291+
<div moduleName='button active'></div>
300292
```
301293

302-
This will map both [ICSS](https://github.com/css-modules/icss) CSS classes to the target element.
303-
304-
However, I encourage you to use composition whenever possible. Composition promotes better separation of markup from style sheets using semantics that would be hard to achieve without CSS modules. You can enforce one CSS class name per `className` using [`allowMultiple` option](#usage).
294+
This will map both [Interoperable CSS](https://github.com/css-modules/icss) CSS classes to the target element.

dist/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ var decoratorConstructor = undefined,
2929
* When used as a function.
3030
*
3131
* @param {Function} Component
32-
* @param {Object} styles CSS modules class map.
32+
* @param {Object} styles CSS Modules class map.
3333
* @param {Object} options {@link https://github.com/gajus/react-css-modules#options}
3434
* @return {Function}
3535
*/
@@ -59,7 +59,7 @@ functionConstructor = function (Component, styles) {
5959
/**
6060
* When used as a ES7 decorator.
6161
*
62-
* @param {Object} styles CSS modules class map.
62+
* @param {Object} styles CSS Modules class map.
6363
* @param {Object} options {@link https://github.com/gajus/react-css-modules#options}
6464
* @return {Function}
6565
*/

dist/linkClass.js

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,51 +24,37 @@ linkClass = function (element) {
2424

2525
var childrenCount = undefined,
2626
clonedElement = undefined,
27-
moduleName = undefined,
27+
moduleNames = undefined,
2828
newChildren = undefined,
29-
newClassName = undefined,
30-
newProps = undefined;
29+
newProps = undefined,
30+
appendClassName = undefined;
3131

32-
if (options.useModuleName) {
33-
moduleName = element.props.moduleName;
32+
moduleNames = element.props.moduleName;
3433

35-
options.includeOriginal = false;
36-
} else {
37-
moduleName = element.props.className;
38-
}
39-
40-
if (moduleName) {
41-
newClassName = moduleName.split(' ');
34+
if (moduleNames) {
35+
moduleNames = moduleNames.split(' ');
4236

43-
if (options.allowMultiple === false && newClassName.length > 1) {
44-
throw new Error('ReactElement defines multiple class names ("' + element.props.className + '") in className declaration.');
37+
if (options.allowMultiple === false && moduleNames.length > 1) {
38+
throw new Error('ReactElement moduleName property defines multiple module names ("' + element.props.moduleName + '").');
4539
}
4640

47-
newClassName = newClassName.map(function (className) {
48-
if (!styles[className] && options.errorNotFound === true) {
49-
throw new Error('"' + className + '" CSS class name is not found in CSS modules styles.');
50-
}
51-
52-
if (options.includeOriginal === false) {
53-
if (styles[className]) {
54-
return styles[className];
55-
} else {
56-
return '';
57-
}
41+
appendClassName = moduleNames.map(function (moduleName) {
42+
if (styles[moduleName]) {
43+
return styles[moduleName];
5844
} else {
59-
if (styles[className]) {
60-
return className + ' ' + styles[className];
61-
} else {
62-
return className;
45+
if (options.errorWhenNotFound === true) {
46+
throw new Error('"' + moduleName + '" CSS module is undefined.');
6347
}
48+
49+
return '';
6450
}
6551
});
6652

67-
newClassName = newClassName.filter(function (className) {
53+
appendClassName = appendClassName.filter(function (className) {
6854
return className.length;
6955
});
7056

71-
newClassName = newClassName.join(' ');
57+
appendClassName = appendClassName.join(' ');
7258
}
7359

7460
// A child can be either an array, a sole object or a string.
@@ -89,9 +75,13 @@ linkClass = function (element) {
8975
}
9076
}
9177

92-
if (newClassName) {
78+
if (appendClassName) {
79+
if (element.props.className) {
80+
appendClassName = element.props.className + ' ' + appendClassName;
81+
}
82+
9383
newProps = {
94-
className: newClassName
84+
className: appendClassName
9585
};
9686
}
9787

0 commit comments

Comments
 (0)