Skip to content

Commit

Permalink
feat: add "-native" option to target React Native
Browse files Browse the repository at this point in the history
  • Loading branch information
kimak authored and gregberge committed Dec 7, 2017
1 parent e898886 commit 76fd6f5
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -91,6 +91,7 @@ powerful and configurable HTML transpiler. It uses AST (like
--no-expand-props disable props expanding
--ids keep ids within the svg
--icon use "1em" as width and height
--native add react-native support with react-native-svg
--replace-attr-value [old=new] replace an attribute value
-p, --precision <value> set the number of digits in the fractional part (svgo)
--no-title remove title tag (svgo)
Expand Down Expand Up @@ -282,6 +283,15 @@ inherits from text size. Also remove title.
| ------- | ------------ | -------------- |
| `false` | `--icon` | `icon: <bool>` |

### Native

Modify all SVG nodes with uppercase and use a specific template with
react-native-svg imports. **All unsupported nodes will be removed.**

| Default | CLI Override | API Override |
| ------- | ------------ | -------------- |
| `false` | `--native` | `native: <bool>` |

### ViewBox

Setting this to `false` will remove the viewBox property.
Expand Down
19 changes: 19 additions & 0 deletions src/__snapshots__/index.test.js.snap
Expand Up @@ -87,6 +87,25 @@ export default SvgComponent;
"
`;

exports[`convert should support react-native 1`] = `
"import React from \\"react\\";
const SvgComponent = props => (
<svg width={88} height={88} viewBox=\\"0 0 88 88\\" {...props}>
<title>Dismiss</title>
<g fill=\\"red\\" fillRule=\\"evenodd\\" strokeLinecap=\\"square\\">
<g id=\\"Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
<path d=\\"M51 37L37 51\\" id=\\"Shape\\" />
<path d=\\"M51 51L37 37\\" />
</g>
</g>
</svg>
);
export default SvgComponent;
"
`;

exports[`rawConvert should convert using specific options 1`] = `
"import React from 'react'
Expand Down
31 changes: 31 additions & 0 deletions src/cli/__snapshots__/index.test.js.snap
Expand Up @@ -41,6 +41,37 @@ export default One;
"
`;

exports[`cli --native 1`] = `
"import React from \\"react\\";
import Svg, {
Circle,
Ellipse,
G,
LinearGradient,
RadialGradient,
Line,
Path,
Polygon,
Polyline,
Rect,
Symbol,
Text,
Use,
Defs,
Stop
} from \\"react-native-svg\\";
const One = props => (
<Svg width={48} height={1} viewBox=\\"0 0 48 1\\" {...props}>
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
</Svg>
);
export default One;
"
`;

exports[`cli --no-expand-props 1`] = `
"import React from \\"react\\";
Expand Down
1 change: 1 addition & 0 deletions src/cli/index.js
Expand Up @@ -26,6 +26,7 @@ program
.option('--ids', 'keep ids within the svg')
.option('--icon', 'use "1em" as width and height')
.option('--no-view-box', 'remove viewBox')
.option('--native', 'add react-native support with react-native-svg')
.option(
'--replace-attr-value [old=new]',
'replace an attribute value',
Expand Down
7 changes: 7 additions & 0 deletions src/cli/index.test.js
Expand Up @@ -87,6 +87,13 @@ describe('cli', () => {
expect(stdout).toMatchSnapshot()
})

it('--native', async () => {
const [stdout] = await exec(
'babel-node src/cli --native __fixtures__/one.svg',
)
expect(stdout).toMatchSnapshot()
})

it('should work with stdin', async () => {
const [stdout] = await exec('babel-node src/cli < __fixtures__/one.svg')
expect(stdout).toMatchSnapshot()
Expand Down
6 changes: 6 additions & 0 deletions src/configToOptions.js
@@ -1,15 +1,18 @@
import jsx from 'h2x-plugin-jsx'
import wrapIntoComponent from './transforms/wrapIntoComponent'
import wrapIntoNativeComponent from './transforms/wrapIntoNativeComponent'
import stripAttribute from './h2x/stripAttribute'
import emSize from './h2x/emSize'
import expandProps from './h2x/expandProps'
import replaceAttrValue from './h2x/replaceAttrValue'
import removeComments from './h2x/removeComments'
import removeStyle from './h2x/removeStyle'
import toReactNative from './h2x/toReactNative'

const defaultConfig = {
svgo: true,
prettier: true,
native: false,
icon: false,
viewBox: true,
replaceAttrValues: [],
Expand All @@ -28,6 +31,8 @@ const defaultConfig = {
}

function configToOptions(config = {}) {
if (!config.template && config.native)
config.template = wrapIntoNativeComponent
config = { ...defaultConfig, ...config }

function getH2xPlugins() {
Expand All @@ -37,6 +42,7 @@ function configToOptions(config = {}) {
plugins.push(replaceAttrValue(oldValue, newValue))
})
if (config.expandProps) plugins.push(expandProps)
if (config.native) plugins.push(toReactNative)

return plugins
}
Expand Down
26 changes: 26 additions & 0 deletions src/h2x/removeStyle.test.js
@@ -0,0 +1,26 @@
import jsx from 'h2x-plugin-jsx'
import h2x from '../plugins/h2x'
import removeStyle from './removeStyle'

describe('removeStyle', () => {
it('should remove style elements', () => {
const result = h2x(
`
<svg>
<style></style>
<style></style>
<g stroke="#063855" stroke-width="2">
<path d="M51,37 L37,51" id="Shape"></path>
</g>
</svg>
`,
{ plugins: [jsx, removeStyle] },
)

expect(result.trim()).toBe(`<svg>
<g stroke="#063855" strokeWidth={2}>
<path d="M51,37 L37,51" id="Shape" />
</g>
</svg>`)
})
})
39 changes: 39 additions & 0 deletions src/h2x/toReactNative.js
@@ -0,0 +1,39 @@
const supportedElements = {
svg: 'Svg',
circle: 'Circle',
ellipse: 'Ellipse',
g: 'G',
linearGradient: 'LinearGradient',
radialGradient: 'RadialGradient',
line: 'Line',
path: 'Path',
polygon: 'Polygon',
polyline: 'Polyline',
rect: 'Rect',
symbol: 'Symbol',
text: 'Text',
use: 'Use',
defs: 'Defs',
stop: 'Stop',
}

const reverse = Object.keys(supportedElements).reduce(
(map, key) => ({ ...map, [supportedElements[key]]: key }),
{},
)

const toReactNative = () => ({
visitor: {
JSXElement: {
enter(path) {
if (supportedElements[path.node.name]) {
path.node.name = supportedElements[path.node.name]
} else if (!reverse[path.node.name]) {
path.remove()
}
},
},
},
})

export default toReactNative
24 changes: 24 additions & 0 deletions src/h2x/toReactNative.test.js
@@ -0,0 +1,24 @@
import jsx from 'h2x-plugin-jsx'
import h2x from '../plugins/h2x'
import toReactNative from './toReactNative'

describe('toReactNative', () => {
it('should take svg and convert it to react-native', () => {
const result = h2x(
`
<svg>
<g stroke="#063855" stroke-width="2">
<path d="M51,37 L37,51" id="Shape"></path>
</g>
</svg>
`,
{ plugins: [jsx, toReactNative] },
)

expect(result.trim()).toBe(`<Svg>
<G stroke="#063855" strokeWidth={2}>
<Path d="M51,37 L37,51" id="Shape" />
</G>
</Svg>`)
})
})
32 changes: 32 additions & 0 deletions src/index.test.js
Expand Up @@ -96,6 +96,38 @@ describe('convert', () => {
expect(result).toMatchSnapshot()
})


it('should support react-native', async () => {
const result = await convert(
`
<?xml version="1.0" encoding="UTF-8"?>
<svg width="88px" height="88px" viewBox="0 0 88 88" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Dismiss</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<style>
#Blocks {
fill: red;
}
</style>
<g id="Blocks" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square">
<g id="Dismiss" stroke="#063855" stroke-width="2">
<path d="M51,37 L37,51" id="Shape"></path>
<path d="M51,51 L37,37" id="Shape"></path>
</g>
<style>
#Shape {}
</style>
</g>
</svg>
`,
{}
)

expect(result).toMatchSnapshot()
})

it('should convert style attribute', async () => {
const result = await convert(
`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Expand Down
22 changes: 22 additions & 0 deletions src/transforms/wrapIntoNativeComponent.js
@@ -0,0 +1,22 @@
export default (opts = {}) => (code, state) => `import React from 'react'
import Svg, {
Circle,
Ellipse,
G,
LinearGradient,
RadialGradient,
Line,
Path,
Polygon,
Polyline,
Rect,
Symbol,
Text,
Use,
Defs,
Stop
} from 'react-native-svg';
const ${state.componentName} = (${opts.expandProps ? 'props' : ''}) => ${code}
export default ${state.componentName}`

0 comments on commit 76fd6f5

Please sign in to comment.