diff --git a/packages/babel-plugin-transform-react-native-svg/src/index.js b/packages/babel-plugin-transform-react-native-svg/src/index.js index 93f21649..2ec96c6a 100644 --- a/packages/babel-plugin-transform-react-native-svg/src/index.js +++ b/packages/babel-plugin-transform-react-native-svg/src/index.js @@ -23,7 +23,15 @@ const elementToComponent = { image: 'Image', } -const plugin = ({ types: t }) => { +const expoPrefix = (component, expo) => { + // Prefix with 'Svg.' in the case we're transforming for Expo + if (!expo) { + return component + } + return (component !== 'Svg' ? 'Svg.' : '') + component +} + +const plugin = ({ types: t }, { expo }) => { function replaceElement(path, state) { const { name } = path.node.openingElement.name @@ -31,13 +39,14 @@ const plugin = ({ types: t }) => { const component = elementToComponent[name] if (component) { + const prefixedComponent = expoPrefix(component, expo) const openingElementName = path.get('openingElement.name') - openingElementName.replaceWith(t.jsxIdentifier(component)) + openingElementName.replaceWith(t.jsxIdentifier(prefixedComponent)) if (path.has('closingElement')) { const closingElementName = path.get('closingElement.name') - closingElementName.replaceWith(t.jsxIdentifier(component)) + closingElementName.replaceWith(t.jsxIdentifier(prefixedComponent)) } - state.replacedComponents.add(component) + state.replacedComponents.add(prefixedComponent) return } @@ -65,26 +74,31 @@ const plugin = ({ types: t }) => { const importDeclarationVisitor = { ImportDeclaration(path, state) { - if (!path.get('source').isStringLiteral({ value: 'react-native-svg' })) { - return - } - - state.replacedComponents.forEach(component => { - if ( - path - .get('specifiers') - .some(specifier => - specifier.get('local').isIdentifier({ name: component }), - ) - ) { - return - } + if (path.get('source').isStringLiteral({ value: 'react-native-svg' })) { + state.replacedComponents.forEach(component => { + if ( + path + .get('specifiers') + .some(specifier => + specifier.get('local').isIdentifier({ name: component }), + ) + ) { + return + } + path.pushContainer( + 'specifiers', + t.importSpecifier(t.identifier(component), t.identifier(component)), + ) + }) + } else if (path.get('source').isStringLiteral({ value: 'expo' })) { path.pushContainer( 'specifiers', - t.importSpecifier(t.identifier(component), t.identifier(component)), + t.importSpecifier(t.identifier('Svg'), t.identifier('Svg')), ) - }) + } else { + return + } if (state.unsupportedComponents.size && !path.has('trailingComments')) { const componentList = [...state.unsupportedComponents].join(', ') diff --git a/packages/babel-plugin-transform-react-native-svg/src/index.test.js b/packages/babel-plugin-transform-react-native-svg/src/index.test.js index 0f634b97..35d004e2 100644 --- a/packages/babel-plugin-transform-react-native-svg/src/index.test.js +++ b/packages/babel-plugin-transform-react-native-svg/src/index.test.js @@ -25,6 +25,19 @@ describe('plugin', () => { /* SVGR has dropped some elements not supported by react-native-svg: div */ ;" +`) + }) + + it('should transform for expo import', () => { + const { code } = testPlugin(`import 'expo';
;`, { + expo: true, + }) + + expect(code).toMatchInlineSnapshot(` +"import { Svg } from 'expo'; +/* SVGR has dropped some elements not supported by react-native-svg: div */ + +;" `) }) }) diff --git a/packages/babel-plugin-transform-svg-component/src/index.test.js b/packages/babel-plugin-transform-svg-component/src/index.test.js index 1120de00..7cece3a1 100644 --- a/packages/babel-plugin-transform-svg-component/src/index.test.js +++ b/packages/babel-plugin-transform-svg-component/src/index.test.js @@ -20,6 +20,36 @@ describe('plugin', () => { const SvgComponent = () =>
; +export default SvgComponent;" +`) + }) + + it('should add import for react-native-svg', () => { + const { code } = testPlugin('
', { + state: { componentName: 'SvgComponent' }, + native: true, + }) + expect(code).toMatchInlineSnapshot(` +"import React from \\"react\\"; +import Svg from \\"react-native-svg\\"; + +const SvgComponent = () =>
; + +export default SvgComponent;" +`) + }) + + it('should import for expo', () => { + const { code } = testPlugin('
', { + state: { componentName: 'SvgComponent' }, + native: { expo: true }, + }) + expect(code).toMatchInlineSnapshot(` +"import React from \\"react\\"; +import \\"expo\\"; + +const SvgComponent = () =>
; + export default SvgComponent;" `) }) diff --git a/packages/babel-plugin-transform-svg-component/src/util.js b/packages/babel-plugin-transform-svg-component/src/util.js index 0ca060b5..18870b6f 100644 --- a/packages/babel-plugin-transform-svg-component/src/util.js +++ b/packages/babel-plugin-transform-svg-component/src/util.js @@ -47,12 +47,16 @@ export const getImport = ({ types: t }, opts) => { ] if (opts.native) { - importDeclarations.push( - t.importDeclaration( - [t.importDefaultSpecifier(t.identifier('Svg'))], - t.stringLiteral('react-native-svg'), - ), - ) + if (opts.native.expo) { + importDeclarations.push(t.importDeclaration([], t.stringLiteral('expo'))) + } else { + importDeclarations.push( + t.importDeclaration( + [t.importDefaultSpecifier(t.identifier('Svg'))], + t.stringLiteral('react-native-svg'), + ), + ) + } } return importDeclarations diff --git a/packages/babel-preset/src/index.js b/packages/babel-preset/src/index.js index cc1c40a7..ef28b66d 100644 --- a/packages/babel-preset/src/index.js +++ b/packages/babel-preset/src/index.js @@ -90,7 +90,11 @@ const plugin = (api, opts) => { } if (opts.native) { - plugins.push(transformReactNativeSVG) + if (opts.native.expo) { + plugins.push([transformReactNativeSVG, opts.native]) + } else { + plugins.push(transformReactNativeSVG) + } } return { plugins } diff --git a/packages/babel-preset/src/index.test.js b/packages/babel-preset/src/index.test.js index 857ff534..a10f3609 100644 --- a/packages/babel-preset/src/index.test.js +++ b/packages/babel-preset/src/index.test.js @@ -29,6 +29,24 @@ describe('preset', () => { const SvgComponent = () => ; +export default SvgComponent;" +`) + }) + + it('should handle native expo option', () => { + expect( + testPreset('', { + native: { expo: true }, + state: { + componentName: 'SvgComponent', + }, + }), + ).toMatchInlineSnapshot(` +"import React from \\"react\\"; +import { Svg } from \\"expo\\"; + +const SvgComponent = () => ; + export default SvgComponent;" `) }) diff --git a/packages/core/src/__snapshots__/convert.test.js.snap b/packages/core/src/__snapshots__/convert.test.js.snap index 92f31af3..3cef5e7b 100644 --- a/packages/core/src/__snapshots__/convert.test.js.snap +++ b/packages/core/src/__snapshots__/convert.test.js.snap @@ -106,6 +106,28 @@ export default SvgComponent " `; +exports[`convert config should support options { native: { expo: true } } 1`] = ` +"import React from 'react' +import { Svg } from 'expo' + +const SvgComponent = props => ( + + + + + +) + +export default SvgComponent +" +`; + exports[`convert config should support options { native: true, expandProps: false } 1`] = ` "import React from 'react' import Svg, { G, Path } from 'react-native-svg' diff --git a/packages/core/src/convert.test.js b/packages/core/src/convert.test.js index afdf2406..cfde68c0 100644 --- a/packages/core/src/convert.test.js +++ b/packages/core/src/convert.test.js @@ -293,6 +293,7 @@ describe('convert', () => { { expandProps: 'start' }, { icon: true }, { native: true }, + { native: { expo: true } }, { native: true, icon: true }, { native: true, expandProps: false }, { native: true, ref: true }, diff --git a/website/src/pages/docs/options.mdx b/website/src/pages/docs/options.mdx index 468bf5de..10ae5d2a 100644 --- a/website/src/pages/docs/options.mdx +++ b/website/src/pages/docs/options.mdx @@ -47,9 +47,11 @@ inherits from text size. Modify all SVG nodes with uppercase and use a specific template with [`react-native-svg`](https://github.com/react-native-community/react-native-svg) imports. **All unsupported nodes will be removed.** +Override using the API with `native: { expo: true }` to template SVG nodes with the [ExpoKit SVG package](https://docs.expo.io/versions/latest/sdk/svg/). This is only necessary for 'ejected' ExpoKit projects where `import 'react-native-svg'` results in an error. + | Default | CLI Override | API Override | | ------- | ------------ | ---------------- | -| `false` | `--native` | `native: ` | +| `false` | `--native` | `native: ` or `native: { expo: true }` | ## Dimensions