Skip to content

Commit

Permalink
feat: new option "svgProps" (#172)
Browse files Browse the repository at this point in the history
Allow to pass dynamic svg props:

In this diff I introduce the new option `svgProps` which is similar to
svgAttributes but applies values in interpolation style `{true}`.

This allows to specify expressions depending on template values for
example default `currentColor` in `fill` prop.

`svgAttributes` is now deprecated and will be removed in v3.
  • Loading branch information
gregberge authored Sep 16, 2018
1 parent 60da35d commit 9657110
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 39 deletions.
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ powerful and configurable HTML transpiler. It uses AST (like
## Command line usage

```
Usage: svgr [options] <file>
Usage: svgr [options] <file|directory>
Options:
Expand All @@ -94,7 +94,8 @@ Options:
--ref add svgRef prop to svg
--no-dimensions remove width and height from root SVG tag
--no-expand-props disable props expanding
--svg-attributes <property=value> add some attributes to the svg
--svg-attributes <property=value> add attributes to the svg element (deprecated)
--svg-props <property=value> add props to the svg element
--replace-attr-values <old=new> replace an attribute value
--template <file> specify a custom template to use
--title-prop create a title element linked with props
Expand All @@ -104,8 +105,8 @@ Options:
--no-svgo disable SVGO
-h, --help output usage information
Examples:
svgr --replace-attr-values "#fff=currentColor" icon.svg
Examples:
svgr --replace-attr-values "#fff=currentColor" icon.svg
```

### Recipes
Expand Down Expand Up @@ -344,13 +345,15 @@ change an icon color to "currentColor" in order to inherit from text color.
| ------- | --------------------------------- | ------------------------------------ |
| `[]` | `--replace-attr-values <old=new>` | `replaceAttrValues: { old: 'new' }>` |

### SVG attributes
### SVG props

Add attributes to the root SVG tag.
Add props to the root SVG tag.

| Default | CLI Override | API Override |
| ------- | ------------------------------- | ----------------------------------- |
| `[]` | `--svg-attributes <name=value>` | `svgAttributes: { name: 'value' }>` |
| Default | CLI Override | API Override |
| ------- | -------------------------- | ------------------------------ |
| `[]` | `--svg-props <name=value>` | `svgProps: { name: 'value' }>` |

> You can specify dynamic property using curly braces: `{ focusable: "{true}" }` or `--svg-props focusable={true}`. It is particulary useful with a custom template.

### Template

Expand Down
47 changes: 24 additions & 23 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,30 @@ npm install @svgr/cli
## Usage

```
Usage: index [options] <file>
Options:
-V, --version output the version number
--config <file> specify the path of the svgr config
-d, --out-dir <dirname> output files into a directory
--ext <ext> specify a custom file extension (default: "js")
--filename-case <case> specify filename case (pascal, kebab, camel) (default: "pascal")
--icon use "1em" as width and height
--native add react-native support with react-native-svg
--ref add svgRef prop to svg
--no-dimensions remove width and height from root SVG tag
--no-expand-props disable props expanding
--svg-attributes <property=value> add some attributes to the svg
--replace-attr-values <old=new> replace an attribute value
--template <file> specify a custom template to use
--title-prop create a title element linked with props
--prettier-config <fileOrJson> Prettier config
--no-prettier disable Prettier
--svgo-config <fileOrJson> SVGO config
--no-svgo disable SVGO
-h, --help output usage information
Usage: svgr [options] <file|directory>
Options:
-V, --version output the version number
--config <file> specify the path of the svgr config
-d, --out-dir <dirname> output files into a directory
--ext <ext> specify a custom file extension (default: "js")
--filename-case <case> specify filename case (pascal, kebab, camel) (default: "pascal")
--icon use "1em" as width and height
--native add react-native support with react-native-svg
--ref add svgRef prop to svg
--no-dimensions remove width and height from root SVG tag
--no-expand-props disable props expanding
--svg-attributes <property=value> add attributes to the svg element (deprecated)
--svg-props <property=value> add props to the svg element
--replace-attr-values <old=new> replace an attribute value
--template <file> specify a custom template to use
--title-prop create a title element linked with props
--prettier-config <fileOrJson> Prettier config
--no-prettier disable Prettier
--svgo-config <fileOrJson> SVGO config
--no-svgo disable SVGO
-h, --help output usage information
Examples:
svgr --replace-attr-values "#fff=currentColor" icon.svg
Expand Down
14 changes: 14 additions & 0 deletions packages/cli/src/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,20 @@ export default File
"
`;

exports[`cli should support various args: --svg-props "hidden={true}" 1`] = `
"import React from 'react'
const File = props => (
<svg hidden={true} width={48} height={1} {...props}>
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
</svg>
)
export default File
"
`;

exports[`cli should support various args: --title-prop 1`] = `
"import React from 'react'
Expand Down
17 changes: 16 additions & 1 deletion packages/cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import program from 'commander'
import path from 'path'
import glob from 'glob'
import fs from 'fs'
import chalk from 'chalk'
import pkg from '../package.json'
import fileCommand from './fileCommand'
import dirCommand from './dirCommand'
Expand Down Expand Up @@ -51,7 +52,12 @@ program
.option('--no-expand-props', 'disable props expanding')
.option(
'--svg-attributes <property=value>',
'add some attributes to the svg',
'add attributes to the svg element (deprecated)',
parseObject,
)
.option(
'--svg-props <property=value>',
'add props to the svg element',
parseObject,
)
.option(
Expand Down Expand Up @@ -123,6 +129,15 @@ async function run() {
}
}

// TODO remove in v3
if (program.outDir && program.svgAttributes) {
console.log(
chalk.yellow(
'--svg-attributes option is deprecated an will be removed in v3, please use --svg-props instead',
),
)
}

const command = program.outDir ? dirCommand : fileCommand
await command(program, filenames, config)
}
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ describe('cli', () => {
['--ref'],
['--replace-attr-values "#063855=currentColor"'],
['--svg-attributes "focusable=false"'],
[`--svg-props "hidden={true}"`],
['--no-svgo'],
['--no-prettier'],
['--title-prop'],
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const DEFAULT_CONFIG = {
ref: false,
replaceAttrValues: null,
svgAttributes: null,
svgProps: null,
svgo: true,
svgoConfig: null,
template: null,
Expand Down
12 changes: 6 additions & 6 deletions packages/core/src/h2x/svgAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const areAttrsAlreadyInjected = (node, attributes = {}) => {
}, true)
}

const svgAttribute = (attributes = {}) => () => {
const svgAttributes = (attributes = {}) => () => {
const keys = Object.keys(attributes)

return {
Expand All @@ -27,10 +27,10 @@ const svgAttribute = (attributes = {}) => () => {
if (areAttrsAlreadyInjected(path.node, attributes)) return

const parseAttributes = keys.reduce((accumulation, key) => {
const props = new JSXAttribute()
props.name = key
props.value = attributes[key]
return [...accumulation, props]
const prop = new JSXAttribute()
prop.name = key
prop.value = attributes[key]
return [...accumulation, prop]
}, [])

const mergeAttributes = path.node.attributes.reduce(
Expand All @@ -50,4 +50,4 @@ const svgAttribute = (attributes = {}) => () => {
}
}

export default svgAttribute
export default svgAttributes
69 changes: 69 additions & 0 deletions packages/core/src/h2x/svgProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { JSXAttribute } from 'h2x-plugin-jsx'

const compareAttrsName = attr => otherAttr => attr.name === otherAttr.name
const compareAttrsValue = attr => otherAttr => attr.value === otherAttr.value

const compareAttrs = attr => otherAttr =>
compareAttrsName(attr)(otherAttr) && compareAttrsValue(attr)(otherAttr)

const areAttrsAlreadyInjected = (node, attributes = {}) => {
const nodeAttrs = node.attributes

return Object.keys(attributes).reduce((accumulation, key) => {
if (nodeAttrs.some(compareAttrs({ name: key, value: attributes[key] })))
return accumulation
return false
}, true)
}

const svgProps = (props = {}) => () => {
const interpolated = new Set()
const keys = Object.keys(props)
const attributes = keys.reduce((acc, prop) => {
const value = props[prop]
if (
typeof value === 'string' &&
value.startsWith('{') &&
value.endsWith('}')
) {
acc[prop] = value.slice(1, -1)
interpolated.add(prop)
} else {
acc[prop] = value
}
return acc
}, {})

return {
visitor: {
JSXElement: {
enter(path) {
if (path.node.name !== 'svg') return
if (areAttrsAlreadyInjected(path.node, attributes)) return

const parseAttributes = keys.reduce((accumulation, key) => {
const prop = new JSXAttribute()
prop.name = key
prop.value = attributes[key]
prop.literal = interpolated.has(key)
return [...accumulation, prop]
}, [])

const mergeAttributes = path.node.attributes.reduce(
(accumulation, value) => {
if (accumulation.some(compareAttrsName(value)))
return accumulation
return [...accumulation, value]
},
parseAttributes,
)

path.node.attributes = mergeAttributes
path.replace(path.node)
},
},
},
}
}

export default svgProps
Loading

0 comments on commit 9657110

Please sign in to comment.