diff --git a/.README/react-css-modules.png b/.README/react-css-modules.png
deleted file mode 100644
index 2614951..0000000
Binary files a/.README/react-css-modules.png and /dev/null differ
diff --git a/.README/react-css-modules.sketch b/.README/react-css-modules.sketch
deleted file mode 100644
index a014d75..0000000
Binary files a/.README/react-css-modules.sketch and /dev/null differ
diff --git a/.babelrc b/.babelrc
index 3751ba8..f651443 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,19 +1,14 @@
{
+ "presets": [
+ "es2015",
+ "stage-0",
+ "react"
+ ],
"plugins": [
"add-module-exports",
"lodash",
"transform-class-properties",
- [
- "transform-es2015-classes",
- {
- "loose": true
- }
- ],
+ ["transform-es2015-classes", { "loose": true }],
"transform-proto-to-assign"
- ],
- "presets": [
- "es2015",
- "stage-0",
- "react"
]
-}
+}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 0f17867..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 2
-indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
diff --git a/.eslintrc b/.eslintrc
index bcaad1b..84b918b 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,6 +1,3 @@
{
- "extends": [
- "canonical",
- "canonical/mocha"
- ]
-}
+ "extends": "canonical"
+}
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 2f093a7..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-github: gajus
-patreon: gajus
diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
index df978de..bc32025
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,39 @@
-node_modules
-coverage
-dist
+# Created by .ignore support plugin (hsz.mobi)
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+.idea/dataSources.ids
+.idea/dataSources.xml
+.idea/dataSources.local.xml
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+.idea/gradle.xml
+.idea/libraries
+.idea/mongoSettings.xml
+*.iws
+/out/
+.idea_modules/
+atlassian-ide-plugin.xml
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+logs
*.log
-.*
-!.babelrc
-!.editorconfig
-!.eslintrc
-!.gitignore
-!.npmignore
-!.README
-!.travis.yml
+npm-debug.log*
+pids
+*.pid
+*.seed
+lib-cov
+coverage
+.nyc_output
+.grunt
+.lock-wscript
+build/Release
+node_modules
+jspm_packages
+.npm
+.node_repl_history
diff --git a/.npmignore b/.npmignore
deleted file mode 100755
index e8add85..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,5 +0,0 @@
-src
-tests
-coverage
-.*
-*.log
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a786167..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: node_js
-node_js:
- - node
- - 8
-before_install:
- - npm config set depth 0
-notifications:
- email: false
-sudo: false
-script:
- - npm run test
- - npm run lint
-after_success:
- - semantic-release pre && npm publish && semantic-release post
diff --git a/README.md b/README.md
index a6b7399..5c8c0ef 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
# React CSS Modules
-[](https://gitspo.com/mentions/gajus/react-css-modules)
[](https://travis-ci.org/gajus/react-css-modules)
[](https://www.npmjs.org/package/react-css-modules)
[](https://github.com/gajus/canonical)
@@ -9,16 +8,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!
-> ## ⚠️⚠️⚠️ DEPRECATION NOTICE ⚠️⚠️⚠️
->
-> If you are considering to use `react-css-modules`, evaluate if [`babel-plugin-react-css-modules`](https://github.com/gajus/babel-plugin-react-css-modules) covers your use case.
-> `babel-plugin-react-css-modules` is a lightweight alternative of `react-css-modules`.
->
-> `babel-plugin-react-css-modules` is not a drop-in replacement and does not cover all the use cases of `react-css-modules`.
-> However, it has a lot smaller performance overhead (0-10% vs +50%; see [Performance](https://github.com/gajus/babel-plugin-react-css-modules#performance)) and a lot smaller size footprint (less than 2kb vs +17kb).
->
-> It is easy to get started! See the demo https://github.com/gajus/babel-plugin-react-css-modules/tree/master/demo
-
- [CSS Modules](#css-modules)
- [webpack `css-loader`](#webpack-css-loader)
- [What's the Problem?](#whats-the-problem)
@@ -35,18 +24,19 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is
- [Decorator](#decorator)
- [Options](#options)
- [`allowMultiple`](#allowmultiple)
- - [`handleNotFoundStyleName`](#handlenotfoundstylename)
+ - [`errorWhenNotFound`](#errorwhennotfound)
- [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors)
- [Enable Sourcemaps](#enable-sourcemaps)
- [Class Composition](#class-composition)
- [What Problems does Class Composition Solve?](#what-problems-does-class-composition-solve)
- [Class Composition Using CSS Preprocessors](#class-composition-using-css-preprocessors)
+- [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors)
- [Global CSS](#global-css)
- [Multiple CSS Modules](#multiple-css-modules)
## CSS Modules
-[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 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/).
+[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/).
In the context of React, CSS Modules look like this:
@@ -71,7 +61,7 @@ Rendering the component will produce a markup similar to:
```js
@@ -83,7 +73,7 @@ Awesome!
### webpack `css-loader`
-[CSS Modules](https://github.com/css-modules/css-modules) is a specification that can be implemented in multiple ways. `react-css-modules` leverages the existing CSS Modules implementation webpack [css-loader](https://github.com/webpack/css-loader#css-modules).
+[CSS Modules](https://github.com/css-modules/css-modules) is a specification that can be implemented in multiple ways. `react-css-modules` leverages as existing CSS Modules implementation webpack [css-loader](https://github.com/webpack/css-loader#css-modules).
## What's the Problem?
@@ -125,7 +115,7 @@ Using `react-css-modules`:
```
-* You are warned when `styleName` refers to an undefined CSS Module ([`handleNotFoundStyleName`](#handlenotfoundstylename) option).
+* You are warned when `styleName` refers to an undefined CSS Module ([`errorWhenNotFound`](#errorwhennotfound) option).
* You can enforce use of a single CSS module per `ReactElement` ([`allowMultiple`](#allowmultiple) option).
## The Implementation
@@ -159,8 +149,8 @@ Setup:
{
test: /\.css$/,
loaders: [
- 'style-loader?sourceMap',
- 'css-loader?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
+ 'style?sourceMap',
+ 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
```
@@ -192,48 +182,22 @@ Setup:
* Install [`style-loader`](https://www.npmjs.com/package/style-loader).
* Install [`css-loader`](https://www.npmjs.com/package/css-loader).
* Use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to extract chunks of CSS into a single stylesheet.
-
* Setup `/\.css$/` loader:
- * ExtractTextPlugin v1x:
-
- ```js
- {
- test: /\.css$/,
- loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
- }
- ```
-
- * ExtractTextPlugin v2x:
-
- ```js
- {
- test: /\.css$/,
- use: ExtractTextPlugin.extract({
- fallback: 'style-loader',
- use: 'css-loader?modules,localIdentName="[name]-[local]-[hash:base64:6]"'
- }),
- }
- ```
+```js
+{
+ test: /\.css$/,
+ loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
+}
+```
* Setup `extract-text-webpack-plugin` plugin:
- * ExtractTextPlugin v1x:
-
- ```js
- new ExtractTextPlugin('app.css', {
- allChunks: true
- })
- ```
-
- * ExtractTextPlugin v2x:
-
- ```js
- new ExtractTextPlugin({
- filename: 'app.css',
- allChunks: true
- })
- ```
+```js
+new ExtractTextPlugin('app.css', {
+ allChunks: true
+})
+```
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.
@@ -406,7 +370,7 @@ export default CSSModules(CustomList, styles);
* @typedef CSSModules~Options
* @see {@link https://github.com/gajus/react-css-modules#options}
* @property {Boolean} allowMultiple
- * @property {String} handleNotFoundStyleName
+ * @property {Boolean} errorWhenNotFound
*/
/**
@@ -490,17 +454,11 @@ When `false`, the following will cause an error:
```
-#### `handleNotFoundStyleName`
-
-Default: `throw`.
-
-Defines the desired action when `styleName` cannot be mapped to an existing CSS Module.
+#### `errorWhenNotFound`
-Available options:
+Default: `true`.
-* `throw` throws an error
-* `log` logs a warning using `console.warn`
-* `ignore` silently ignores the missing style name
+Throws an error when `styleName` cannot be mapped to an existing CSS Module.
## SASS, SCSS, LESS and other CSS Preprocessors
@@ -590,7 +548,7 @@ This pattern emerged with the advent of OOCSS. The biggest disadvantage of this
### Class Composition Using CSS Preprocessors
-This section of the document is included as a learning exercise to broaden the understanding about the origin of Class Composition. CSS Modules support a native method of composing CSS Modules using [`composes`](https://github.com/css-modules/css-modules#composition) keyword. CSS Preprocessor is not required.
+This section of the document is included as a learning exercise to broaden the understanding about the origin of Class Composition. CSS Modules support a native method of composting CSS Modules using [`composes`](https://github.com/css-modules/css-modules#composition) keyword. CSS Preprocessor is not required.
You can write compositions in SCSS using [`@extend`](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#extend) keyword and using [Mixin Directives](http://sass-lang.com/documentation/file.SASS_REFERENCE.html#mixins), e.g.
diff --git a/dist/extendReactClass.js b/dist/extendReactClass.js
new file mode 100644
index 0000000..a0a2688
--- /dev/null
+++ b/dist/extendReactClass.js
@@ -0,0 +1,91 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _assign2 = require('lodash/assign');
+
+var _assign3 = _interopRequireDefault(_assign2);
+
+var _isObject2 = require('lodash/isObject');
+
+var _isObject3 = _interopRequireDefault(_isObject2);
+
+var _react = require('react');
+
+var _react2 = _interopRequireDefault(_react);
+
+var _hoistNonReactStatics = require('hoist-non-react-statics');
+
+var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics);
+
+var _linkClass = require('./linkClass');
+
+var _linkClass2 = _interopRequireDefault(_linkClass);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } /* eslint-disable react/prop-types */
+
+/**
+ * @param {ReactClass} Component
+ * @param {Object} defaultStyles
+ * @param {Object} options
+ * @returns {ReactClass}
+ */
+exports.default = function (Component, defaultStyles, options) {
+ var WrappedComponent = function (_Component) {
+ _inherits(WrappedComponent, _Component);
+
+ function WrappedComponent() {
+ _classCallCheck(this, WrappedComponent);
+
+ return _possibleConstructorReturn(this, _Component.apply(this, arguments));
+ }
+
+ WrappedComponent.prototype.render = function render() {
+ var propsChanged = void 0,
+ styles = void 0;
+
+ propsChanged = false;
+
+ if (this.props.styles) {
+ styles = this.props.styles;
+ } else if ((0, _isObject3.default)(defaultStyles)) {
+ this.props = (0, _assign3.default)({}, this.props, {
+ styles: defaultStyles
+ });
+
+ propsChanged = true;
+ styles = defaultStyles;
+ } else {
+ styles = {};
+ }
+
+ var renderResult = _Component.prototype.render.call(this);
+
+ if (propsChanged) {
+ delete this.props.styles;
+ }
+
+ if (renderResult) {
+ return (0, _linkClass2.default)(renderResult, styles, options);
+ }
+
+ return _react2.default.createElement('noscript');
+ };
+
+ return WrappedComponent;
+ }(Component);
+
+ return (0, _hoistNonReactStatics2.default)(WrappedComponent, Component);
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/generateAppendClassName.js b/dist/generateAppendClassName.js
new file mode 100644
index 0000000..295c566
--- /dev/null
+++ b/dist/generateAppendClassName.js
@@ -0,0 +1,53 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _simpleMap = require('./simple-map');
+
+var _simpleMap2 = _interopRequireDefault(_simpleMap);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var stylesIndex = new _simpleMap2.default();
+
+exports.default = function (styles, styleNames, errorWhenNotFound) {
+ var appendClassName = void 0,
+ stylesIndexMap = void 0;
+
+ stylesIndexMap = stylesIndex.get(styles);
+
+ if (stylesIndexMap) {
+ var styleNameIndex = stylesIndexMap.get(styleNames);
+
+ if (styleNameIndex) {
+ return styleNameIndex;
+ }
+ } else {
+ stylesIndexMap = new _simpleMap2.default();
+ stylesIndex.set(styles, new _simpleMap2.default());
+ }
+
+ appendClassName = '';
+
+ for (var styleName in styleNames) {
+ if (styleNames.hasOwnProperty(styleName)) {
+ var className = styles[styleNames[styleName]];
+
+ if (className) {
+ appendClassName += ' ' + className;
+ } else if (errorWhenNotFound === true) {
+ throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.');
+ }
+ }
+ }
+
+ appendClassName = appendClassName.trim();
+
+ stylesIndexMap.set(styleNames, appendClassName);
+
+ return appendClassName;
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..552029b
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,77 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _isFunction2 = require('lodash/isFunction');
+
+var _isFunction3 = _interopRequireDefault(_isFunction2);
+
+var _extendReactClass = require('./extendReactClass');
+
+var _extendReactClass2 = _interopRequireDefault(_extendReactClass);
+
+var _wrapStatelessFunction = require('./wrapStatelessFunction');
+
+var _wrapStatelessFunction2 = _interopRequireDefault(_wrapStatelessFunction);
+
+var _makeConfiguration = require('./makeConfiguration');
+
+var _makeConfiguration2 = _interopRequireDefault(_makeConfiguration);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Determines if the given object has the signature of a class that inherits React.Component.
+ */
+
+
+/**
+ * @see https://github.com/gajus/react-css-modules#options
+ */
+var isReactComponent = function isReactComponent(maybeReactComponent) {
+ return 'prototype' in maybeReactComponent && (0, _isFunction3.default)(maybeReactComponent.prototype.render);
+};
+
+/**
+ * When used as a function.
+ */
+var functionConstructor = function functionConstructor(Component, defaultStyles, options) {
+ var decoratedClass = void 0;
+
+ var configuration = (0, _makeConfiguration2.default)(options);
+
+ if (isReactComponent(Component)) {
+ decoratedClass = (0, _extendReactClass2.default)(Component, defaultStyles, configuration);
+ } else {
+ decoratedClass = (0, _wrapStatelessFunction2.default)(Component, defaultStyles, configuration);
+ }
+
+ if (Component.displayName) {
+ decoratedClass.displayName = Component.displayName;
+ } else {
+ decoratedClass.displayName = Component.name;
+ }
+
+ return decoratedClass;
+};
+
+/**
+ * When used as a ES7 decorator.
+ */
+var decoratorConstructor = function decoratorConstructor(defaultStyles, options) {
+ return function (Component) {
+ return functionConstructor(Component, defaultStyles, options);
+ };
+};
+
+exports.default = function () {
+ if ((0, _isFunction3.default)(arguments.length <= 0 ? undefined : arguments[0])) {
+ return functionConstructor(arguments.length <= 0 ? undefined : arguments[0], arguments.length <= 1 ? undefined : arguments[1], arguments.length <= 2 ? undefined : arguments[2]);
+ } else {
+ return decoratorConstructor(arguments.length <= 0 ? undefined : arguments[0], arguments.length <= 1 ? undefined : arguments[1]);
+ }
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/isIterable.js b/dist/isIterable.js
new file mode 100644
index 0000000..d3d33d5
--- /dev/null
+++ b/dist/isIterable.js
@@ -0,0 +1,41 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _isObject2 = require('lodash/isObject');
+
+var _isObject3 = _interopRequireDefault(_isObject2);
+
+var _isFunction2 = require('lodash/isFunction');
+
+var _isFunction3 = _interopRequireDefault(_isFunction2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var ITERATOR_SYMBOL = typeof Symbol !== 'undefined' && (0, _isFunction3.default)(Symbol) && Symbol.iterator;
+var OLD_ITERATOR_SYMBOL = '@@iterator';
+
+/**
+ * @see https://github.com/lodash/lodash/issues/1668
+ * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols
+ */
+
+exports.default = function (maybeIterable) {
+ var iterator = void 0;
+
+ if (!(0, _isObject3.default)(maybeIterable)) {
+ return false;
+ }
+
+ if (ITERATOR_SYMBOL) {
+ iterator = maybeIterable[ITERATOR_SYMBOL];
+ } else {
+ iterator = maybeIterable[OLD_ITERATOR_SYMBOL];
+ }
+
+ return (0, _isFunction3.default)(iterator);
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/linkClass.js b/dist/linkClass.js
new file mode 100644
index 0000000..c73b88c
--- /dev/null
+++ b/dist/linkClass.js
@@ -0,0 +1,106 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _isObject2 = require('lodash/isObject');
+
+var _isObject3 = _interopRequireDefault(_isObject2);
+
+var _isArray2 = require('lodash/isArray');
+
+var _isArray3 = _interopRequireDefault(_isArray2);
+
+var _react = require('react');
+
+var _react2 = _interopRequireDefault(_react);
+
+var _objectUnfreeze = require('object-unfreeze');
+
+var _objectUnfreeze2 = _interopRequireDefault(_objectUnfreeze);
+
+var _isIterable = require('./isIterable');
+
+var _isIterable2 = _interopRequireDefault(_isIterable);
+
+var _parseStyleName = require('./parseStyleName');
+
+var _parseStyleName2 = _interopRequireDefault(_parseStyleName);
+
+var _generateAppendClassName = require('./generateAppendClassName');
+
+var _generateAppendClassName2 = _interopRequireDefault(_generateAppendClassName);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var linkElement = function linkElement(element, styles, configuration) {
+ var appendClassName = void 0,
+ elementIsFrozen = void 0,
+ elementShallowCopy = void 0;
+
+ elementShallowCopy = element;
+
+ if (Object.isFrozen && Object.isFrozen(elementShallowCopy)) {
+ elementIsFrozen = true;
+
+ // https://github.com/facebook/react/blob/v0.13.3/src/classic/element/ReactElement.js#L131
+ elementShallowCopy = (0, _objectUnfreeze2.default)(elementShallowCopy);
+ elementShallowCopy.props = (0, _objectUnfreeze2.default)(elementShallowCopy.props);
+ }
+
+ var styleNames = (0, _parseStyleName2.default)(elementShallowCopy.props.styleName || '', configuration.allowMultiple);
+
+ if (_react2.default.isValidElement(elementShallowCopy.props.children)) {
+ elementShallowCopy.props.children = linkElement(_react2.default.Children.only(elementShallowCopy.props.children), styles, configuration);
+ } else if ((0, _isArray3.default)(elementShallowCopy.props.children) || (0, _isIterable2.default)(elementShallowCopy.props.children)) {
+ elementShallowCopy.props.children = _react2.default.Children.map(elementShallowCopy.props.children, function (node) {
+ if (_react2.default.isValidElement(node)) {
+ return linkElement(node, styles, configuration);
+ } else {
+ return node;
+ }
+ });
+ }
+
+ if (styleNames.length) {
+ appendClassName = (0, _generateAppendClassName2.default)(styles, styleNames, configuration.errorWhenNotFound);
+
+ if (appendClassName) {
+ if (elementShallowCopy.props.className) {
+ appendClassName = elementShallowCopy.props.className + ' ' + appendClassName;
+ }
+
+ elementShallowCopy.props.className = appendClassName;
+ }
+ }
+
+ delete elementShallowCopy.props.styleName;
+
+ if (elementIsFrozen) {
+ Object.freeze(elementShallowCopy.props);
+ Object.freeze(elementShallowCopy);
+ }
+
+ return elementShallowCopy;
+};
+
+/**
+ * @param {ReactElement} element
+ * @param {Object} styles CSS modules class map.
+ * @param {CSSModules~Options} configuration
+ */
+
+exports.default = function (element) {
+ var styles = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+ var configuration = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
+
+ // @see https://github.com/gajus/react-css-modules/pull/30
+ if (!(0, _isObject3.default)(element)) {
+ return element;
+ }
+
+ return linkElement(element, styles, configuration);
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/makeConfiguration.js b/dist/makeConfiguration.js
new file mode 100644
index 0000000..a8bbc81
--- /dev/null
+++ b/dist/makeConfiguration.js
@@ -0,0 +1,55 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _isBoolean2 = require('lodash/isBoolean');
+
+var _isBoolean3 = _interopRequireDefault(_isBoolean2);
+
+var _isUndefined2 = require('lodash/isUndefined');
+
+var _isUndefined3 = _interopRequireDefault(_isUndefined2);
+
+var _forEach2 = require('lodash/forEach');
+
+var _forEach3 = _interopRequireDefault(_forEach2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * @typedef CSSModules~Options
+ * @see {@link https://github.com/gajus/react-css-modules#options}
+ * @property {boolean} allowMultiple
+ * @property {boolean} errorWhenNotFound
+ */
+
+/**
+ * @param {CSSModules~Options} userConfiguration
+ * @returns {CSSModules~Options}
+ */
+exports.default = function () {
+ var userConfiguration = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ var configuration = {
+ allowMultiple: false,
+ errorWhenNotFound: true
+ };
+
+ (0, _forEach3.default)(userConfiguration, function (value, name) {
+ if ((0, _isUndefined3.default)(configuration[name])) {
+ throw new Error('Unknown configuration property "' + name + '".');
+ }
+
+ if (!(0, _isBoolean3.default)(value)) {
+ throw new Error('"' + name + '" property value must be a boolean.');
+ }
+
+ configuration[name] = value;
+ });
+
+ return configuration;
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/parseStyleName.js b/dist/parseStyleName.js
new file mode 100644
index 0000000..8a8be42
--- /dev/null
+++ b/dist/parseStyleName.js
@@ -0,0 +1,38 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _filter2 = require('lodash/filter');
+
+var _filter3 = _interopRequireDefault(_filter2);
+
+var _trim2 = require('lodash/trim');
+
+var _trim3 = _interopRequireDefault(_trim2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var styleNameIndex = {};
+
+exports.default = function (styleNamePropertyValue, allowMultiple) {
+ var styleNames = void 0;
+
+ if (styleNameIndex[styleNamePropertyValue]) {
+ styleNames = styleNameIndex[styleNamePropertyValue];
+ } else {
+ styleNames = (0, _trim3.default)(styleNamePropertyValue).split(' ');
+ styleNames = (0, _filter3.default)(styleNames);
+
+ styleNameIndex[styleNamePropertyValue] = styleNames;
+ }
+
+ if (allowMultiple === false && styleNames.length > 1) {
+ throw new Error('ReactElement styleName property defines multiple module names ("' + styleNamePropertyValue + '").');
+ }
+
+ return styleNames;
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/dist/simple-map.js b/dist/simple-map.js
new file mode 100644
index 0000000..33db5e6
--- /dev/null
+++ b/dist/simple-map.js
@@ -0,0 +1,44 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var SimpleMap = exports.SimpleMap = function () {
+ function SimpleMap() {
+ _classCallCheck(this, SimpleMap);
+
+ this.keys = [];
+ this.values = [];
+ }
+
+ SimpleMap.prototype.get = function get(key) {
+ var index = this.keys.indexOf(key);
+
+ return this.values[index];
+ };
+
+ SimpleMap.prototype.set = function set(key, value) {
+ this.keys.push(key);
+ this.values.push(value);
+
+ return value;
+ };
+
+ _createClass(SimpleMap, [{
+ key: 'size',
+ get: function get() {
+ return this.keys.length;
+ }
+ }]);
+
+ return SimpleMap;
+}();
+
+var exportedMap = typeof Map === 'undefined' ? SimpleMap : Map;
+
+exports.default = exportedMap;
\ No newline at end of file
diff --git a/dist/wrapStatelessFunction.js b/dist/wrapStatelessFunction.js
new file mode 100644
index 0000000..9948dc2
--- /dev/null
+++ b/dist/wrapStatelessFunction.js
@@ -0,0 +1,69 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _assign2 = require('lodash/assign');
+
+var _assign3 = _interopRequireDefault(_assign2);
+
+var _isObject2 = require('lodash/isObject');
+
+var _isObject3 = _interopRequireDefault(_isObject2);
+
+var _react = require('react');
+
+var _react2 = _interopRequireDefault(_react);
+
+var _linkClass = require('./linkClass');
+
+var _linkClass2 = _interopRequireDefault(_linkClass);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components
+ */
+/* eslint-disable react/prop-types */
+
+exports.default = function (Component, defaultStyles, options) {
+ var WrappedComponent = function WrappedComponent() {
+ for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ var props = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ var styles = void 0,
+ useProps = void 0;
+
+ if (props.styles) {
+ useProps = props;
+ styles = props.styles;
+ } else if ((0, _isObject3.default)(defaultStyles)) {
+ useProps = (0, _assign3.default)({}, props, {
+ styles: defaultStyles
+ });
+
+ styles = defaultStyles;
+ } else {
+ useProps = props;
+ styles = {};
+ }
+
+ var renderResult = Component.apply(undefined, [useProps].concat(args));
+
+ if (renderResult) {
+ return (0, _linkClass2.default)(renderResult, styles, options);
+ }
+
+ return _react2.default.createElement('noscript');
+ };
+
+ (0, _assign3.default)(WrappedComponent, Component);
+
+ return WrappedComponent;
+};
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/package.json b/package.json
index 00e1ffa..383dd4b 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "react-css-modules",
"description": "Seamless mapping of class names to CSS modules inside of React components.",
- "main": "./dist/index.js",
+ "main": "./dist/",
"repository": {
"type": "git",
"url": "https://github.com/gajus/react-css-modules"
@@ -12,7 +12,7 @@
"css",
"modules"
],
- "version": "4.3.0",
+ "version": "3.7.9",
"author": {
"name": "Gajus Kuizinas",
"email": "gajus@gajus.com",
@@ -20,36 +20,32 @@
},
"license": "BSD-3-Clause",
"dependencies": {
- "hoist-non-react-statics": "^2.5.5",
- "lodash": "^4.16.6",
- "object-unfreeze": "^1.1.0"
+ "hoist-non-react-statics": "^1.0.5",
+ "lodash": "^4.6.1",
+ "object-unfreeze": "^1.0.2"
},
"devDependencies": {
- "babel-cli": "^6.18.0",
+ "babel-cli": "^6.10.1",
"babel-plugin-add-module-exports": "^0.2.1",
- "babel-plugin-lodash": "^3.2.9",
+ "babel-plugin-lodash": "^3.2.5",
"babel-plugin-transform-proto-to-assign": "^6.9.0",
- "babel-preset-es2015": "^6.18.0",
- "babel-preset-react": "^6.16.0",
- "babel-preset-stage-0": "^6.16.0",
- "babel-register": "^6.18.0",
- "chai": "^4.0.0-canary.1",
- "chai-spies": "^0.7.1",
- "eslint": "^3.10.0",
- "eslint-config-canonical": "^5.5.0",
- "husky": "^0.11.9",
- "jsdom": "^9.8.3",
- "mocha": "^3.1.2",
- "react": "^15.4.0-rc.4",
- "react-addons-shallow-compare": "^15.4.0-rc.4",
- "react-addons-test-utils": "^15.4.0-rc.4",
- "react-dom": "^15.4.0-rc.4",
- "semantic-release": "^6.3.2"
+ "babel-preset-es2015": "^6.9.0",
+ "babel-preset-react": "^6.11.1",
+ "babel-preset-stage-0": "^6.5.0",
+ "babel-register": "^6.9.0",
+ "chai": "^3.5.0",
+ "eslint": "^3.0.0",
+ "eslint-config-canonical": "^1.7.12",
+ "jsdom": "^8.1.0",
+ "mocha": "^2.5.3",
+ "react": "^15.0.0-rc.1",
+ "react-addons-shallow-compare": "^15.0.0-rc.1",
+ "react-addons-test-utils": "^15.0.0-rc.1",
+ "react-dom": "^15.0.0-rc.1"
},
"scripts": {
"lint": "eslint ./src ./tests",
- "test": "NODE_ENV=development mocha --compilers js:babel-register ./tests/**/*.js && npm run lint && npm run build",
- "build": "NODE_ENV=production babel ./src --out-dir ./dist",
- "precommit": "npm run test"
+ "test": "mocha --compilers js:babel-register ./tests/**/*.js",
+ "build": "babel ./src --out-dir ./dist"
}
-}
+}
\ No newline at end of file
diff --git a/src/SimpleMap.js b/src/SimpleMap.js
deleted file mode 100644
index 7cf618b..0000000
--- a/src/SimpleMap.js
+++ /dev/null
@@ -1,21 +0,0 @@
-export default class {
- constructor () {
- this.size = 0;
- this.keys = [];
- this.values = [];
- }
-
- get (key) {
- const index = this.keys.indexOf(key);
-
- return this.values[index];
- }
-
- set (key, value) {
- this.keys.push(key);
- this.values.push(value);
- this.size = this.keys.length;
-
- return value;
- }
-}
diff --git a/src/extendReactClass.js b/src/extendReactClass.js
index 4741bea..b5cfb2d 100644
--- a/src/extendReactClass.js
+++ b/src/extendReactClass.js
@@ -1,10 +1,9 @@
/* eslint-disable react/prop-types */
-import _ from 'lodash';
import React from 'react';
+import _ from 'lodash';
import hoistNonReactStatics from 'hoist-non-react-statics';
import linkClass from './linkClass';
-import renderNothing from './renderNothing';
/**
* @param {ReactClass} Component
@@ -13,62 +12,39 @@ import renderNothing from './renderNothing';
* @returns {ReactClass}
*/
export default (Component: Object, defaultStyles: Object, options: Object) => {
- const WrappedComponent = class extends Component {
- render () {
- let styles;
-
- const hasDefaultstyles = _.isObject(defaultStyles);
+ const WrappedComponent = class extends Component {
+ render () {
+ let propsChanged,
+ styles;
- let renderResult;
-
- if (this.props.styles || hasDefaultstyles) {
- const props = Object.assign({}, this.props);
-
- if (props.styles) {
- styles = props.styles;
- } else if (hasDefaultstyles) {
- styles = defaultStyles;
- delete props.styles;
- }
+ propsChanged = false;
- Object.defineProperty(props, 'styles', {
- configurable: true,
- enumerable: false,
- value: styles,
- writable: false
- });
+ if (this.props.styles) {
+ styles = this.props.styles;
+ } else if (_.isObject(defaultStyles)) {
+ this.props = _.assign({}, this.props, {
+ styles: defaultStyles
+ });
- const originalProps = this.props;
+ propsChanged = true;
+ styles = defaultStyles;
+ } else {
+ styles = {};
+ }
- let renderIsSuccessful = false;
+ const renderResult = super.render();
- try {
- this.props = props;
+ if (propsChanged) {
+ delete this.props.styles;
+ }
- renderResult = super.render();
+ if (renderResult) {
+ return linkClass(renderResult, styles, options);
+ }
- renderIsSuccessful = true;
- } finally {
- this.props = originalProps;
+ return React.createElement('noscript');
}
+ };
- // @see https://github.com/facebook/react/issues/14224
- if (!renderIsSuccessful) {
- renderResult = super.render();
- }
- } else {
- styles = {};
-
- renderResult = super.render();
- }
-
- if (renderResult) {
- return linkClass(renderResult, styles, options);
- }
-
- return renderNothing(React.version);
- }
- };
-
- return hoistNonReactStatics(WrappedComponent, Component);
+ return hoistNonReactStatics(WrappedComponent, Component);
};
diff --git a/src/generateAppendClassName.js b/src/generateAppendClassName.js
index 127aa2a..3bbb23f 100644
--- a/src/generateAppendClassName.js
+++ b/src/generateAppendClassName.js
@@ -1,49 +1,41 @@
-import SimpleMap from './SimpleMap';
+import Map from './simple-map';
-const CustomMap = typeof Map === 'undefined' ? SimpleMap : Map;
+const stylesIndex = new Map();
-const stylesIndex = new CustomMap();
+export default (styles, styleNames: Array, errorWhenNotFound: boolean): string => {
+ let appendClassName,
+ stylesIndexMap;
-export default (styles, styleNames: Array, handleNotFoundStyleName: "throw" | "log" | "ignore"): string => {
- let appendClassName;
- let stylesIndexMap;
+ stylesIndexMap = stylesIndex.get(styles);
- stylesIndexMap = stylesIndex.get(styles);
+ if (stylesIndexMap) {
+ const styleNameIndex = stylesIndexMap.get(styleNames);
- if (stylesIndexMap) {
- const styleNameIndex = stylesIndexMap.get(styleNames);
-
- if (styleNameIndex) {
- return styleNameIndex;
- }
- } else {
- stylesIndexMap = new CustomMap();
- stylesIndex.set(styles, new CustomMap());
- }
-
- appendClassName = '';
-
- for (const styleName in styleNames) {
- if (styleNames.hasOwnProperty(styleName)) {
- const className = styles[styleNames[styleName]];
-
- if (className) {
- appendClassName += ' ' + className;
- } else {
- if (handleNotFoundStyleName === 'throw') {
- throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.');
+ if (styleNameIndex) {
+ return styleNameIndex;
}
- if (handleNotFoundStyleName === 'log') {
- // eslint-disable-next-line no-console
- console.warn('"' + styleNames[styleName] + '" CSS module is undefined.');
+ } else {
+ stylesIndexMap = new Map();
+ stylesIndex.set(styles, new Map());
+ }
+
+ appendClassName = '';
+
+ for (const styleName in styleNames) {
+ if (styleNames.hasOwnProperty(styleName)) {
+ const className = styles[styleNames[styleName]];
+
+ if (className) {
+ appendClassName += ' ' + className;
+ } else if (errorWhenNotFound === true) {
+ throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.');
+ }
}
- }
}
- }
- appendClassName = appendClassName.trim();
+ appendClassName = appendClassName.trim();
- stylesIndexMap.set(styleNames, appendClassName);
+ stylesIndexMap.set(styleNames, appendClassName);
- return appendClassName;
+ return appendClassName;
};
diff --git a/src/index.js b/src/index.js
index b913b29..7ee7e4e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,45 +12,45 @@ type TypeOptions = {};
* Determines if the given object has the signature of a class that inherits React.Component.
*/
const isReactComponent = (maybeReactComponent: any): boolean => {
- return 'prototype' in maybeReactComponent && _.isFunction(maybeReactComponent.prototype.render);
+ return 'prototype' in maybeReactComponent && _.isFunction(maybeReactComponent.prototype.render);
};
/**
* When used as a function.
*/
const functionConstructor = (Component: Function, defaultStyles: Object, options: TypeOptions): Function => {
- let decoratedClass;
+ let decoratedClass;
- const configuration = makeConfiguration(options);
+ const configuration = makeConfiguration(options);
- if (isReactComponent(Component)) {
- decoratedClass = extendReactClass(Component, defaultStyles, configuration);
- } else {
- decoratedClass = wrapStatelessFunction(Component, defaultStyles, configuration);
- }
+ if (isReactComponent(Component)) {
+ decoratedClass = extendReactClass(Component, defaultStyles, configuration);
+ } else {
+ decoratedClass = wrapStatelessFunction(Component, defaultStyles, configuration);
+ }
- if (Component.displayName) {
- decoratedClass.displayName = Component.displayName;
- } else {
- decoratedClass.displayName = Component.name;
- }
+ if (Component.displayName) {
+ decoratedClass.displayName = Component.displayName;
+ } else {
+ decoratedClass.displayName = Component.name;
+ }
- return decoratedClass;
+ return decoratedClass;
};
/**
* When used as a ES7 decorator.
*/
const decoratorConstructor = (defaultStyles: Object, options: TypeOptions): Function => {
- return (Component: Function) => {
- return functionConstructor(Component, defaultStyles, options);
- };
+ return (Component: Function) => {
+ return functionConstructor(Component, defaultStyles, options);
+ };
};
export default (...args) => {
- if (_.isFunction(args[0])) {
- return functionConstructor(args[0], args[1], args[2]);
- } else {
- return decoratorConstructor(args[0], args[1]);
- }
+ if (_.isFunction(args[0])) {
+ return functionConstructor(args[0], args[1], args[2]);
+ } else {
+ return decoratorConstructor(args[0], args[1]);
+ }
};
diff --git a/src/isIterable.js b/src/isIterable.js
index 67d0a94..2c800b1 100644
--- a/src/isIterable.js
+++ b/src/isIterable.js
@@ -8,17 +8,17 @@ const OLD_ITERATOR_SYMBOL = '@@iterator';
* @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols
*/
export default (maybeIterable: any): boolean => {
- let iterator;
+ let iterator;
- if (!_.isObject(maybeIterable)) {
- return false;
- }
+ if (!_.isObject(maybeIterable)) {
+ return false;
+ }
- if (ITERATOR_SYMBOL) {
- iterator = maybeIterable[ITERATOR_SYMBOL];
- } else {
- iterator = maybeIterable[OLD_ITERATOR_SYMBOL];
- }
+ if (ITERATOR_SYMBOL) {
+ iterator = maybeIterable[ITERATOR_SYMBOL];
+ } else {
+ iterator = maybeIterable[OLD_ITERATOR_SYMBOL];
+ }
- return _.isFunction(iterator);
+ return _.isFunction(iterator);
};
diff --git a/src/linkClass.js b/src/linkClass.js
index 4ed3975..ea199e9 100644
--- a/src/linkClass.js
+++ b/src/linkClass.js
@@ -7,88 +7,55 @@ import isIterable from './isIterable';
import parseStyleName from './parseStyleName';
import generateAppendClassName from './generateAppendClassName';
-const linkArray = (array: Array, styles: Object, configuration: Object) => {
- _.forEach(array, (value, index) => {
- if (React.isValidElement(value)) {
- // eslint-disable-next-line no-use-before-define
- array[index] = linkElement(React.Children.only(value), styles, configuration);
- } else if (_.isArray(value)) {
- const unfreezedValue = Object.isFrozen(value) ? objectUnfreeze(value) : value;
-
- array[index] = linkArray(unfreezedValue, styles, configuration);
- }
- });
-
- return array;
-};
-
const linkElement = (element: ReactElement, styles: Object, configuration: Object): ReactElement => {
- let appendClassName;
- let elementShallowCopy;
-
- elementShallowCopy = element;
+ let appendClassName,
+ elementIsFrozen,
+ elementShallowCopy;
- if (Array.isArray(elementShallowCopy)) {
- return elementShallowCopy.map((arrayElement) => {
- return linkElement(arrayElement, styles, configuration);
- });
- }
+ elementShallowCopy = element;
- const elementIsFrozen = Object.isFrozen && Object.isFrozen(elementShallowCopy);
- const propsFrozen = Object.isFrozen && Object.isFrozen(elementShallowCopy.props);
- const propsNotExtensible = Object.isExtensible && !Object.isExtensible(elementShallowCopy.props);
+ if (Object.isFrozen && Object.isFrozen(elementShallowCopy)) {
+ elementIsFrozen = true;
- if (elementIsFrozen) {
- // https://github.com/facebook/react/blob/v0.13.3/src/classic/element/ReactElement.js#L131
- elementShallowCopy = objectUnfreeze(elementShallowCopy);
- elementShallowCopy.props = objectUnfreeze(elementShallowCopy.props);
- } else if (propsFrozen || propsNotExtensible) {
- elementShallowCopy.props = objectUnfreeze(elementShallowCopy.props);
- }
-
- const styleNames = parseStyleName(elementShallowCopy.props.styleName || '', configuration.allowMultiple);
- const {children, ...restProps} = elementShallowCopy.props;
-
- if (React.isValidElement(children)) {
- elementShallowCopy.props.children = linkElement(React.Children.only(children), styles, configuration);
- } else if (_.isArray(children) || isIterable(children)) {
- elementShallowCopy.props.children = linkArray(objectUnfreeze(children), styles, configuration);
- }
+ // https://github.com/facebook/react/blob/v0.13.3/src/classic/element/ReactElement.js#L131
+ elementShallowCopy = objectUnfreeze(elementShallowCopy);
+ elementShallowCopy.props = objectUnfreeze(elementShallowCopy.props);
+ }
- _.forEach(restProps, (propValue, propName) => {
- if (React.isValidElement(propValue)) {
- elementShallowCopy.props[propName] = linkElement(React.Children.only(propValue), styles, configuration);
- } else if (_.isArray(propValue)) {
- elementShallowCopy.props[propName] = linkArray(propValue, styles, configuration);
+ const styleNames = parseStyleName(elementShallowCopy.props.styleName || '', configuration.allowMultiple);
+
+ if (React.isValidElement(elementShallowCopy.props.children)) {
+ elementShallowCopy.props.children = linkElement(React.Children.only(elementShallowCopy.props.children), styles, configuration);
+ } else if (_.isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) {
+ elementShallowCopy.props.children = React.Children.map(elementShallowCopy.props.children, (node) => {
+ if (React.isValidElement(node)) {
+ return linkElement(node, styles, configuration);
+ } else {
+ return node;
+ }
+ });
}
- });
- if (styleNames.length) {
- appendClassName = generateAppendClassName(styles, styleNames, configuration.handleNotFoundStyleName);
+ if (styleNames.length) {
+ appendClassName = generateAppendClassName(styles, styleNames, configuration.errorWhenNotFound);
- if (appendClassName) {
- if (elementShallowCopy.props.className) {
- appendClassName = elementShallowCopy.props.className + ' ' + appendClassName;
- }
+ if (appendClassName) {
+ if (elementShallowCopy.props.className) {
+ appendClassName = elementShallowCopy.props.className + ' ' + appendClassName;
+ }
- elementShallowCopy.props.className = appendClassName;
+ elementShallowCopy.props.className = appendClassName;
+ }
}
- }
- delete elementShallowCopy.props.styleName;
+ delete elementShallowCopy.props.styleName;
- if (elementIsFrozen) {
- Object.freeze(elementShallowCopy.props);
- Object.freeze(elementShallowCopy);
- } else if (propsFrozen) {
- Object.freeze(elementShallowCopy.props);
- }
-
- if (propsNotExtensible) {
- Object.preventExtensions(elementShallowCopy.props);
- }
+ if (elementIsFrozen) {
+ Object.freeze(elementShallowCopy.props);
+ Object.freeze(elementShallowCopy);
+ }
- return elementShallowCopy;
+ return elementShallowCopy;
};
/**
@@ -98,9 +65,9 @@ const linkElement = (element: ReactElement, styles: Object, configuration: Objec
*/
export default (element: ReactElement, styles = {}, configuration = {}): ReactElement => {
// @see https://github.com/gajus/react-css-modules/pull/30
- if (!_.isObject(element)) {
- return element;
- }
+ if (!_.isObject(element)) {
+ return element;
+ }
- return linkElement(element, styles, configuration);
+ return linkElement(element, styles, configuration);
};
diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js
index cc3169c..83b2d41 100644
--- a/src/makeConfiguration.js
+++ b/src/makeConfiguration.js
@@ -4,7 +4,7 @@ import _ from 'lodash';
* @typedef CSSModules~Options
* @see {@link https://github.com/gajus/react-css-modules#options}
* @property {boolean} allowMultiple
- * @property {string} handleNotFoundStyleName
+ * @property {boolean} errorWhenNotFound
*/
/**
@@ -12,26 +12,22 @@ import _ from 'lodash';
* @returns {CSSModules~Options}
*/
export default (userConfiguration = {}) => {
- const configuration = {
- allowMultiple: false,
- handleNotFoundStyleName: 'throw'
- };
+ const configuration = {
+ allowMultiple: false,
+ errorWhenNotFound: true
+ };
- _.forEach(userConfiguration, (value, name) => {
- if (_.isUndefined(configuration[name])) {
- throw new Error('Unknown configuration property "' + name + '".');
- }
+ _.forEach(userConfiguration, (value, name) => {
+ if (_.isUndefined(configuration[name])) {
+ throw new Error('Unknown configuration property "' + name + '".');
+ }
- if (name === 'allowMultiple' && !_.isBoolean(value)) {
- throw new Error('"allowMultiple" property value must be a boolean.');
- }
+ if (!_.isBoolean(value)) {
+ throw new Error('"' + name + '" property value must be a boolean.');
+ }
- if (name === 'handleNotFoundStyleName' && !_.includes(['throw', 'log', 'ignore'], value)) {
- throw new Error('"handleNotFoundStyleName" property value must be "throw", "log" or "ignore".');
- }
+ configuration[name] = value;
+ });
- configuration[name] = value;
- });
-
- return configuration;
+ return configuration;
};
diff --git a/src/parseStyleName.js b/src/parseStyleName.js
index 937b2d6..39c328a 100644
--- a/src/parseStyleName.js
+++ b/src/parseStyleName.js
@@ -3,20 +3,20 @@ import _ from 'lodash';
const styleNameIndex = {};
export default (styleNamePropertyValue: string, allowMultiple: boolean): Array => {
- let styleNames;
+ let styleNames;
- if (styleNameIndex[styleNamePropertyValue]) {
- styleNames = styleNameIndex[styleNamePropertyValue];
- } else {
- styleNames = _.trim(styleNamePropertyValue).split(/\s+/);
- styleNames = _.filter(styleNames);
+ if (styleNameIndex[styleNamePropertyValue]) {
+ styleNames = styleNameIndex[styleNamePropertyValue];
+ } else {
+ styleNames = _.trim(styleNamePropertyValue).split(' ');
+ styleNames = _.filter(styleNames);
- styleNameIndex[styleNamePropertyValue] = styleNames;
- }
+ styleNameIndex[styleNamePropertyValue] = styleNames;
+ }
- if (allowMultiple === false && styleNames.length > 1) {
- throw new Error('ReactElement styleName property defines multiple module names ("' + styleNamePropertyValue + '").');
- }
+ if (allowMultiple === false && styleNames.length > 1) {
+ throw new Error('ReactElement styleName property defines multiple module names ("' + styleNamePropertyValue + '").');
+ }
- return styleNames;
+ return styleNames;
};
diff --git a/src/renderNothing.js b/src/renderNothing.js
deleted file mode 100644
index 93675fe..0000000
--- a/src/renderNothing.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from 'react';
-
-export default function (version) {
- const major = version.split('.')[0];
-
- return parseInt(major, 10) < 15 ? React.createElement('noscript') : null;
-}
diff --git a/src/simple-map.js b/src/simple-map.js
new file mode 100644
index 0000000..4582e33
--- /dev/null
+++ b/src/simple-map.js
@@ -0,0 +1,27 @@
+export class SimpleMap {
+ constructor () {
+ this.keys = [];
+ this.values = [];
+ }
+
+ get size () {
+ return this.keys.length;
+ }
+
+ get (key) {
+ const index = this.keys.indexOf(key);
+
+ return this.values[index];
+ }
+
+ set (key, value) {
+ this.keys.push(key);
+ this.values.push(value);
+
+ return value;
+ }
+}
+
+const exportedMap = typeof Map === 'undefined' ? SimpleMap : Map;
+
+export default exportedMap;
diff --git a/src/wrapStatelessFunction.js b/src/wrapStatelessFunction.js
index b6b9162..878119a 100644
--- a/src/wrapStatelessFunction.js
+++ b/src/wrapStatelessFunction.js
@@ -3,47 +3,39 @@
import _ from 'lodash';
import React from 'react';
import linkClass from './linkClass';
-import renderNothing from './renderNothing';
/**
* @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components
*/
export default (Component: Function, defaultStyles: Object, options: Object): Function => {
- const WrappedComponent = (props = {}, ...args) => {
- let styles;
- let useProps;
- const hasDefaultstyles = _.isObject(defaultStyles);
-
- if (props.styles || hasDefaultstyles) {
- useProps = Object.assign({}, props);
-
- if (props.styles) {
- styles = props.styles;
- } else {
- styles = defaultStyles;
- }
-
- Object.defineProperty(useProps, 'styles', {
- configurable: true,
- enumerable: false,
- value: styles,
- writable: false
- });
- } else {
- useProps = props;
- styles = {};
- }
-
- const renderResult = Component(useProps, ...args);
-
- if (renderResult) {
- return linkClass(renderResult, styles, options);
- }
-
- return renderNothing(React.version);
- };
-
- _.assign(WrappedComponent, Component);
-
- return WrappedComponent;
+ const WrappedComponent = (props = {}, ...args) => {
+ let styles,
+ useProps;
+
+ if (props.styles) {
+ useProps = props;
+ styles = props.styles;
+ } else if (_.isObject(defaultStyles)) {
+ useProps = _.assign({}, props, {
+ styles: defaultStyles
+ });
+
+ styles = defaultStyles;
+ } else {
+ useProps = props;
+ styles = {};
+ }
+
+ const renderResult = Component(useProps, ...args);
+
+ if (renderResult) {
+ return linkClass(renderResult, styles, options);
+ }
+
+ return React.createElement('noscript');
+ };
+
+ _.assign(WrappedComponent, Component);
+
+ return WrappedComponent;
};
diff --git a/tests/SimpleMap.js b/tests/SimpleMap.js
deleted file mode 100644
index 08ca888..0000000
--- a/tests/SimpleMap.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import {
- expect
-} from 'chai';
-import SimpleMap from './../src/SimpleMap';
-
-describe('SimpleMap', () => {
- context('simple map with primitive or object as keys', () => {
- const values = [
- [1, 'something'],
- ['1', 'somethingElse'],
- [{}, []],
- [null, null]
- ];
-
- let map;
-
- beforeEach(() => {
- map = new SimpleMap();
- });
-
- it('should set', () => {
- values.forEach(([key, value]) => {
- map.set(key, value);
- });
- expect(map.size).to.equal(values.length);
- });
-
- it('should get', () => {
- values.forEach(([key, value]) => {
- map.set(key, value);
- });
-
- values.forEach(([key, value]) => {
- expect(map.get(key)).to.equal(value);
- });
- });
- });
-});
diff --git a/tests/extendReactClass.js b/tests/extendReactClass.js
deleted file mode 100644
index 01733ee..0000000
--- a/tests/extendReactClass.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/* eslint-disable max-nested-callbacks, react/prefer-stateless-function, react/prop-types, react/no-multi-comp, class-methods-use-this */
-
-import {
- expect
-} from 'chai';
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import shallowCompare from 'react-addons-shallow-compare';
-import jsdom from 'jsdom';
-import extendReactClass from './../src/extendReactClass';
-
-describe('extendReactClass', () => {
- beforeEach(() => {
- global.document = jsdom.jsdom('');
-
- global.window = document.defaultView;
- });
- context('using default styles', () => {
- it('exposes styles through this.props.styles property', (done) => {
- let Component;
-
- const styles = {
- foo: 'foo-1'
- };
-
- Component = class extends React.Component {
- render () {
- expect(this.props.styles).to.equal(styles);
- done();
- }
- };
-
- Component = extendReactClass(Component, styles);
-
- TestUtils.renderIntoDocument();
- });
- it('exposes non-enumerable styles property', (done) => {
- let Component;
-
- const styles = {
- foo: 'foo-1'
- };
-
- Component = class extends React.Component {
- render () {
- expect(this.props.propertyIsEnumerable('styles')).to.equal(false);
- done();
- }
- };
-
- Component = extendReactClass(Component, styles);
-
- TestUtils.renderIntoDocument();
- });
- it('does not affect the other instance properties', (done) => {
- let Component;
-
- Component = class extends React.Component {
- render () {
- expect(this.props.bar).to.equal('baz');
- done();
- }
- };
-
- const styles = {
- foo: 'foo-1'
- };
-
- Component = extendReactClass(Component, styles);
-
- TestUtils.renderIntoDocument();
- });
- it('does not affect pure-render logic', (done) => {
- let Component;
- let rendered;
-
- rendered = false;
-
- const styles = {
- foo: 'foo-1'
- };
-
- Component = class extends React.Component {
- shouldComponentUpdate (newProps) {
- if (rendered) {
- expect(shallowCompare(this.props, newProps)).to.equal(true);
-
- done();
- }
-
- return true;
- }
-
- render () {
- rendered = true;
- }
- };
-
- Component = extendReactClass(Component, styles);
-
- const instance = TestUtils.renderIntoDocument();
-
- // trigger shouldComponentUpdate
- instance.setState({});
- });
- });
- context('overwriting default styles using "styles" property of the extended component', () => {
- it('overwrites default styles', (done) => {
- let Component;
-
- const styles = {
- foo: 'foo-1'
- };
-
- Component = class extends React.Component {
- render () {
- expect(this.props.styles).to.equal(styles);
- done();
- }
- };
-
- Component = extendReactClass(Component, {
- bar: 'bar-0',
- foo: 'foo-0'
- });
-
- TestUtils.renderIntoDocument();
- });
- });
- context('rendering Component that returns null', () => {
- it('generates null', () => {
- let Component;
-
- const shallowRenderer = TestUtils.createRenderer();
-
- Component = class extends React.Component {
- render () {
- return null;
- }
- };
-
- Component = extendReactClass(Component);
-
- shallowRenderer.render();
-
- const component = shallowRenderer.getRenderOutput();
-
- expect(component).to.equal(null);
- });
- });
- context('target component have static properties', () => {
- it('hoists static properties', () => {
- const Component = class extends React.Component {
- static foo = 'FOO';
-
- render () {
- return null;
- }
- };
-
- const WrappedComponent = extendReactClass(Component);
-
- expect(Component.foo).to.equal('FOO');
- expect(WrappedComponent.foo).to.equal(Component.foo);
- });
- });
-});
diff --git a/tests/linkClass.js b/tests/linkClass.js
deleted file mode 100644
index cf7c289..0000000
--- a/tests/linkClass.js
+++ /dev/null
@@ -1,483 +0,0 @@
-/* eslint-disable max-nested-callbacks, react/prefer-stateless-function, class-methods-use-this, no-console, no-unused-expressions */
-
-import chai, {
- expect
-} from 'chai';
-import spies from 'chai-spies';
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import jsdom from 'jsdom';
-import linkClass from './../src/linkClass';
-
-chai.use(spies);
-
-describe('linkClass', () => {
- context('ReactElement does not define styleName', () => {
- it('does not affect element properties', () => {
- expect(linkClass()).to.deep.equal();
- });
-
- it('does not affect element properties with a single element child', () => {
- expect(linkClass()).to.deep.equal();
- });
-
- it('does not affect element properties with a single element child in non-`children` prop', () => {
- expect(linkClass(} />)).to.deep.equal(} />);
- });
-
- it('does not affect element properties with a single text child', () => {
- expect(linkClass(test
)).to.deep.equal(test
);
- });
-
- it('does not affect the className', () => {
- expect(linkClass()).to.deep.equal();
- });
-
- xit('does not affect element with a single children when that children is contained in an array', () => {
- const subject = React.createElement('div', null, [
- React.createElement('p')
- ]);
- const outcome = React.createElement('div', null, [
- React.createElement('p')
- ]);
-
- expect(linkClass(subject)).to.deep.equal(outcome);
- });
-
- xit('does not affect element with multiple children', () => {
- // Using array instead of object causes the following error:
- // Warning: Each child in an array or iterator should have a unique "key" prop.
- // Check the render method of _class. See https://fb.me/react-warning-keys for more information.
- // @see https://github.com/facebook/react/issues/4723#issuecomment-135555277
- // expect(linkClass()).to.deep.equal();
-
- const subject = React.createElement('div', null, [
- React.createElement('p'),
- React.createElement('p')
- ]);
- const outcome = React.createElement('div', null, [
- React.createElement('p'),
- React.createElement('p')
- ]);
-
- expect(linkClass(subject)).to.deep.equal(outcome);
- });
- });
-
- context('called with null instead of ReactElement', () => {
- it('returns null', () => {
- const subject = linkClass(null);
-
- expect(subject).to.equal(null);
- });
- });
-
- context('styleName matches an existing CSS module', () => {
- context('when a descendant element has styleName', () => {
- it('assigns a generated className', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject.props.children.props.className).to.equal('foo-1');
- });
- });
- context('when a descendant element in non-`children` prop has styleName', () => {
- it('assigns a generated className', () => {
- let subject;
-
- subject = }
- els={[, []]}
- />;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- baz: 'baz-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.el.props.className).to.equal('foo-1');
- expect(subject.props.els[0].props.className).to.equal('bar-1');
- expect(subject.props.els[1][0].props.className).to.equal('baz-1');
- });
- });
- context('when multiple descendant elements have styleName', () => {
- it('assigns a generated className', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0].props.className).to.equal('foo-1');
- expect(subject.props.children[1].props.className).to.equal('bar-1');
- });
- it('assigns a generated className to elements inside nested arrays', () => {
- let subject;
-
- subject =
- {[
- [
-
,
-
- ],
- [
-
,
-
- ]
- ]}
-
;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0][0].props.className).to.equal('foo-1');
- expect(subject.props.children[0][1].props.className).to.equal('bar-1');
-
- expect(subject.props.children[1][0].props.className).to.equal('foo-1');
- expect(subject.props.children[1][1].props.className).to.equal('bar-1');
- });
- it('styleName is deleted from props', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0].props).not.to.have.property('styleName');
- expect(subject.props.children[1].props).not.to.have.property('styleName');
- });
- it('preserves original keys', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0].key).to.equal('1');
- expect(subject.props.children[1].key).to.equal('2');
- });
- });
- context('when multiple descendants have styleName and are iterable', () => {
- it('assigns a generated className', () => {
- let subject;
-
- const iterable = {
- 0: ,
- 1: ,
- length: 2,
-
- // eslint-disable-next-line no-use-extend-native/no-use-extend-native
- [Symbol.iterator]: Array.prototype[Symbol.iterator]
- };
-
- subject = {iterable}
;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0].props.className).to.equal('foo-1');
- expect(subject.props.children[1].props.className).to.equal('bar-1');
- });
- });
- context('when non-`children` prop is an iterable', () => {
- it('it is left untouched', () => {
- let subject;
-
- const iterable = {
- 0: ,
- 1: ,
- length: 2,
-
- // eslint-disable-next-line no-use-extend-native/no-use-extend-native
- [Symbol.iterator]: Array.prototype[Symbol.iterator]
- };
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.els[0].props.styleName).to.equal('foo');
- expect(subject.props.els[1].props.styleName).to.equal('bar');
- expect(subject.props.els[0].props).not.to.have.property('className');
- expect(subject.props.els[1].props).not.to.have.property('className');
- });
- });
- context('when ReactElement does not have an existing className', () => {
- it('uses the generated class name to set the className property', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject.props.className).to.deep.equal('foo-1');
- });
- });
- context('when ReactElement has an existing className', () => {
- it('appends the generated class name to the className property', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1'
- });
-
- expect(subject.props.className).to.deep.equal('foo bar-1');
- });
- });
- });
-
- context('styleName includes multiple whitespace characters', () => {
- it('resolves CSS modules', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- }, {
- allowMultiple: true
- });
-
- expect(subject.props.children.props.className).to.equal('foo-1 bar-1');
- });
- });
-
- context('can\'t write to properties', () => {
- context('when the element is frozen', () => {
- it('adds className but is still frozen', () => {
- let subject;
-
- subject = ;
-
- Object.freeze(subject);
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject).to.be.frozen;
- expect(subject.props.className).to.equal('foo-1');
- });
- });
- context('when the element\'s props are frozen', () => {
- it('adds className and only props are still frozen', () => {
- let subject;
-
- subject = ;
-
- Object.freeze(subject.props);
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject.props).to.be.frozen;
- expect(subject.props.className).to.equal('foo-1');
- });
- });
- context('when the element\'s props are not extensible', () => {
- it('adds className and props are still not extensible', () => {
- let subject;
-
- subject = ;
-
- Object.preventExtensions(subject.props);
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject.props).to.not.be.extensible;
- expect(subject.props.className).to.equal('foo-1');
- });
- });
- });
-
- context('when element is an array', () => {
- it('handles each element individually', () => {
- let subject;
-
- subject = [
- ,
-
- ];
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- });
-
- expect(subject).to.be.an('array');
- expect(subject[0].props.className).to.equal('foo-1');
- expect(subject[1].props.children.props.className).to.equal('bar-1');
- });
- });
-
- describe('options.allowMultiple', () => {
- context('when multiple module names are used', () => {
- context('when false', () => {
- it('throws an error', () => {
- expect(() => {
- linkClass(, {}, {allowMultiple: false});
- }).to.throw(Error, 'ReactElement styleName property defines multiple module names ("foo bar").');
- });
- });
- context('when true', () => {
- it('appends a generated class name for every referenced CSS module', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- foo: 'foo-1'
- }, {
- allowMultiple: true
- });
-
- expect(subject.props.className).to.deep.equal('foo-1 bar-1');
- });
- });
- });
- });
-
- describe('options.handleNotFoundStyleName', () => {
- context('when styleName does not match an existing CSS module', () => {
- context('when throw', () => {
- it('throws an error', () => {
- expect(() => {
- linkClass(, {}, {handleNotFoundStyleName: 'throw'});
- }).to.throw(Error, '"foo" CSS module is undefined.');
- });
- });
- context('when log', () => {
- it('logs a warning to the console', () => {
- const warnSpy = chai.spy(() => {});
-
- console.warn = warnSpy;
- linkClass(, {}, {handleNotFoundStyleName: 'log'});
- expect(warnSpy).to.have.been.called();
- });
- });
- context('when ignore', () => {
- it('does not log a warning', () => {
- const warnSpy = chai.spy(() => {});
-
- console.warn = warnSpy;
- linkClass(, {}, {handleNotFoundStyleName: 'ignore'});
- expect(warnSpy).to.not.have.been.called();
- });
-
- it('does not throw an error', () => {
- expect(() => {
- linkClass(, {}, {handleNotFoundStyleName: 'ignore'});
- }).to.not.throw(Error, '"foo" CSS module is undefined.');
- });
- });
- });
- });
-
- context('when ReactElement includes ReactComponent', () => {
- let Foo;
- let nodeList;
-
- beforeEach(() => {
- global.document = jsdom.jsdom('');
- global.window = document.defaultView;
-
- Foo = class extends React.Component {
- render () {
- return Hello
;
- }
- };
-
- nodeList = TestUtils.renderIntoDocument(linkClass(
, {foo: 'foo-1'}));
- });
- it('processes ReactElement nodes', () => {
- expect(nodeList.className).to.equal('foo-1');
- });
- it('does not process ReactComponent nodes', () => {
- expect(nodeList.firstChild.className).to.equal('');
- });
- });
-
- it('deletes styleName property from the target element', () => {
- let subject;
-
- subject = ;
-
- subject = linkClass(subject, {
- foo: 'foo-1'
- });
-
- expect(subject.props.className).to.deep.equal('foo-1');
- expect(subject.props).not.to.have.property('styleName');
- });
-
- it('deletes styleName property from the target element (deep)', () => {
- let subject;
-
- subject = }
- els={[, []]}
- styleName='foo'
- >
-
-
- ;
-
- subject = linkClass(subject, {
- bar: 'bar-1',
- baz: 'baz-1',
- foo: 'foo-1'
- });
-
- expect(subject.props.children[0].props.className).to.deep.equal('bar-1');
- expect(subject.props.children[0].props).not.to.have.property('styleName');
- expect(subject.props.el.props.className).to.deep.equal('baz-1');
- expect(subject.props.el.props).not.to.have.property('styleName');
- expect(subject.props.els[0].props.className).to.deep.equal('foo-1');
- expect(subject.props.els[0].props).not.to.have.property('styleName');
- expect(subject.props.els[1][0].props.className).to.deep.equal('bar-1');
- expect(subject.props.els[1][0].props).not.to.have.property('styleName');
- });
-});
diff --git a/tests/makeConfiguration.js b/tests/makeConfiguration.js
deleted file mode 100644
index 4193311..0000000
--- a/tests/makeConfiguration.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* eslint-disable max-nested-callbacks */
-
-import {
- expect
-} from 'chai';
-import makeConfiguration from './../src/makeConfiguration';
-
-describe('makeConfiguration', () => {
- describe('when using default configuration', () => {
- let configuration;
-
- beforeEach(() => {
- configuration = makeConfiguration();
- });
- describe('allowMultiple property', () => {
- it('defaults to false', () => {
- expect(configuration.allowMultiple).to.equal(false);
- });
- });
- describe('handleNotFoundStyleName property', () => {
- it('defaults to "throw"', () => {
- expect(configuration.handleNotFoundStyleName).to.equal('throw');
- });
- });
- });
- describe('when unknown property is provided', () => {
- it('throws an error', () => {
- expect(() => {
- makeConfiguration({
- unknownProperty: true
- });
- }).to.throw(Error, 'Unknown configuration property "unknownProperty".');
- });
- });
- it('does not mutate user configuration', () => {
- const userConfiguration = {};
-
- makeConfiguration(userConfiguration);
-
- expect(userConfiguration).to.deep.equal({});
- });
-});
diff --git a/tests/reactCssModules.js b/tests/reactCssModules.js
deleted file mode 100644
index d484d95..0000000
--- a/tests/reactCssModules.js
+++ /dev/null
@@ -1,184 +0,0 @@
-/* eslint-disable max-nested-callbacks, react/no-multi-comp, react/prop-types, react/prefer-stateless-function, class-methods-use-this */
-
-import {
- expect
-} from 'chai';
-import React from 'react';
-import ReactDOM from 'react-dom';
-import TestUtils from 'react-addons-test-utils';
-import jsdom from 'jsdom';
-import reactCssModules from './../src/index';
-
-describe('reactCssModules', () => {
- context('a ReactComponent is decorated using react-css-modules', () => {
- it('inherits displayName', () => {
- let Foo;
-
- Foo = class extends React.Component {};
-
- // @todo https://phabricator.babeljs.io/T2779
- Foo.displayName = 'Bar';
-
- Foo = reactCssModules(Foo);
-
- expect(Foo.displayName).to.equal('Bar');
- });
- context('target component does not name displayName', () => {
- it('uses name for displayName', () => {
- let Foo;
-
- Foo = class Bar extends React.Component {};
-
- Foo = reactCssModules(Foo);
-
- expect(Foo.displayName).to.equal('Bar');
- });
- });
- });
- context('a ReactComponent renders an element with the styleName prop', () => {
- context('the component is a class that extends React.Component', () => {
- let Foo;
- let component;
-
- beforeEach(() => {
- const shallowRenderer = TestUtils.createRenderer();
-
- Foo = class extends React.Component {
- render () {
- return Hello
;
- }
- };
-
- Foo = reactCssModules(Foo, {
- foo: 'foo-1'
- });
-
- shallowRenderer.render();
-
- component = shallowRenderer.getRenderOutput();
- });
- it('that element should contain the equivalent className', () => {
- expect(component.props.className).to.equal('foo-1');
- });
- it('the styleName prop should be "consumed" in the process', () => {
- expect(component.props).not.to.have.property('styleName');
- });
- });
- context('the component is a stateless function component', () => {
- let Foo;
- let component;
-
- beforeEach(() => {
- const shallowRenderer = TestUtils.createRenderer();
-
- Foo = () => {
- return Hello
;
- };
-
- Foo = reactCssModules(Foo, {
- foo: 'foo-1'
- });
-
- shallowRenderer.render();
-
- component = shallowRenderer.getRenderOutput();
- });
- it('that element should contain the equivalent className', () => {
- expect(component.props.className).to.equal('foo-1');
- });
- it('the styleName prop should be "consumed" in the process', () => {
- expect(component.props).not.to.have.property('styleName');
- });
- });
- });
- context('a ReactComponent renders nothing', () => {
- context('the component is a class that extends React.Component', () => {
- it('linkClass must not intervene', () => {
- let Foo;
-
- const shallowRenderer = TestUtils.createRenderer();
-
- Foo = class extends React.Component {
- render () {
- return null;
- }
- };
-
- Foo = reactCssModules(Foo, {
- foo: 'foo-1'
- });
-
- shallowRenderer.render();
-
- const component = shallowRenderer.getRenderOutput();
-
- expect(typeof component).to.equal('object');
- });
- });
- context('the component is a stateless function component', () => {
- it('that element should contain the equivalent className', () => {
- let Foo;
-
- const shallowRenderer = TestUtils.createRenderer();
-
- Foo = () => {
- return null;
- };
-
- Foo = reactCssModules(Foo, {
- foo: 'foo-1'
- });
-
- shallowRenderer.render();
-
- const component = shallowRenderer.getRenderOutput();
-
- expect(typeof component).to.equal('object');
- });
- });
- });
- context('rendering element', () => {
- beforeEach(() => {
- global.document = jsdom.jsdom('');
-
- global.window = document.defaultView;
- });
- context('parent component is using react-css-modules and interpolates props.children', () => {
- // @see https://github.com/gajus/react-css-modules/issues/76
- it('unsets the styleName property', () => {
- let Bar;
- let Foo;
- let subject;
-
- Foo = class extends React.Component {
- render () {
- return
- foo
- ;
- }
- };
-
- Foo = reactCssModules(Foo, {
- test: 'foo-0'
- });
-
- Bar = class extends React.Component {
- render () {
- return {this.props.children}
;
- }
- };
-
- Bar = reactCssModules(Bar, {
- test: 'bar-0'
- });
-
- subject = TestUtils.renderIntoDocument();
-
- // eslint-disable-next-line react/no-find-dom-node
- subject = ReactDOM.findDOMNode(subject);
-
- expect(subject.firstChild.className).to.equal('foo-0');
- });
- });
- });
-});
diff --git a/tests/renderNothing.js b/tests/renderNothing.js
deleted file mode 100644
index 7a666e8..0000000
--- a/tests/renderNothing.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {
- expect
-} from 'chai';
-import renderNothing from '../src/renderNothing';
-
-describe('renderNothing', () => {
- context('renderNothing should return different node types for various React versions', () => {
- it('should return noscript tag for React v14 or lower', () => {
- expect(renderNothing('14.0.0').type).to.equal('noscript');
- });
-
- it('should return null for React v15 or higher', () => {
- expect(renderNothing('15.0.0')).to.equal(null);
- });
- });
-});
diff --git a/tests/wrapStatelessFunction.js b/tests/wrapStatelessFunction.js
deleted file mode 100644
index 9c71935..0000000
--- a/tests/wrapStatelessFunction.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* eslint-disable max-nested-callbacks */
-
-import {
- expect
-} from 'chai';
-import React from 'react';
-import TestUtils from 'react-addons-test-utils';
-import wrapStatelessFunction from './../src/wrapStatelessFunction';
-
-describe('wrapStatelessFunction', () => {
- it('hoists static own properties from the input component to the wrapped component', () => {
- const styles = {
- foo: 'foo-1'
- };
-
- const InnerComponent = () => {
- return null;
- };
-
- InnerComponent.propTypes = {};
- InnerComponent.defaultProps = {};
-
- const WrappedComponent = wrapStatelessFunction(InnerComponent, styles);
-
- expect(WrappedComponent.propTypes).to.equal(InnerComponent.propTypes);
- expect(WrappedComponent.defaultProps).to.equal(InnerComponent.defaultProps);
- expect(WrappedComponent.name).not.to.equal(InnerComponent.name);
- });
- context('using default styles', () => {
- it('exposes styles through styles property', (done) => {
- const styles = {
- foo: 'foo-1'
- };
-
- wrapStatelessFunction((props) => {
- expect(props.styles).to.equal(styles);
- done();
- }, styles)();
- });
- it('exposes non-enumerable styles property', (done) => {
- const styles = {
- foo: 'foo-1'
- };
-
- wrapStatelessFunction((props) => {
- expect(props.propertyIsEnumerable('styles')).to.equal(false);
- done();
- }, styles)();
- });
- it('does not affect the other instance properties', (done) => {
- const styles = {
- foo: 'foo-1'
- };
-
- wrapStatelessFunction((props) => {
- expect(props.bar).to.equal('baz');
- done();
- }, styles)({
- bar: 'baz'
- });
- });
- });
- context('using explicit styles', () => {
- it('exposes styles through styles property', (done) => {
- const styles = {
- foo: 'foo-1'
- };
-
- wrapStatelessFunction((props) => {
- expect(props.styles).to.equal(styles);
- done();
- })({
- styles
- });
- });
- });
- context('rendering Component that returns null', () => {
- it('generates null', () => {
- const shallowRenderer = TestUtils.createRenderer();
-
- const Component = wrapStatelessFunction(() => {
- return null;
- });
-
- shallowRenderer.render();
-
- const component = shallowRenderer.getRenderOutput();
-
- expect(component).to.equal(null);
- });
- });
-});