Skip to content

Commit 86e0bda

Browse files
lifeiscontentgregberge
authored andcommitted
feat: add ref option (#29)
1 parent 82023ad commit 86e0bda

9 files changed

Lines changed: 128 additions & 29 deletions

File tree

README.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Options:
9090
--template <file> specify a custom template to use
9191
--no-expand-props disable props expanding (default: true)
9292
--ids keep ids within the svg
93+
--ref add svgRef prop to svg
9394
--icon use "1em" as width and height
9495
--no-view-box remove viewBox (default: true)
9596
--native add react-native support with react-native-svg
@@ -167,10 +168,23 @@ $ svgr --template path/to/template.js my-icon.svg
167168
**Example of template:**
168169

169170
```js
170-
module.exports = (opts = {}) => (code, state) => `import React from 'react'
171-
const ${state.componentName} = (${opts.expandProps ? 'props' : ''}) => ${code}
172-
export default ${state.componentName}
173-
`
171+
export default (opts = {}) => {
172+
let props = ''
173+
174+
if (opts.expandProps && opts.ref) {
175+
props = '{svgRef, ...props}'
176+
} else if (opts.expandProps) {
177+
props = 'props'
178+
} else if (opts.ref) {
179+
props = '{svgRef}'
180+
}
181+
182+
return (code, state) => `import React from 'react'
183+
184+
const ${state.componentName} = (${props}) => ${code}
185+
186+
export default ${state.componentName}`
187+
}
174188
```
175189

176190
## Node API usage
@@ -319,6 +333,14 @@ using CSS or third party library (eg:
319333
| ------- | ------------ | ------------- |
320334
| `false` | `--ids` | `ids: <bool>` |
321335

336+
### Ref
337+
338+
Setting this to `true` will allow you to hook into the ref of the svg components that are created by exposing a `svgRef` prop
339+
340+
| Default | CLI Override | API Override |
341+
| ------- | ------------ | ------------- |
342+
| `false` | `--ref` | `ref: <bool>` |
343+
322344
### Replace attribute value
323345

324346
Replace an attribute value by an other. The main usage of this option is to

src/cli/__snapshots__/index.test.js.snap

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,36 @@ export default One;
187187
"
188188
`;
189189

190+
exports[`cli --ref --no-expand-props 1`] = `
191+
"import React from \\"react\\";
192+
193+
const One = ({ svgRef }) => (
194+
<svg width={48} height={1} viewBox=\\"0 0 48 1\\" ref={svgRef}>
195+
<title>Rectangle 5</title>
196+
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
197+
</svg>
198+
);
199+
200+
export default One;
201+
202+
"
203+
`;
204+
205+
exports[`cli --ref 1`] = `
206+
"import React from \\"react\\";
207+
208+
const One = ({ svgRef, ...props }) => (
209+
<svg width={48} height={1} viewBox=\\"0 0 48 1\\" ref={svgRef} {...props}>
210+
<title>Rectangle 5</title>
211+
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
212+
</svg>
213+
);
214+
215+
export default One;
216+
217+
"
218+
`;
219+
190220
exports[`cli --replace-attr-value 1`] = `
191221
"import React from \\"react\\";
192222

src/cli/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ program
2424
.option('--template <file>', 'specify a custom template to use')
2525
.option('--no-expand-props', 'disable props expanding')
2626
.option('--ids', 'keep ids within the svg')
27+
.option('--ref', 'add svgRef prop to svg')
2728
.option('--icon', 'use "1em" as width and height')
2829
.option('--no-view-box', 'remove viewBox')
2930
.option('--native', 'add react-native support with react-native-svg')

src/cli/index.test.js

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,12 @@ describe('cli', () => {
1313
})
1414

1515
it('--no-svgo', async () => {
16-
const [stdout] = await exec(
17-
'bin/svgr --no-svgo __fixtures__/one.svg',
18-
)
16+
const [stdout] = await exec('bin/svgr --no-svgo __fixtures__/one.svg')
1917
expect(stdout).toMatchSnapshot()
2018
})
2119

2220
it('--no-prettier', async () => {
23-
const [stdout] = await exec(
24-
'bin/svgr --no-prettier __fixtures__/one.svg',
25-
)
21+
const [stdout] = await exec('bin/svgr --no-prettier __fixtures__/one.svg')
2622
expect(stdout).toMatchSnapshot()
2723
})
2824

@@ -34,8 +30,18 @@ describe('cli', () => {
3430
})
3531

3632
it('--icon', async () => {
33+
const [stdout] = await exec('bin/svgr --icon __fixtures__/one.svg')
34+
expect(stdout).toMatchSnapshot()
35+
})
36+
37+
it('--ref', async () => {
38+
const [stdout] = await exec('bin/svgr --ref __fixtures__/one.svg')
39+
expect(stdout).toMatchSnapshot()
40+
})
41+
42+
it('--ref --no-expand-props', async () => {
3743
const [stdout] = await exec(
38-
'bin/svgr --icon __fixtures__/one.svg',
44+
'bin/svgr --ref --no-expand-props __fixtures__/one.svg',
3945
)
4046
expect(stdout).toMatchSnapshot()
4147
})
@@ -46,9 +52,7 @@ describe('cli', () => {
4652
})
4753

4854
it('--no-view-box', async () => {
49-
const [stdout] = await exec(
50-
'bin/svgr --no-view-box __fixtures__/one.svg',
51-
)
55+
const [stdout] = await exec('bin/svgr --no-view-box __fixtures__/one.svg')
5256
expect(stdout).toMatchSnapshot()
5357
})
5458

@@ -60,23 +64,17 @@ describe('cli', () => {
6064
})
6165

6266
it('--precision', async () => {
63-
const [stdout] = await exec(
64-
'bin/svgr --precision 1 __fixtures__/one.svg',
65-
)
67+
const [stdout] = await exec('bin/svgr --precision 1 __fixtures__/one.svg')
6668
expect(stdout).toMatchSnapshot()
6769
})
6870

6971
it('--no-title', async () => {
70-
const [stdout] = await exec(
71-
'bin/svgr --no-title __fixtures__/one.svg',
72-
)
72+
const [stdout] = await exec('bin/svgr --no-title __fixtures__/one.svg')
7373
expect(stdout).toMatchSnapshot()
7474
})
7575

7676
it('--no-semi', async () => {
77-
const [stdout] = await exec(
78-
'bin/svgr --no-semi __fixtures__/one.svg',
79-
)
77+
const [stdout] = await exec('bin/svgr --no-semi __fixtures__/one.svg')
8078
expect(stdout).toMatchSnapshot()
8179
})
8280

@@ -88,9 +86,7 @@ describe('cli', () => {
8886
})
8987

9088
it('--native', async () => {
91-
const [stdout] = await exec(
92-
'bin/svgr --native __fixtures__/one.svg',
93-
)
89+
const [stdout] = await exec('bin/svgr --native __fixtures__/one.svg')
9490
expect(stdout).toMatchSnapshot()
9591
})
9692

src/configToOptions.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import wrapIntoNativeComponent from './transforms/wrapIntoNativeComponent'
44
import stripAttribute from './h2x/stripAttribute'
55
import emSize from './h2x/emSize'
66
import expandProps from './h2x/expandProps'
7+
import svgRef from './h2x/svgRef'
78
import replaceAttrValue from './h2x/replaceAttrValue'
89
import removeComments from './h2x/removeComments'
910
import removeStyle from './h2x/removeStyle'
1011
import toReactNative from './h2x/toReactNative'
1112

1213
const defaultConfig = {
14+
ref: false,
1315
svgo: true,
1416
prettier: true,
1517
native: false,
@@ -41,6 +43,7 @@ function configToOptions(config = {}) {
4143
config.replaceAttrValues.forEach(([oldValue, newValue]) => {
4244
plugins.push(replaceAttrValue(oldValue, newValue))
4345
})
46+
if (config.ref) plugins.push(svgRef)
4447
if (config.expandProps) plugins.push(expandProps)
4548
if (config.native) plugins.push(toReactNative)
4649

src/h2x/svgRef.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { JSXAttribute } from 'h2x-plugin-jsx'
2+
3+
const svgRef = () => ({
4+
visitor: {
5+
JSXElement: {
6+
enter(path) {
7+
if (
8+
path.node.name === 'svg' &&
9+
!path.node.attributes.some(attr => attr && attr.name === 'ref')
10+
) {
11+
const props = new JSXAttribute()
12+
props.name = 'ref'
13+
props.value = 'svgRef'
14+
props.litteral = true
15+
path.node.attributes.push(props)
16+
path.replace(path.node)
17+
}
18+
},
19+
},
20+
},
21+
})
22+
23+
export default svgRef

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { pascalCase } from './transforms/rename'
99
import stripAttribute from './h2x/stripAttribute'
1010
import emSize from './h2x/emSize'
1111
import expandProps from './h2x/expandProps'
12+
import svgRef from './h2x/svgRef'
1213
import replaceAttrValue from './h2x/replaceAttrValue'
1314
import removeComments from './h2x/removeComments'
1415
import removeStyle from './h2x/removeStyle'
@@ -20,6 +21,7 @@ export {
2021
emSize,
2122
expandProps,
2223
replaceAttrValue,
24+
svgRef,
2325
wrapIntoComponent,
2426
removeComments,
2527
removeStyle,
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
export default (opts = {}) => (code, state) => `import React from 'react'
1+
export default (opts = {}) => {
2+
let props = ''
23

3-
const ${state.componentName} = (${opts.expandProps ? 'props' : ''}) => ${code}
4+
if (opts.expandProps && opts.ref) {
5+
props = '{svgRef, ...props}'
6+
} else if (opts.expandProps) {
7+
props = 'props'
8+
} else if (opts.ref) {
9+
props = '{svgRef}'
10+
}
11+
12+
return (code, state) => `import React from 'react'
13+
14+
const ${state.componentName} = (${props}) => ${code}
415
516
export default ${state.componentName}`
17+
}

src/transforms/wrapIntoNativeComponent.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,24 @@ export default (opts = {}) => (code, state) => {
1616
unsupportedComponents = new Set(),
1717
} = state
1818

19+
let props = ''
20+
21+
if (opts.expandProps && opts.ref) {
22+
props = '{svgRef, ...props}'
23+
} else if (opts.expandProps) {
24+
props = 'props'
25+
} else if (opts.ref) {
26+
props = '{svgRef}'
27+
}
28+
1929
return `import React from 'react'
2030
import Svg, { ${componentsToList(
2131
reactNativeSvgReplacedComponents,
2232
)} } from 'react-native-svg';
2333
${logUnsupportedComponents(unsupportedComponents)}
2434
2535
26-
const ${state.componentName} = (${opts.expandProps ? 'props' : ''}) => ${code}
36+
const ${state.componentName} = (${props}) => ${code}
2737
2838
export default ${state.componentName}`
2939
}

0 commit comments

Comments
 (0)