pugjs / babel-plugin-transform-react-pug

A plugin for transpiling pug templates to jsx
MIT License
810 stars 47 forks source link

Add new option: `attributeAlias` #122

Open shirohana opened 4 years ago

shirohana commented 4 years ago

I made a new option to solve https://github.com/pugjs/babel-plugin-transform-react-pug/issues/111, this option grant everyone can decide which syntax to use between:

pug`div( class="box" )`

and

pug`div( className="box" )`

But before that, I must implement expressional className so I can make attributeAlias works correctly.

This pull request brings two features in actual:

Usage

babel.config.js
{
  plugins: [
    // or shorthand:
    // ["transform-react-pug", {
    ["babel-plugin-transform-react-pug", {
      attributeAlias: {
        class: 'className'
      }
    }]
  ]
}

With attributeAlias: { class: 'className' } set, you can now write expressions inside class again just like the native syntax of Pug:

Changes

1. Allow expression and array

*Pug allows pass array as class attribute natively.

const darkMode = true

const A = pug`
  div.box( class=("is-large " + (darkMode ? "is-dark" : "")) )
`

const B = pug`
  div.box( class=${`is-large ${darkMode && "is-dark" : ""`} )
`

const C = pug`
  div.box( class=["is-large", darkMode && "is-dark"] )
`

All renders to: (ignore there's extra spaces in A and B)

<div className="box is-large is-dark" />

2. Correct syntax of className

*Also see: https://github.com/facebook/react/issues/3138

Before:

pug`
  div( class=100 )
  div( class=["A", "B"] )
`
// => <div className={100} />
// => <div className={["A", "B"]} />

After:

pug`
  div( className=100 )`
  div( class=["A", "B"] )
`
// => <div className="100" />
// => <div className="A B" />

3. ClassName interpolation

import $ from './style.css'

const A = pug`div( class=$.Box )`
// => <div className={$.Box} />

const B = pug`div( class=[$.Box, $.isLarge ] )`
// => <div className={`${$.Box} ${$.isLarge}`} />

const C = pug`div( class=["class-1", "class-2"] )`
// => <div className="class-1 class-2" />

const D = pug`div( class=["class-1", $.InterpolateClass, "class-2"] )`
// => <div className={`class-1 ${$.InterpolateClass} class-2`} />

4. Default alias (❗Breaking Change)

Now we don't parse there attributes in initiative:

To make it works like before, create aliases in your babelrc:

babel.config.js
{
  plugins: [
    ["babel-plugin-transform-react-pug", {
      attributeAlias: {
        for: 'htmlFor',
        maxlength: 'maxLength'
      }
    }]
  ]
}

Question:

Is it a good idea that make class and for alias in default?

5. Limitation

Currently array spread operators are ignored, here's some sample:

const classes = ["class-1", "class-2"]

pug`
  div.box( classes=["class-1", "class-2"] )
`
// => <div className="box class-1 class-2" />

pug`
  div.box( classes=classes )
`
// => <div className={`box ${classes}`} />

pug`
  div( class=["box", ...classes] )
`
// => <div className="box" /> // ...ignored

More about attributeAlias

With this option, you can even do more than just classNames.

For example, you can create shorthands like that:

babel.config.js
{
  plugins: [
    ["babel-plugin-transform-react-pug", {
      attributeAlias: {
        "@click": 'onClick',
        "@change": 'onChange',
        "@value": 'defaultValue',
        "@html": 'dangerouslySetInnerHTML'
      }
    }]
  ]
}

And feel the power:

pug`
  button( @click=handleClick )
    | Button
`
// => <button onClick={handleClick}>Button</button>

pug`
  input( @change=setEmail, @value=email )
`
// => <input onChange={setEmail} defaultValue={email} />

pug`
  svg( @html={ __html: svgContentText } )
`
// => <svg dangerouslySetInnerHTML={{ __html: svgContentText }} />
codecov-commenter commented 4 years ago

Codecov Report

Merging #122 into master will increase coverage by 0.97%. The diff coverage is 90.90%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #122      +/-   ##
==========================================
+ Coverage   87.14%   88.12%   +0.97%     
==========================================
  Files          21       21              
  Lines         459      480      +21     
  Branches      112      112              
==========================================
+ Hits          400      423      +23     
+ Misses         53       51       -2     
  Partials        6        6              
Impacted Files Coverage Δ
src/context.js 88.46% <ø> (ø)
src/index.js 100.00% <ø> (ø)
src/visitors/Tag.js 94.82% <90.00%> (+6.30%) :arrow_up:
src/utils/get-class-name-value.js 91.07% <91.07%> (+0.44%) :arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 0cb224b...d8ef7b9. Read the comment docs.

shirohana commented 4 years ago

Any response (´・ω・`)?

skotchpine commented 4 years ago

This is brilliant. Good job!