babel-plugin-jsx-map-class-props v1.0.0
babel-plugin-jsx-map-class-props
Merges class names from any attribute with className
or other compatible attributes.
- Installation
- Why?
- Configuration
- How does it work?
- Runtime attribute value formatting and merging
- Have a question or want to suggest an improvement?
Installation
When babel-plugin-jsx-map-class-props
cannot resolve attribute value at compile time, it imports helper functions (read Runtime attribute value formatting and merging). Therefore, you must install babel-plugin-jsx-map-class-props
as a direct dependency of the project.
npm install babel-plugin-jsx-map-class-props --save
Why?
The idea was born when I tried to identify the components in our E2E tests.
First of all I tried to find a property that most components pass to the DOM. I read about testId
, data-test-id
and some others, but our components library isn't aware of any of them.
Then I thought about className
. It is supported by most components. But we use CSS-modules, which decorates the class names, and so they cannot be simply recognized by e2e test. So we have to use additional classes for tests and combine them with the existing ones, and that makes a mess. Also we need to strip them in production.
Finally, the combination of both directions gave me a new idea: i could put an identifier into a different property and merge it with the className
at compile time. It also solved the issue of stripping these properties for production.
Configuration
Configure the options for the plugin within your .babelrc
as follows:
{
"plugins": [
["jsx-map-class-props", {
"option": "value"
}]
]
}
Options
Name | Type | Description | Default |
---|---|---|---|
context | ?string | Scoped names will be calculated relative to this path. | process.cwd() |
format | ?GenerateScopedNameConfigurationType | Global pattern for class names formatting. Can be overridden by mapping option. Refer to Generating scoped names and Interpolate Name. | none |
clean | ?boolean | Removes all matching props. This option can be used for removing debug/test classNames from production build. Can be overridden by mapping option. Ignored if false | false |
mappings | AttributeMappingType [] | Array of attribute mapping options | [] |
Attribute Mapping Options
Name | Type | Description | Default |
---|---|---|---|
format | ?GenerateScopedNameConfigurationType | Pattern for class names formatting. Can override global option. Set null to prevent formatting. Refer to Generating scoped names and Interpolate Name. | none |
clean | ?boolean | Removes all matching props. This option can be used for removing debug/test classNames from production build. Can override global option by being set to false explicitly. | none |
sourceName | ?string | Name of an attribute to be matched. | |
sourceMask | ?string | RegExp pattern string to find matching attributes. | |
prefix | ?string | String to find matching attributes by prefix. Target attribute's name will be calculated by removing prefix, if other options not specified. | |
targetName | ?string | Name of the attribute the value will be merged with. This option has the highest priority for target calculation. Can be used with any source option. | |
targetMask | ?string, ?function | Second parameter of String.replace . Can only be used with sourceMask , which will be used as a first parameter. Allows to calculate attribute name to merge value with. |
Missing a configuration? Raise an issue.
Allowed combinations of source-target options
(in priority order)
Source | Target | Strategy Description |
---|---|---|
sourceName | targetName | match attribute by exact sourceName , merge with targetName attribute |
sourceMask | targetName | match attribute by sourceMask RegExp, merge with targetName attribute |
sourceMask | targetMask | match attribute by sourceMask RegExp, calculate target using foundName.replace(sourceMask, targetMask) , merge with target attribute |
prefix | targetName | match attribute by prefix , merge with targetName attribute |
prefix | match attribute by prefix , get target by stripping prefix, merge with target attribute |
Notes:
- only one combination per mapping is allowed
- other options will be ignored (according to priority)
- if attribute is matched by a mapping, other mappings are ignored (in other words, an attribute can have only one target)
How does it work?
- Iterates through all JSX element declarations.
- Finds matched source attributes according to the mapping options.
- If
clean
option istrue
, removes the source attribute that was found from the element and continues to the next iteration.
- If
- Calculates target attribute names according to the mapping options.
- Formats source attribute value according to the mapping options:
- If value is a string literal, generates a string literal value.
- If value is a
jSXExpressionContainer
and format option is valid, uses a helper function (getClassName
) to format value at runtime.
- Merges source attribute value with the target attribute:
- If target attribute doesn't exist, moves formatted source attribute to the target.
- If source and target values are a string literal, generates a string literal value.
- If source or target value is a
jSXExpressionContainer
, uses a helper function (joinClassNames
) to join values at runtime.
- Removes the source attribute from the element.
Runtime attribute value formatting and merging
When the value of a source attribute cannot be determined at compile time, babel-plugin-jsx-map-class-props
uses getClassName
helper function to format the value at runtime.
Input:
<div test-className={Math.random() > .5 ? 'a' : 'b'} />;
Output:
import _getClassName from 'babel-plugin-jsx-map-class-props/dist/browser/getClassName';
<div className={
_getClassName(Math.random() > .5 ? 'a' : 'b', 'e2e-|')
} />;
When the value of a source or a target attribute cannot be determined at compile time, babel-plugin-jsx-map-class-props
uses joinClassNames
helper function to join the values at runtime.
Input:
<div test-className='my-component' className={styles.myComponent} />;
Output:
import _joinClassNames from 'babel-plugin-jsx-map-class-props/dist/browser/joinClassNames';
<div className={
_joinClassNames('e2e-my-component', styles.myComponent)
} />;
Have a question or want to suggest an improvement?
- Have technical questions? Ask on Stack Overflow.
- Have a feature suggestion or want to report an issue? Raise an issues.
6 years ago