1.0.2 • Published 5 years ago

babel-plugin-jsx-classnames-advanced v1.0.2

Weekly downloads
10
License
MIT
Repository
github
Last release
5 years ago

babel-plugin-jsx-classnames-advanced

Build Status Coverage Status NPM version NPM downloads

Plugin for babel@7, automatically adding classnames() to [className] attributes.

Inspired from meowtec's repo babel-plugin-jsx-classnames for babel@6.

// transforming
<Component className={expression} />

// to
import classnames from 'classnames';
<Component className={classnames(expression)} />

Why

Passing expression to classnames which is imported automatically.

Comparison of src:

// string template
<Component className={`${styles.wrap || ''} ${this.props.className || ''}`} />
<Component className={`${active ? 'btn-active' : ''} ${disabled ? 'btn-disabled' : ''}`} />

// using classnames
import classnames from 'classnames';
<Component className={classnames([styles.wrap, this.props.className])} />
<Component className={classnames({ 'btn-active': active, 'btn-disabled': disabled })} />

// using babel-plugin-jsx-classnames-advanced
<Component className={[styles.wrap, this.props.className]} />
<Component className={{ 'btn-active': active, 'btn-disabled': disabled }} />

Usage

Install

npm i babel-plugin-jsx-classnames-advanced --save-dev

Babel config

Work with @babel/preset-react, or position after @babel/plugin-syntax-jsx.

{
  "presets": [
    ...
    // "@babel/preset-react"
  ],
  "plugins": [
    ...
    // "@babel/plugin-syntax-jsx",
    "babel-plugin-jsx-classnames-advanced"
  ]
}

Cases:

// src

// ignores
<Component otherAttributeNames={[]} />
<Component className="wrap" />
<Component className={"wrap"} />
<Component className={styles.wrap} />

// expressions
<Component className={[styles.wrap, this.props.className]} />
<Component className={{ [styles.wrap]: true }} />
<Component className={'a' + 'b'} />

// other attribute names in ant-design
<Component dropdownClassName={[styles.wrap, this.props.className]} />
<Component wrapperClassName={[styles.wrap, this.props.className]} />
<Component wrapClassName={[styles.wrap, this.props.className]} />
// transformed

import _babel_plugin_jsx_classnames_advanced from 'classnames';

// ignores
<Component otherAttributeNames={[]} />
<Component className="wrap" />
<Component className={"wrap"} />
<Component className={styles.wrap} />

// expressions
<Component className={_babel_plugin_jsx_classnames_advanced([styles.wrap, this.props.className])} />
<Component className={_babel_plugin_jsx_classnames_advanced({ [styles.wrap]: true })} />
<Component className={_babel_plugin_jsx_classnames_advanced('a' + 'b')} />

// other attribute names in ant-design
<Component dropdownClassName={_babel_plugin_jsx_classnames_advanced([styles.wrap, this.props.className])} />
<Component wrapperClassName={_babel_plugin_jsx_classnames_advanced([styles.wrap, this.props.className])} />
<Component wrapClassName={_babel_plugin_jsx_classnames_advanced([styles.wrap, this.props.className])} />

Options

Babel config with options:

{
  "plugins": [
    ["babel-plugin-jsx-classnames-advanced", { nameHint: 'nameHint' }]
  ]
}

nameHint

string | false(boolean), defaults to '_babel_plugin_jsx_classnames_advanced'

Unique import name of classnames (callee of callExpression) in modules, passed to addDefault.

Note that the import name which generated by babel api in the first transformation, will be referenced in others, for uniq imports and better performance.

Default value works well in most cases. It would cause problems if there are variables same as nameHint in scopes.

Which should be avoided:

// src

<Component className={[]} />

{  // inner scope
  const _babel_plugin_jsx_classnames_advanced = () => {};
  <Component className={[]} />
}
// transformed

// generated by babel api, according to the first transformation
import _babel_plugin_jsx_classnames_advanced from 'classnames';
// first transformation
<Component className={_babel_plugin_jsx_classnames_advanced([])} />

{  // inner scope
  const _babel_plugin_jsx_classnames_advanced = () => {}
  // generated for referencing to imported function in line 1, but it refs to function of inner scope
  <Component className={_babel_plugin_jsx_classnames_advanced([])} />
}

option false, keep default behavior of addDefault:

// src
<Component className={[]} />
<Component className={[]} />

// transformed
import _babel_plugin_jsx_classnames_advanced2 from 'classnames';
import _babel_plugin_jsx_classnames_advanced from 'classnames';

<Component className={_babel_plugin_jsx_classnames_advanced([])} />
<Component className={_babel_plugin_jsx_classnames_advanced2([])} />

attributeNames

Array<string>, defaults to ['className', 'dropdownClassName', 'wrapperClassName', 'wrapClassName', 'overlayClassName']

Defaults to frequent attribute names, integrating with ant-design.

This array will be replaced entirely, passing necessary options like 'className' manually.

ignoreMemberExpression

boolean, defaults to true

Ignore memberExpression, for less transforms, integrating with css module.

// ignored
import styles from './index.css';
<Component className={styles.wrap} />

If you want to transform memberExpression, recommend to:

<Component className={[foo.bar]} />

option false:

// src
import styles from './index.css';
<Component className={styles.wrap} />
<Component className={foo.bar} />

// transformed
import _babel_plugin_jsx_classnames_advanced from 'classnames';
import styles from './index.css';
<Component className={_babel_plugin_jsx_classnames_advanced(styles.wrap)} />
<Component className={_babel_plugin_jsx_classnames_advanced(foo.bar)} />

ignoreIdentifier

boolean, defaults to true

Transforms of identifier will be ignored, for less transforms.

// ignored
<Component className={foo} />

If you want to transform identifier, recommend to:

<Component className={[foo]} />

option false:

// src
<Component className={foo} />

// transformed
<Component className={_babel_plugin_jsx_classnames_advanced(foo)} />