Skip to content

Commit

Permalink
fix: wrap svg component directly with memo/forwardRef (#440) (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
katywings committed Apr 27, 2020
1 parent f30bb85 commit a6de2da
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,22 @@ export default SvgComponent;"
exports[`plugin javascript with "ref" and "expandProps" option expands props 1`] = `
"import * as React from \\"react\\";
function SvgComponent({
svgRef,
...props
}) {
function SvgComponent(props, svgRef) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef((props, ref) => <SvgComponent svgRef={ref} {...props} />);
const ForwardRef = React.forwardRef(SvgComponent);
export default ForwardRef;"
`;
exports[`plugin javascript with "ref" option adds ForwardRef component 1`] = `
"import * as React from \\"react\\";
function SvgComponent({
svgRef
}) {
function SvgComponent(props, svgRef) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef((props, ref) => <SvgComponent svgRef={ref} {...props} />);
const ForwardRef = React.forwardRef(SvgComponent);
export default ForwardRef;"
`;
Expand All @@ -127,18 +122,30 @@ function SvgComponent({
export default SvgComponent;"
`;
exports[`plugin javascript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
exports[`plugin javascript with "titleProp" and "expandProps" adds "titleProp", "titleId" props and expands props 1`] = `
"import * as React from \\"react\\";
function SvgComponent({
svgRef
title,
titleId,
...props
}) {
return <svg><g /></svg>;
}
const MemoSvgComponent = React.memo(SvgComponent);
const ForwardRef = React.forwardRef((props, ref) => <MemoSvgComponent svgRef={ref} {...props} />);
export default ForwardRef;"
export default SvgComponent;"
`;
exports[`plugin javascript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
"import * as React from \\"react\\";
function SvgComponent(props, svgRef) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef(SvgComponent);
const MemoForwardRef = React.memo(ForwardRef);
export default MemoForwardRef;"
`;
exports[`plugin typescript custom templates support basic template 1`] = `
Expand Down Expand Up @@ -214,34 +221,23 @@ export default SvgComponent;"
exports[`plugin typescript with "ref" and "expandProps" option expands props 1`] = `
"import * as React from \\"react\\";
interface SVGRProps {
svgRef?: React.Ref<SVGSVGElement>
}
function SvgComponent({
svgRef,
...props
}: React.SVGProps<SVGSVGElement> & SVGRProps) {
function SvgComponent(props: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement>) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef((props, ref: React.Ref<SVGSVGElement>) => <SvgComponent svgRef={ref} {...props} />);
const ForwardRef = React.forwardRef(SvgComponent);
export default ForwardRef;"
`;
exports[`plugin typescript with "ref" option adds ForwardRef component 1`] = `
"import * as React from \\"react\\";
interface SVGRProps {
svgRef?: React.Ref<SVGSVGElement>
}
function SvgComponent({
svgRef
}: SVGRProps) {
function SvgComponent(props: {}, svgRef?: React.Ref<SVGSVGElement>) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef((props, ref: React.Ref<SVGSVGElement>) => <SvgComponent svgRef={ref} {...props} />);
const ForwardRef = React.forwardRef(SvgComponent);
export default ForwardRef;"
`;
Expand All @@ -262,19 +258,32 @@ function SvgComponent({
export default SvgComponent;"
`;
exports[`plugin typescript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
exports[`plugin typescript with "titleProp" and "expandProps" adds "titleProp", "titleId" props and expands props 1`] = `
"import * as React from \\"react\\";
interface SVGRProps {
svgRef?: React.Ref<SVGSVGElement>
title?: string,
titleId?: string,
}
function SvgComponent({
svgRef
}: SVGRProps) {
title,
titleId,
...props
}: React.SVGProps<SVGSVGElement> & SVGRProps) {
return <svg><g /></svg>;
}
const MemoSvgComponent = React.memo(SvgComponent);
const ForwardRef = React.forwardRef((props, ref: React.Ref<SVGSVGElement>) => <MemoSvgComponent svgRef={ref} {...props} />);
export default ForwardRef;"
export default SvgComponent;"
`;
exports[`plugin typescript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
"import * as React from \\"react\\";
function SvgComponent(props: {}, svgRef?: React.Ref<SVGSVGElement>) {
return <svg><g /></svg>;
}
const ForwardRef = React.forwardRef(SvgComponent);
const MemoForwardRef = React.memo(ForwardRef);
export default MemoForwardRef;"
`;
11 changes: 11 additions & 0 deletions packages/babel-plugin-transform-svg-component/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ describe('plugin', () => {
})
})

describe('with "titleProp" and "expandProps"', () => {
it('adds "titleProp", "titleId" props and expands props', () => {
const { code } = testPlugin(language)('<svg><g /></svg>', {
state: { componentName: 'SvgComponent' },
expandProps: true,
titleProp: true,
})
expect(code).toMatchSnapshot()
})
})

describe('with "expandProps"', () => {
it('add props', () => {
const { code } = testPlugin(language)('<svg><g /></svg>', {
Expand Down
94 changes: 43 additions & 51 deletions packages/babel-plugin-transform-svg-component/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,6 @@ function getSvgPropsTypeAnnotation(t) {
export const getProps = ({ types: t }, opts) => {
const props = []

if (opts.ref) {
props.push(
t.objectProperty(
t.identifier('svgRef'),
t.identifier('svgRef'),
false,
true,
),
)
}

if (opts.titleProp) {
props.push(
t.objectProperty(
Expand All @@ -103,53 +92,62 @@ export const getProps = ({ types: t }, opts) => {
)
}

if (opts.expandProps) {
if (opts.expandProps && props.length > 0) {
props.push(t.restElement(t.identifier('props')))
}

if (props.length === 0) {
return null
}
const propsArgument =
props.length > 0 ? t.objectPattern(props) : t.identifier('props')
let propsTypeAnnotation
if (props.length > 0) {
propsTypeAnnotation = genericTypeAnnotation(t.identifier('SVGRProps'))

if (props.length === 1 && opts.expandProps) {
return addTypeAnotation(
t.identifier('props'),
typeAnnotation(getSvgPropsTypeAnnotation(t)),
opts,
)
if (opts.expandProps) {
propsTypeAnnotation = intersectionTypeAnnotation([
getSvgPropsTypeAnnotation(t),
propsTypeAnnotation,
])
}
} else {
propsTypeAnnotation = opts.expandProps
? getSvgPropsTypeAnnotation(t)
: t.objectPattern([])
}

return addTypeAnotation(
t.objectPattern(props),
typeAnnotation(
opts.expandProps
? intersectionTypeAnnotation([
getSvgPropsTypeAnnotation(t),
genericTypeAnnotation(t.identifier('SVGRProps')),
])
: genericTypeAnnotation(t.identifier('SVGRProps')),
),
const typedPropsArgument = addTypeAnotation(
propsArgument,
typeAnnotation(propsTypeAnnotation),
opts,
)
}

export const getInterface = ({ types: t }, opts) => {
if (!opts.typescript) return null
const properties = []
const args = []
if (opts.expandProps || props.length > 0 || opts.ref)
args.push(typedPropsArgument)

if (opts.ref) {
properties.push(
objectTypeProperty(
t.identifier('svgRef'),
const refArgument = t.identifier(opts.typescript ? 'svgRef?' : 'svgRef')
const typedRefArgument = addTypeAnotation(
refArgument,
typeAnnotation(
genericTypeAnnotation(
qualifiedTypeIdentifier(t.identifier('React'), t.identifier('Ref')),
typeParameters([
genericTypeAnnotation(t.identifier('SVGSVGElement')),
]),
),
true,
),
opts,
)

args.push(typedRefArgument)
}

return args
}

export const getInterface = ({ types: t }, opts) => {
if (!opts.typescript) return null
const properties = []
if (opts.titleProp) {
properties.push(
objectTypeProperty(t.identifier('title'), t.identifier('string'), true),
Expand Down Expand Up @@ -198,21 +196,15 @@ export const getExport = ({ template }, opts) => {
plugins.push('typescript')
}

if (opts.memo) {
const nextExportName = `Memo${exportName}`
result += `const ${nextExportName} = React.memo(${exportName})\n\n`
exportName = nextExportName
}

if (opts.ref) {
const nextExportName = `ForwardRef`
let refType = ''

if (opts.typescript) {
refType = ': React.Ref<SVGSVGElement>'
}
result += `const ${nextExportName} = React.forwardRef(${exportName})\n\n`
exportName = nextExportName
}

result += `const ${nextExportName} = React.forwardRef((props, ref${refType}) => <${exportName} svgRef={ref} {...props} />)\n\n`
if (opts.memo) {
const nextExportName = `Memo${exportName}`
result += `const ${nextExportName} = React.memo(${exportName})\n\n`
exportName = nextExportName
}

Expand Down
Loading

1 comment on commit a6de2da

@vercel
Copy link

@vercel vercel bot commented on a6de2da Apr 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.