diff --git a/demo/package.json b/demo/package.json index deb75b0..be31c1a 100644 --- a/demo/package.json +++ b/demo/package.json @@ -5,6 +5,7 @@ }, "dependencies": { "babel-plugin-react-css-modules": "^2.1.3", + "classnames": "^2.2.6", "react": "^15.4.1", "react-dom": "^15.4.1", "webpack": "^2.2.0-rc.3" diff --git a/demo/webpack.config.js b/demo/webpack.config.js index 4a63762..a3b23dc 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -23,7 +23,7 @@ module.exports = { plugins: [ 'transform-react-jsx', [ - 'react-css-modules', + require('../dist/index.js').default, { context } diff --git a/src/index.js b/src/index.js index 2c32aa8..77a88c8 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,7 @@ import optionsDefaults from './schemas/optionsDefaults'; import createObjectExpression from './createObjectExpression'; import requireCssModule from './requireCssModule'; import resolveStringLiteral from './resolveStringLiteral'; +import resolveJSXExpression from './resolveJSXExpression'; import replaceJsxExpressionContainer from './replaceJsxExpressionContainer'; const ajv = new Ajv({ @@ -210,6 +211,18 @@ export default ({ } ); } else if (t.isJSXExpressionContainer(attribute.value)) { + if(t.isCallExpression(attribute.value.expression)) { + resolveJSXExpression( + path, + filenameMap[filename].styleModuleImportMap, + attribute, + destinationName, + { + handleMissingStyleName + } + ); + return; + } if (!filenameMap[filename].importedHelperIndentifier) { setupFileForRuntimeResolution(path, filename); } diff --git a/src/resolveJSXExpression.js b/src/resolveJSXExpression.js new file mode 100644 index 0000000..971b33d --- /dev/null +++ b/src/resolveJSXExpression.js @@ -0,0 +1,57 @@ +// @flow + +import { + isJSXExpressionContainer, + isStringLiteral, + isObjectExpression, + JSXAttribute, + stringLiteral +} from 'babel-types'; +import conditionalClassMerge from './conditionalClassMerge'; +import getClassName from './getClassName'; +import type { + StyleModuleImportMapType, + HandleMissingStyleNameOptionType +} from './types'; + +type OptionsType = {| + handleMissingStyleName: HandleMissingStyleNameOptionType +|}; + +/** + * Updates the className value of a JSX element using a provided styleName attribute. + */ +export default ( + path: *, + styleModuleImportMap: StyleModuleImportMapType, + sourceAttribute: JSXAttribute, + destinationName: string, + options: OptionsType): void => { + const callExpressionArguments = sourceAttribute.value.expression.arguments; + + for (let argumentIndex in callExpressionArguments) { + let argument = callExpressionArguments[argumentIndex]; + if(isStringLiteral(argument)) { + callExpressionArguments[argumentIndex].value = getClassName(argument.value, styleModuleImportMap, options); + } else if(isObjectExpression(argument)) { + for (let propertyIndex in argument.properties){ + let property = argument.properties[propertyIndex]; + if(isStringLiteral(property.key)) { + property.key.value = getClassName(property.key.value, styleModuleImportMap, options); + } + } + } + } + + + const destinationAttribute = path.node.openingElement.attributes + .find((attribute) => { + return typeof attribute.name !== 'undefined' && attribute.name.name === destinationName; + }); + + if (destinationAttribute) { + throw new Error('Destination Attribute cannot be present on JSX Element when using JSX Expressions'); + } else { + sourceAttribute.name.name = destinationName; + } +};