├── .node-version ├── .husky └── pre-push ├── tests ├── fixtures │ ├── pct-unit.svg │ ├── with-style-and-data.svg │ ├── edge-case-width.svg │ ├── simple.svg │ ├── with-stroke.svg │ ├── matrix-negative.svg │ ├── with-fill.svg │ ├── clean.svg │ └── sketch-export.svg └── components │ ├── with-web │ ├── SVGPctUnit.js │ ├── SVGWithStyleAndData.js │ ├── SVGEdgeCaseWidth.js │ ├── SVGSimple.js │ ├── SVGWithStroke.js │ ├── SVGClean.js │ ├── SVGWithFill.js │ ├── SVGMatrixNegative.js │ └── SVGSketchExport.js │ ├── with-native_with-web │ ├── SVGPctUnit.web.js │ ├── SVGWithStyleAndData.web.js │ ├── SVGEdgeCaseWidth.web.js │ ├── SVGSimple.web.js │ ├── SVGPctUnit.js │ ├── SVGWithStyleAndData.js │ ├── SVGEdgeCaseWidth.js │ ├── SVGWithStroke.web.js │ ├── SVGSimple.js │ ├── SVGClean.web.js │ ├── SVGWithFill.web.js │ ├── SVGMatrixNegative.web.js │ ├── SVGSketchExport.web.js │ ├── SVGWithStroke.js │ ├── SVGClean.js │ ├── SVGWithFill.js │ ├── SVGMatrixNegative.js │ └── SVGSketchExport.js │ ├── with-web-for-typescript │ ├── SVGPctUnit.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGSimple.tsx │ ├── SVGWithStroke.tsx │ ├── SVGClean.tsx │ ├── SVGWithFill.tsx │ ├── SVGMatrixNegative.tsx │ └── SVGSketchExport.tsx │ ├── with-native-for-typescript_with-web-for-typescript │ ├── SVGPctUnit.web.tsx │ ├── SVGWithStyleAndData.web.tsx │ ├── SVGEdgeCaseWidth.web.tsx │ ├── SVGSimple.web.tsx │ ├── SVGPctUnit.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGWithStroke.web.tsx │ ├── SVGClean.web.tsx │ ├── SVGSimple.tsx │ ├── SVGWithFill.web.tsx │ ├── SVGMatrixNegative.web.tsx │ ├── SVGSketchExport.web.tsx │ ├── SVGWithStroke.tsx │ ├── SVGClean.tsx │ ├── SVGWithFill.tsx │ ├── SVGMatrixNegative.tsx │ └── SVGSketchExport.tsx │ ├── with-native │ ├── SVGPctUnit.js │ ├── SVGWithStyleAndData.js │ ├── SVGEdgeCaseWidth.js │ ├── SVGSimple.js │ ├── SVGWithStroke.js │ ├── SVGClean.js │ ├── SVGWithFill.js │ ├── SVGMatrixNegative.js │ └── SVGSketchExport.js │ ├── with-native-for-typescript │ ├── SVGPctUnit.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGSimple.tsx │ ├── SVGWithStroke.tsx │ ├── SVGClean.tsx │ ├── SVGWithFill.tsx │ ├── SVGMatrixNegative.tsx │ └── SVGSketchExport.tsx │ ├── with-native-for-typescript_remove-fill │ ├── SVGPctUnit.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGSimple.tsx │ ├── SVGWithStroke.tsx │ ├── SVGWithFill.tsx │ ├── SVGClean.tsx │ ├── SVGSketchExport.tsx │ └── SVGMatrixNegative.tsx │ ├── with-native-for-typescript_remove-stroke │ ├── SVGPctUnit.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGSimple.tsx │ ├── SVGWithStroke.tsx │ ├── SVGClean.tsx │ ├── SVGWithFill.tsx │ ├── SVGSketchExport.tsx │ └── SVGMatrixNegative.tsx │ ├── with-native-for-typescript_allow-override-fill │ ├── SVGPctUnit.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGSimple.tsx │ ├── SVGClean.tsx │ ├── SVGWithStroke.tsx │ ├── SVGMatrixNegative.tsx │ ├── SVGSketchExport.tsx │ └── SVGWithFill.tsx │ └── with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill │ ├── SVGPctUnit.tsx │ ├── SVGEdgeCaseWidth.tsx │ ├── SVGWithStyleAndData.tsx │ ├── SVGSimple.tsx │ ├── SVGClean.tsx │ ├── SVGWithStroke.tsx │ ├── SVGMatrixNegative.tsx │ ├── SVGSketchExport.tsx │ └── SVGWithFill.tsx ├── .gitignore ├── src ├── case.ts ├── bin.ts ├── templates.ts ├── adjust-svg.ts ├── all-combinations.test.ts └── transformer.ts ├── tsconfig.json ├── .github └── workflows │ └── build.yml ├── LICENSE ├── package.json ├── README.md └── CHANGELOG.md /.node-version: -------------------------------------------------------------------------------- 1 | 24 2 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | npm test 2 | -------------------------------------------------------------------------------- /tests/fixtures/pct-unit.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macos crap 2 | .DS_Store 3 | 4 | # node 5 | node_modules 6 | 7 | # build 8 | dist 9 | -------------------------------------------------------------------------------- /tests/fixtures/with-style-and-data.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/case.ts: -------------------------------------------------------------------------------- 1 | import camelCase from "camelcase"; 2 | 3 | export const toCamel = (s: string): string => 4 | camelCase(s, { pascalCase: false }); 5 | export const toPascal = (s: string): string => 6 | camelCase(s, { pascalCase: true }); 7 | -------------------------------------------------------------------------------- /tests/fixtures/edge-case-width.svg: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGPctUnit.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGPctUnit = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGPctUnit; 12 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGPctUnit.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGPctUnit = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGPctUnit; 12 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGPctUnit = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGPctUnit; 12 | -------------------------------------------------------------------------------- /tests/fixtures/simple.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGPctUnit.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGPctUnit = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGPctUnit; 12 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGWithStyleAndData.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStyleAndData = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default SVGWithStyleAndData; 13 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithStyleAndData.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStyleAndData = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default SVGWithStyleAndData; 13 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGEdgeCaseWidth.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGEdgeCaseWidth = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGEdgeCaseWidth; 12 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStyleAndData = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default SVGWithStyleAndData; 13 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGEdgeCaseWidth.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGEdgeCaseWidth = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGEdgeCaseWidth; 12 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithStyleAndData.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStyleAndData = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 9 | ); 10 | }; 11 | 12 | export default SVGWithStyleAndData; 13 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGEdgeCaseWidth = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGEdgeCaseWidth; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "moduleResolution": "NodeNext", 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "jsx": "react", 10 | "outDir": "dist", 11 | "rootDir": "src" 12 | }, 13 | "ts-node": { 14 | "compilerOptions": { 15 | "module": "NodeNext" 16 | } 17 | }, 18 | "exclude": ["tests/**"] 19 | } 20 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGEdgeCaseWidth.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGEdgeCaseWidth = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGEdgeCaseWidth; 12 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGSimple.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSimple = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGSimple; 20 | -------------------------------------------------------------------------------- /tests/fixtures/with-stroke.svg: -------------------------------------------------------------------------------- 1 | 2 | ionicons-v5-h 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGSimple.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSimple = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGSimple; 20 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSimple = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGSimple; 20 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGSimple.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSimple = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGSimple; 20 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGPctUnit.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGPctUnit = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGPctUnit; 37 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGPctUnit.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGPctUnit = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGPctUnit; 37 | -------------------------------------------------------------------------------- /tests/fixtures/matrix-negative.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGPctUnit = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGPctUnit; 38 | -------------------------------------------------------------------------------- /tests/fixtures/with-fill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGPctUnit = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGPctUnit; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGPctUnit = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGPctUnit; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGPctUnit = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGPctUnit; 38 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGWithStyleAndData.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithStyleAndData = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGWithStyleAndData; 38 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithStyleAndData.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithStyleAndData = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGWithStyleAndData; 38 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGEdgeCaseWidth.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGEdgeCaseWidth = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGEdgeCaseWidth; 37 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGEdgeCaseWidth.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGEdgeCaseWidth = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGEdgeCaseWidth; 37 | -------------------------------------------------------------------------------- /tests/fixtures/clean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStyleAndData = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGWithStyleAndData; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStyleAndData = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGWithStyleAndData; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStyleAndData = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGWithStyleAndData; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStyleAndData = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGWithStyleAndData; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGEdgeCaseWidth = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGEdgeCaseWidth; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGPctUnit = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGPctUnit; 42 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGEdgeCaseWidth = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGEdgeCaseWidth; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGEdgeCaseWidth = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGEdgeCaseWidth; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGPctUnit.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGPctUnit = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGPctUnit; 42 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGEdgeCaseWidth = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGEdgeCaseWidth; 38 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGWithStroke.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStroke = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 15 | 26 | 27 | ); 28 | }; 29 | 30 | export default SVGWithStroke; 31 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithStroke.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStroke = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 15 | 26 | 27 | ); 28 | }; 29 | 30 | export default SVGWithStroke; 31 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStroke = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 15 | 26 | 27 | ); 28 | }; 29 | 30 | export default SVGWithStroke; 31 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGSimple.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGSimple = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGSimple; 45 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGSimple.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGSimple = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGSimple; 45 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGClean.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGClean = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGClean; 12 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithStroke.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithStroke = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 15 | 26 | 27 | ); 28 | }; 29 | 30 | export default SVGWithStroke; 31 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: [main] 6 | push: 7 | branches: [main] 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest, windows-latest] 14 | runs-on: ${{ matrix.os }} 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Use Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version-file: "package.json" 23 | cache: "npm" 24 | 25 | - name: Handle Next.js Cache 26 | uses: actions/cache@v4 27 | with: 28 | path: .next/cache 29 | key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} 30 | restore-keys: | 31 | ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- 32 | 33 | - name: Install dependencies 34 | run: npm ci 35 | 36 | - name: Test 37 | run: npm run test 38 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGClean.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGClean = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGClean; 12 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGWithFill.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithFill = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGWithFill; 20 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGEdgeCaseWidth = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGEdgeCaseWidth; 42 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithFill.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithFill = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGWithFill; 20 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGClean = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGClean; 12 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSimple = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGSimple; 45 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSimple = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGSimple; 45 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGEdgeCaseWidth.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGEdgeCaseWidth = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGEdgeCaseWidth; 42 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSimple = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGSimple; 46 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithFill = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGWithFill; 20 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGClean.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGClean = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | ); 9 | }; 10 | 11 | export default SVGClean; 12 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSimple = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGSimple; 46 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithFill.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGWithFill = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 8 | 14 | 15 | 16 | ); 17 | }; 18 | 19 | export default SVGWithFill; 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Maxime Thirouin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGMatrixNegative.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGMatrixNegative = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGMatrixNegative; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithStyleAndData = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 47 | 48 | ); 49 | }; 50 | 51 | export default SVGWithStyleAndData; 52 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGMatrixNegative.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGMatrixNegative = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGMatrixNegative; 39 | -------------------------------------------------------------------------------- /tests/components/with-web/SVGSketchExport.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSketchExport = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 14 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default SVGSketchExport; 26 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGWithStyleAndData.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithStyleAndData = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 47 | 48 | ); 49 | }; 50 | 51 | export default SVGWithStyleAndData; 52 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGSketchExport.web.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSketchExport = (props) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 14 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default SVGSketchExport; 26 | -------------------------------------------------------------------------------- /tests/fixtures/sketch-export.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | chevron 7 | Created with Sketch. 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGMatrixNegative = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGMatrixNegative; 39 | -------------------------------------------------------------------------------- /tests/components/with-web-for-typescript/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSketchExport = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 14 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default SVGSketchExport; 26 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGMatrixNegative.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGMatrixNegative = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | 26 | 34 | 35 | ); 36 | }; 37 | 38 | export default SVGMatrixNegative; 39 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGSketchExport.web.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const SVGSketchExport = (props: React.SVGProps) => { 3 | return ( 4 | 5 | {props.children} 6 | 7 | 14 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default SVGSketchExport; 26 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGWithStroke.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithStroke = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 40 | 51 | 52 | ); 53 | }; 54 | 55 | export default SVGWithStroke; 56 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithStroke.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithStroke = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 40 | 51 | 52 | ); 53 | }; 54 | 55 | export default SVGWithStroke; 56 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGSimple = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 49 | 50 | ); 51 | }; 52 | 53 | export default SVGSimple; 54 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGSimple.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGSimple = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 48 | 49 | ); 50 | }; 51 | 52 | export default SVGSimple; 53 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStroke = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 40 | 50 | 51 | ); 52 | }; 53 | 54 | export default SVGWithStroke; 55 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStroke = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 40 | 50 | 51 | ); 52 | }; 53 | 54 | export default SVGWithStroke; 55 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGClean.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGClean = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGClean; 37 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStroke = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 41 | 52 | 53 | ); 54 | }; 55 | 56 | export default SVGWithStroke; 57 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGClean.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGClean = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | ); 34 | }; 35 | 36 | export default SVGClean; 37 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGWithFill.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithFill = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGWithFill; 45 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithStroke = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 41 | 52 | 53 | ); 54 | }; 55 | 56 | export default SVGWithStroke; 57 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGWithFill.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGWithFill = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 33 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGWithFill; 45 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithFill = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGWithFill; 45 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGClean = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGClean; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGClean = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGClean; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGClean = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGClean; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithFill = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGWithFill; 46 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGClean = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default SVGClean; 38 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithFill = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGWithFill; 46 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGWithFill = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGWithFill; 46 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSketchExport = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default SVGSketchExport; 45 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGMatrixNegative.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGMatrixNegative = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 51 | 59 | 60 | ); 61 | }; 62 | 63 | export default SVGMatrixNegative; 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-from-svg", 3 | "description": "Transform SVG files into React components, Native and/or Web, JavaScript and TypeScript. Without shitload of dependencies.", 4 | "version": "8.0.2", 5 | "license": "MIT", 6 | "repository": "https://github.com/MoOx/react-from-svg", 7 | "author": { 8 | "name": "Maxime Thirouin", 9 | "url": "https://github.com/MoOx" 10 | }, 11 | "type": "module", 12 | "exports": "./dist/bin.js", 13 | "keywords": [ 14 | "react-native-svg", 15 | "react-native-web", 16 | "react-native", 17 | "react", 18 | "svg-to-react", 19 | "svg", 20 | "svgr-cli", 21 | "svgr" 22 | ], 23 | "bin": { 24 | "react-from-svg": "./dist/bin.js" 25 | }, 26 | "files": [ 27 | "dist", 28 | "!dist/**.test.js" 29 | ], 30 | "scripts": { 31 | "prepare": "husky", 32 | "build": "tsc", 33 | "format:generated": "prettier --write tests/components", 34 | "test:build:all": "node dist/all-combinations.test.js", 35 | "test": "npm run build && npm run test:build:all", 36 | "prepublishOnly": "npm run build", 37 | "release": "npmpub" 38 | }, 39 | "dependencies": { 40 | "camelcase": "^8.0.0", 41 | "glob": "^11.0.1", 42 | "meow": "^13.2.0", 43 | "mkdirp": "^3.0.1" 44 | }, 45 | "devDependencies": { 46 | "@types/react": "^19.1.0", 47 | "husky": "^9.1.7", 48 | "npmpub": "^5.0.0", 49 | "prettier": "^3.5.3", 50 | "react": "^19.1.0", 51 | "react-native-svg": "^15.11.2", 52 | "typescript": "^5.8.0" 53 | }, 54 | "prettier": { 55 | "trailingComma": "all" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGMatrixNegative.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGMatrixNegative = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 51 | 59 | 60 | ); 61 | }; 62 | 63 | export default SVGMatrixNegative; 64 | -------------------------------------------------------------------------------- /tests/components/with-native/SVGSketchExport.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGSketchExport = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 39 | 45 | 46 | 47 | ); 48 | }; 49 | 50 | export default SVGSketchExport; 51 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSketchExport = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 34 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default SVGSketchExport; 46 | -------------------------------------------------------------------------------- /tests/components/with-native_with-web/SVGSketchExport.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | const SVGSketchExport = (props) => { 28 | return ( 29 | 30 | {props.children} 31 | 32 | 39 | 45 | 46 | 47 | ); 48 | }; 49 | 50 | export default SVGSketchExport; 51 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGClean = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGClean; 42 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGClean.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGClean = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 38 | ); 39 | }; 40 | 41 | export default SVGClean; 42 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGMatrixNegative = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 59 | 60 | ); 61 | }; 62 | 63 | export default SVGMatrixNegative; 64 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-stroke/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGMatrixNegative = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 59 | 60 | ); 61 | }; 62 | 63 | export default SVGMatrixNegative; 64 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGMatrixNegative = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 60 | 61 | ); 62 | }; 63 | 64 | export default SVGMatrixNegative; 65 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSketchExport = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 40 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default SVGSketchExport; 52 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGMatrixNegative = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 60 | 61 | ); 62 | }; 63 | 64 | export default SVGMatrixNegative; 65 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_with-web-for-typescript/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { SvgProps } from "react-native-svg"; 28 | const SVGSketchExport = (props: SvgProps) => { 29 | return ( 30 | 31 | {props.children} 32 | 33 | 40 | 46 | 47 | 48 | ); 49 | }; 50 | 51 | export default SVGSketchExport; 52 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithStroke = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 48 | 62 | 63 | ); 64 | }; 65 | 66 | export default SVGWithStroke; 67 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGWithStroke.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithStroke = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 49 | 64 | 65 | ); 66 | }; 67 | 68 | export default SVGWithStroke; 69 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGMatrixNegative = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 43 | 44 | 45 | 46 | 53 | 54 | 55 | 56 | 67 | 68 | ); 69 | }; 70 | 71 | export default SVGMatrixNegative; 72 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGMatrixNegative.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGMatrixNegative = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 43 | 44 | 45 | 46 | 53 | 54 | 55 | 56 | 68 | 69 | ); 70 | }; 71 | 72 | export default SVGMatrixNegative; 73 | -------------------------------------------------------------------------------- /src/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import meow from "meow"; 4 | import { make } from "./transformer.js"; 5 | 6 | const cli = meow( 7 | ` 8 | Usage 9 | $ react-from-svg [--with-native|--with-web] 10 | 11 | Options 12 | --with-native, -rn Output code for react-native-svg 13 | --with-native-for-typescript, -rnts Output code for react-native-svg with TypeScript 14 | --with-web, -rnw Output code for DOM. If --with-native is also used, will be output as .web.js files 15 | --with-web-for-typescript, -rnwts Output code for DOM with TypeScript. If --with-native is also used, will be output as .web.tsx files 16 | --remove-fill, -rf Remove all 'fill' properties from SVGs, convenient for icons 17 | --remove-stroke, -rs Remove all 'stroke' properties from SVGs, convenient for icons 18 | --allow-override-fill, -aof Replace all 'fill' properties by a dynamic prop (fills) in SVGs, e.g. fill={fills[N]}. 19 | 20 | Example 21 | $ react-from-svg src/svgs src/svgs/components --with-web-for-typescript --allow-override-fill 22 | `, 23 | { 24 | importMeta: import.meta, 25 | flags: { 26 | withNative: { type: "boolean", shortFlag: "rn" }, 27 | withNativeForTypescript: { type: "boolean", shortFlag: "rnts" }, 28 | withWeb: { type: "boolean", shortFlag: "rnw" }, 29 | withWebForTypescript: { type: "boolean", shortFlag: "rnwts" }, 30 | removeFill: { type: "boolean", shortFlag: "rf" }, 31 | removeStroke: { type: "boolean", shortFlag: "rs" }, 32 | allowOverrideFill: { type: "boolean", shortFlag: "aof" }, 33 | }, 34 | }, 35 | ); 36 | 37 | if ( 38 | cli.flags.withNative === undefined && 39 | cli.flags.withNativeForTypescript === undefined && 40 | cli.flags.withWeb === undefined && 41 | cli.flags.withWebForTypescript === undefined 42 | ) { 43 | console.error( 44 | "You should at least choose an output option (one of --with-*)!", 45 | ); 46 | cli.showHelp(); 47 | process.exit(1); 48 | } 49 | 50 | make(cli.input as [string, string], cli.flags); 51 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGSketchExport = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 48 | 58 | 59 | 60 | ); 61 | }; 62 | 63 | export default SVGSketchExport; 64 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGSketchExport.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGSketchExport = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 37 | 47 | 57 | 58 | 59 | ); 60 | }; 61 | 62 | export default SVGSketchExport; 63 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_allow-override-fill/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithFill = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 44 | 52 | 62 | 63 | 64 | ); 65 | }; 66 | 67 | export default SVGWithFill; 68 | -------------------------------------------------------------------------------- /tests/components/with-native-for-typescript_remove-fill_remove-stroke_allow-override-fill/SVGWithFill.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Svg, { 3 | Circle, 4 | ClipPath, 5 | Defs, 6 | Ellipse, 7 | ForeignObject, 8 | G, 9 | Image, 10 | Line, 11 | LinearGradient, 12 | Marker, 13 | Mask, 14 | Path, 15 | Pattern, 16 | Polygon, 17 | Polyline, 18 | RadialGradient, 19 | Rect, 20 | Stop, 21 | Symbol, 22 | Text, 23 | TextPath, 24 | TSpan as Tspan, 25 | Use, 26 | } from "react-native-svg"; 27 | import type { ColorValue } from "react-native"; 28 | import type { SvgProps } from "react-native-svg"; 29 | const SVGWithFill = ({ 30 | fills, 31 | ...props 32 | }: SvgProps & { fills?: (ColorValue | undefined)[] }) => { 33 | return ( 34 | 35 | {props.children} 36 | 44 | 52 | 62 | 63 | 64 | ); 65 | }; 66 | 67 | export default SVGWithFill; 68 | -------------------------------------------------------------------------------- /src/templates.ts: -------------------------------------------------------------------------------- 1 | const sep = ";\n"; 2 | 3 | // Helper for prop signature 4 | function getPropsSignature( 5 | allowOverrideFill: boolean, 6 | typescript: boolean, 7 | native: boolean, 8 | ): string { 9 | const fillsType = `{fills?: (${native ? "ColorValue" : "string"} | undefined)[]}`; 10 | const optionalPropsType = typescript 11 | ? ` : ${ 12 | native ? "SvgProps" : "React.SVGProps" 13 | }${allowOverrideFill ? " & " + fillsType : ""}` 14 | : ""; 15 | return `(${allowOverrideFill ? "{ fills, ...props }" : "props"}${optionalPropsType})`; 16 | } 17 | 18 | const importReact = (): string => { 19 | return "import React from 'react'"; 20 | }; 21 | 22 | const jsExport = ( 23 | name: string, 24 | svgOutput: string, 25 | allowOverrideFill: boolean = false, 26 | ): string => { 27 | const content = 28 | `const ${name} = ${getPropsSignature(allowOverrideFill, false, false)} => { 29 | return (${svgOutput}); 30 | }` + sep; 31 | return `${content} 32 | export default ${name}`; 33 | }; 34 | 35 | const tsxExport = ( 36 | name: string, 37 | svgOutput: string, 38 | native: boolean, 39 | allowOverrideFill: boolean = false, 40 | ): string => { 41 | const content = 42 | `const ${name} = ${getPropsSignature(allowOverrideFill, true, native)} => { 43 | return (${svgOutput}); 44 | }` + sep; 45 | return `${content} 46 | export default ${name}`; 47 | }; 48 | 49 | const web = ( 50 | svgOutput: string, 51 | name: string, 52 | allowOverrideFill: boolean = false, 53 | ): string => { 54 | return ( 55 | importReact() + sep + jsExport(name, svgOutput, allowOverrideFill) + sep 56 | ); 57 | }; 58 | 59 | const RNSvgModules = [ 60 | "Circle", 61 | "ClipPath", 62 | "Defs", 63 | "Ellipse", 64 | "ForeignObject", 65 | "G", 66 | "Image", 67 | "Line", 68 | "LinearGradient", 69 | "Marker", 70 | "Mask", 71 | "Path", 72 | "Pattern", 73 | "Polygon", 74 | "Polyline", 75 | "RadialGradient", 76 | "Rect", 77 | "Stop", 78 | "Symbol", 79 | "Text", 80 | "TextPath", 81 | "TSpan as Tspan", 82 | "Use", 83 | ]; 84 | 85 | const importReactNativeSvg = ( 86 | typescript: boolean, 87 | allowOverrideFill: boolean, 88 | ): string => { 89 | return `import Svg, { 90 | ${RNSvgModules.join(",")} 91 | } from 'react-native-svg';${ 92 | typescript && allowOverrideFill 93 | ? `import type { ColorValue } from 'react-native';` 94 | : "" 95 | }${typescript ? `import type { SvgProps } from 'react-native-svg';` : ""} 96 | `; 97 | }; 98 | 99 | const native = ( 100 | svgOutput: string, 101 | name: string, 102 | allowOverrideFill: boolean = false, 103 | ): string => { 104 | return ( 105 | importReact() + 106 | sep + 107 | importReactNativeSvg(false, allowOverrideFill) + 108 | sep + 109 | jsExport(name, svgOutput, allowOverrideFill) + 110 | sep 111 | ); 112 | }; 113 | 114 | const nativeForTypescript = ( 115 | svgOutput: string, 116 | name: string, 117 | allowOverrideFill: boolean = false, 118 | ): string => { 119 | return ( 120 | importReact() + 121 | sep + 122 | importReactNativeSvg(true, allowOverrideFill) + 123 | sep + 124 | tsxExport(name, svgOutput, true, allowOverrideFill) + 125 | sep 126 | ); 127 | }; 128 | 129 | const webForTypescript = ( 130 | svgOutput: string, 131 | name: string, 132 | allowOverrideFill: boolean = false, 133 | ): string => { 134 | return ( 135 | importReact() + 136 | sep + 137 | tsxExport(name, svgOutput, false, allowOverrideFill) + 138 | sep 139 | ); 140 | }; 141 | 142 | export { web, native, nativeForTypescript, webForTypescript }; 143 | -------------------------------------------------------------------------------- /src/adjust-svg.ts: -------------------------------------------------------------------------------- 1 | import { toCamel, toPascal } from "./case.js"; 2 | 3 | const tagsToRemove = ["title", "desc"]; 4 | 5 | const cleanupStart = (svg: string): string => { 6 | let result = svg 7 | .replace(/'/g, '"') 8 | .replace(/\sversion="1.1"/g, "") 9 | .replace(/<\?xml(.*)\?>/g, "") 10 | .replace(/\sxmlns="http:\/\/www\.w3\.org\/2000\/svg"/g, "") 11 | .replace(/\sxmlns:xlink="http:\/\/www.w3.org\/1999\/xlink"/g, "") 12 | .replace(//g, ""); 13 | 14 | // Remove tags with or without attributes 15 | tagsToRemove.forEach((tag) => { 16 | result = result.replace(new RegExp(`<${tag}[^>]*>.*?<\/${tag}>`, "gs"), ""); 17 | }); 18 | 19 | return result; 20 | }; 21 | 22 | const prepareSvgProps = (svg: string): string => { 23 | return svg 24 | .replace(/]*)?\swidth="[^"]*"/g, "]*)?\sheight="[^"]*"/g, "]*)?\sfill="[^"]*"/g, " { 30 | // Inject {...props} and {props.children} just after the opening tag of or 31 | // 1. Inject {...props} as before 32 | // 2. Immediately after, inject {props.children} 33 | // This ensures that children can be injected by React 34 | return svg 35 | .replace(/(\{\.\.\.props\}>)/, "$1{props.children}") 36 | .replace(/(>)/, " {...props}>{props.children}"); 37 | }; 38 | 39 | const dashToCamelCaseProps = (svg: string): string => { 40 | return svg.replace(/\s([a-z][a-z-]+[a-z])/g, (match, p1) => { 41 | if (p1.startsWith("data-") || p1.startsWith("aria-")) { 42 | return match; 43 | } 44 | return " " + toCamel(p1); 45 | }); 46 | }; 47 | 48 | const tagToPascalCase = (svg: string): string => { 49 | return svg.replace( 50 | /<(\/?)([a-z])/g, 51 | (_, p1, p2) => "<" + (p1 + toPascal(p2)), 52 | ); 53 | }; 54 | 55 | const cleanupEndWithoutSpace = (svg: string): string => { 56 | return svg.replace(/>\s+<"); 57 | }; 58 | 59 | const deleteFill = (svg: string): string => { 60 | return svg.replace(/ fill="[^"]*"/g, ""); 61 | }; 62 | 63 | const deleteStroke = (svg: string): string => { 64 | return svg.replace(/ stroke="[^"]*"/g, ""); 65 | }; 66 | 67 | const transformStyleAttributes = (svg: string): string => { 68 | return svg.replace(/ style="([^"]*)"/g, (_, styleContent) => { 69 | const styleObject = styleContent 70 | .split(";") 71 | .filter(Boolean) 72 | .map((style: string) => { 73 | const [property, value] = style.split(":").map((s: string) => s.trim()); 74 | return `"${toCamel(property)}": "${value}"`; 75 | }) 76 | .join(", "); 77 | 78 | return ` style={{${styleObject}}}`; 79 | }); 80 | }; 81 | 82 | // Replace each existing fill with fill={fills[N]} (N = index of occurrence) 83 | // If fills[N] is strictly undefined, keep the original value unless removeFill is true, then fallback to undefined 84 | function allowOverrideFillWithProp( 85 | svg: string, 86 | removeFill: boolean = false, 87 | ): string { 88 | let fillIndex = 0; 89 | return svg.replace( 90 | /(<(?!svg)[^\s>]+)([^>]*?)\sfill="([^"]*)"([^>]*>)/g, 91 | function ( 92 | match: string, 93 | startTag: string, 94 | beforeFill: string, 95 | fillValue: string, 96 | afterFill: string, 97 | ) { 98 | const idx = fillIndex++; 99 | // If removeFill: no fallback to the original value 100 | // Otherwise: fallback to the original value 101 | const fallback = removeFill ? "undefined" : `"${fillValue}"`; 102 | return `${startTag}${beforeFill} fill={typeof fills !== 'undefined' && typeof fills[${idx}] !== 'undefined' ? fills[${idx}] : ${fallback}}${afterFill}`; 103 | }, 104 | ); 105 | } 106 | 107 | export { 108 | cleanupStart, 109 | prepareSvgProps, 110 | injectSvgJsProps, 111 | dashToCamelCaseProps, 112 | tagToPascalCase, 113 | cleanupEndWithoutSpace, 114 | deleteFill, 115 | deleteStroke, 116 | transformStyleAttributes, 117 | allowOverrideFillWithProp, 118 | }; 119 | -------------------------------------------------------------------------------- /src/all-combinations.test.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { execSync } from "node:child_process"; 4 | import { mkdirSync, existsSync, rmSync } from "node:fs"; 5 | import path from "node:path"; 6 | import { fileURLToPath } from "node:url"; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | const optionalFlags = [ 12 | { name: "remove-fill", alias: "rf", bool: true }, 13 | { name: "remove-stroke", alias: "rs", bool: true }, 14 | { name: "allow-override-fill", alias: "aof", bool: true, value: '["#f00"]' }, 15 | ]; 16 | 17 | // Create specific core combinations as requested 18 | const coreCombinations = [ 19 | [{ name: "with-native", alias: "rn", bool: true }], 20 | 21 | [{ name: "with-web", alias: "rnw", bool: true }], 22 | 23 | [ 24 | { name: "with-native", alias: "rn", bool: true }, 25 | { name: "with-web", alias: "rnw", bool: true }, 26 | ], 27 | 28 | [{ name: "with-native-for-typescript", alias: "rnts", bool: true }], 29 | 30 | [{ name: "with-web-for-typescript", alias: "rnwts", bool: true }], 31 | 32 | [ 33 | { name: "with-native-for-typescript", alias: "rnts", bool: true }, 34 | { name: "with-web-for-typescript", alias: "rnwts", bool: true }, 35 | ], 36 | ]; 37 | 38 | // Helper function to generate combinations of other options with with-native-for-typescript 39 | function generateOtherOptionCombinations() { 40 | const baseTsOption = { 41 | name: "with-native-for-typescript", 42 | alias: "rnts", 43 | bool: true, 44 | }; 45 | const result = []; 46 | 47 | // Generate combinations of other options 48 | optionalFlags.forEach((option) => { 49 | result.push([baseTsOption, option]); 50 | }); 51 | 52 | // Also test all other options together 53 | if (optionalFlags.length > 0) { 54 | result.push([baseTsOption, ...optionalFlags]); 55 | } 56 | 57 | return result; 58 | } 59 | 60 | const allCombinations = [ 61 | ...coreCombinations, 62 | ...generateOtherOptionCombinations(), 63 | ]; 64 | 65 | // Create output directory if it doesn't exist 66 | const outputBaseDir = path.join(__dirname, "../tests/components"); 67 | if (existsSync(outputBaseDir)) { 68 | rmSync(outputBaseDir, { recursive: true, force: true }); 69 | } 70 | mkdirSync(outputBaseDir, { recursive: true }); 71 | 72 | console.log(`Testing ${allCombinations.length} combinations...`); 73 | 74 | // Run each combination 75 | for (let i = 0; i < allCombinations.length; i++) { 76 | const combination = allCombinations[i]; 77 | 78 | // Create option string for command 79 | const optionsString = combination.map((opt) => `--${opt.name}`).join(" "); 80 | 81 | // Create directory name from combination 82 | const dirName = combination 83 | .map((opt) => opt.name) 84 | .join("_") 85 | .replace(/\-/g, "-"); 86 | 87 | const outputDir = path.join(outputBaseDir, dirName); 88 | mkdirSync(outputDir, { recursive: true }); 89 | 90 | // Build and execute the command 91 | const command = `node ./dist/bin.js tests/fixtures ${outputDir} ${optionsString}`; 92 | 93 | try { 94 | console.log(`[${i + 1}/${allCombinations.length}] Running: ${command}`); 95 | execSync(command, { stdio: "inherit" }); 96 | 97 | // Run prettier on generated files to fix formatting issues (including escaped quotes) 98 | console.log(`Running prettier on ${outputDir}`); 99 | try { 100 | execSync(`npx prettier --write "${outputDir}/**/*.{js,jsx,ts,tsx}"`, { 101 | stdio: "inherit", 102 | }); 103 | } catch (prettierError: unknown) { 104 | console.error(`⚠️ Prettier failed for ${dirName}:`); 105 | console.error(prettierError); 106 | // Exit immediately if prettier fails 107 | process.exit(1); 108 | } 109 | 110 | console.log(`✅ Completed: ${dirName}`); 111 | } catch (error: unknown) { 112 | console.error(`❌ Failed: ${dirName}`); 113 | console.error(error); 114 | // Exit immediately if any combination fails 115 | process.exit(1); 116 | } 117 | } 118 | 119 | console.log("All combinations tested!"); 120 | 121 | // Check if there are Git changes in the tests/components directory 122 | try { 123 | console.log("Checking for Git changes in tests/components..."); 124 | const gitDiff = execSync(`git diff --ignore-cr-at-eol tests/components`, { 125 | encoding: "utf-8", 126 | }); 127 | 128 | if (gitDiff.trim()) { 129 | console.error( 130 | "❌ Error: Git changes detected in tests/components directory!", 131 | ); 132 | console.error("\n📋 Git diff:"); 133 | console.error(gitDiff); 134 | console.error("Please commit these changes or update the expected output."); 135 | process.exit(1); 136 | } 137 | 138 | console.log("✅ No Git changes detected in tests/components."); 139 | } catch (error: unknown) { 140 | console.error("❌ Error checking Git status:"); 141 | console.error(error); 142 | process.exit(1); 143 | } 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React from SVG 2 | 3 | 4 | Sponsoring button 5 | 6 | 7 | [![GitHub package.json version](https://img.shields.io/github/package-json/v/MoOx/react-from-svg) ![npm downloads](https://img.shields.io/npm/dm/react-from-svg)](https://www.npmjs.com/package/react-from-svg) 8 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/MoOx/react-from-svg/build.yml?branch=main)](https://github.com/MoOx/react-from-svg/actions) 9 | [![License](https://img.shields.io/github/license/MoOx/react-from-svg)](https://github.com/MoOx/react-from-svg) 10 | ![My website moox.io](https://img.shields.io/badge/%F0%9F%8C%8D%20-https%3A%2F%2Fmoox.io-gray?style=social) 11 | [![GitHub followers](https://img.shields.io/github/followers/MoOx?style=social&label=GitHub)](https://github.com/MoOx) 12 | [![LinkedIn Follow](https://img.shields.io/badge/LinkedIn-%20?style=social&logo=invision&logoColor=%230077B5)](https://www.linkedin.com/in/maxthirouin/) 13 | [![BlueSky Follow](https://img.shields.io/badge/BlueSky-%20?style=social&logo=bluesky)](https://bsky.app/profile/moox.io) 14 | [![X Follow](https://img.shields.io/twitter/follow/MoOx?style=social&label=)](https://x.com/MoOx) 15 | 16 | > Transform SVG files into React components, Native and/or Web, JavaScript and/or TypeScript. 17 | > Without minimal dependencies. 18 | 19 | ## Install 20 | 21 | ```console 22 | npm install react-from-svg 23 | ``` 24 | 25 | ## Usage 26 | 27 | ```console 28 | react-from-svg --help 29 | 30 | Usage 31 | $ react-from-svg [--with-native|--with-web] 32 | 33 | Options 34 | --with-native, -rn Output code for react-native-svg 35 | --with-native-for-typescript, -rnts Output code for react-native-svg with TypeScript 36 | --with-web, -rnw Output code for DOM. If --with-native is also used, will be output as .web.js files 37 | --with-web-for-typescript, -rnwts Output code for DOM with TypeScript. If --with-native is also used, will be output as .web.tsx files 38 | --remove-fill, -rf Remove all 'fill' properties from SVGs, convenient for icons 39 | --remove-stroke, -rs Remove all 'stroke' properties from SVGs, convenient for icons 40 | --allow-override-fill, -aof --allow-override-fill, -aof Replace all 'fill' properties by a dynamic prop (fills) in SVGs, e.g. fill={fills[N]}. 41 | 42 | Example 43 | $ react-from-svg src/svgs src/svgs/components --with-web-for-typescript --allow-override-fill 44 | ``` 45 | 46 | Generated components will allow you to inject all the props you could use on an ``/``, such as: 47 | 48 | - `width` 49 | - `height` 50 | - `fill` (if you use `--remove-fill`) 51 | - `stroke` (if you use `--remove-stroke`) 52 | - `style` 53 | 54 | ⚠️ To see what you can expect from the transformations, [check our snapshots](./tests/) 👀 55 | 56 | ## Requirements 57 | 58 | ### `--with-web(-*)` 59 | 60 | Need you to have: 61 | 62 | - [React](https://reactjs.org) 63 | 64 | Note: if you use [React Native for Web](https://github.com/necolas/react-native-web), see requirements below. 65 | 66 | ### `--with-native(-*)` 67 | 68 | Need you to have: 69 | 70 | - [React](https://reactjs.org) 71 | - [React Native](https://reactnative.dev) (or an alternative platform like 72 | [React Native Web](https://github.com/necolas/react-native-web)) 73 | - [`react-native-svg`](https://github.com/react-native-community/react-native-svg) 74 | 75 | ## Options 76 | 77 | ### `--remove-fill` 78 | 79 | Remove all `fill` properties from SVGs, convenient for icons. 80 | 81 | ### `--remove-stroke` 82 | 83 | Remove all `stroke` properties from SVGs, convenient for icons. 84 | 85 | ### `--allow-override-fill` 86 | 87 | Replace all `fill` properties by a dynamic prop (fills) in SVGs, e.g. fill={fills[N]}. 88 | If `fills[N]` is undefined, fallback to the original value (except if `--remove-fill` is used). Useful to dynamically control icon color(s). 89 | 90 | ## Examples 91 | 92 | ### Usage with `--allow-override-fill` and children 93 | 94 | When using `--allow-override-fill`, you can pass children to the component to override the fill(s). 95 | You can for example update a black SVG path to one using a gradient. 96 | 97 | Assuming you have a SVG in `src/svgs/logo.svg`, let's generate an SVG component : 98 | 99 | ```console 100 | react-from-svg src/svgs src/svgs/components --with-web-for-typescript 101 | ``` 102 | 103 | You should have an SVG component in `src/svgs/components/SVGLogo.tsx`. 104 | 105 | Now let's boost this SVG component to use a gradient. 106 | 107 | ```tsx 108 | import SVGLogo from "@/src/svgs/components/SVGLogo"; 109 | import { colors } from "@/src/tokens.stylex"; // your colors could be just a simple object 110 | 111 | const logoGradientId = "logo-gradient-id"; 112 | export default function LogoWithGradient() { 113 | return ( 114 | 115 | 116 | 117 | 118 | 119 | 120 | ); 121 | } 122 | ``` 123 | 124 | That's it. You started from a simple single color SVG path and ended up with a gradient SVG path. 125 | -------------------------------------------------------------------------------- /src/transformer.ts: -------------------------------------------------------------------------------- 1 | import { mkdirp } from "mkdirp"; 2 | import { join, dirname } from "node:path"; 3 | import { readFileSync, writeFileSync } from "node:fs"; 4 | import { glob } from "glob"; 5 | import { toPascal } from "./case.js"; 6 | import { 7 | cleanupStart, 8 | prepareSvgProps, 9 | injectSvgJsProps, 10 | dashToCamelCaseProps, 11 | tagToPascalCase, 12 | cleanupEndWithoutSpace, 13 | deleteFill, 14 | deleteStroke, 15 | transformStyleAttributes, 16 | allowOverrideFillWithProp, 17 | } from "./adjust-svg.js"; 18 | import { 19 | web, 20 | native, 21 | nativeForTypescript, 22 | webForTypescript, 23 | } from "./templates.js"; 24 | 25 | type File = { 26 | name: string; 27 | content: string; 28 | }; 29 | 30 | type Flags = { 31 | withNative?: boolean; 32 | withNativeForTypescript?: boolean; 33 | withWeb?: boolean; 34 | withWebForTypescript?: boolean; 35 | removeFill?: boolean; 36 | removeStroke?: boolean; 37 | allowOverrideFill?: boolean; 38 | }; 39 | 40 | const get = async (globPattern: string): Promise => { 41 | const files = await glob(globPattern.replace(/\\/g, '/'), { posix: true }); 42 | return files 43 | .sort() 44 | .reverse() 45 | .map((item: string) => ({ 46 | name: item, 47 | content: readFileSync(item, "utf8"), 48 | })); 49 | }; 50 | 51 | const shortenFilenames = (sourcePath: string, files: File[]): File[] => { 52 | return files.map((file) => ({ 53 | ...file, 54 | name: file.name 55 | .replace(sourcePath + "/", "") 56 | .replace(".svg", "") 57 | .split("/") 58 | .map((part) => toPascal(part)) 59 | .join("/"), 60 | })); 61 | }; 62 | 63 | export const transformSvg = ( 64 | svg: string, 65 | options: { 66 | removeFill: boolean; 67 | removeStroke: boolean; 68 | allowOverrideFill: boolean; 69 | pascalCaseTag: boolean; 70 | template: (svg: string) => string; 71 | }, 72 | ): string => { 73 | const { 74 | removeFill, 75 | removeStroke, 76 | allowOverrideFill, 77 | pascalCaseTag, 78 | template, 79 | } = options; 80 | 81 | let result = cleanupStart(svg); 82 | result = prepareSvgProps(result); 83 | result = injectSvgJsProps(result); 84 | result = dashToCamelCaseProps(result); 85 | result = transformStyleAttributes(result); 86 | result = pascalCaseTag ? tagToPascalCase(result) : result; 87 | result = cleanupEndWithoutSpace(result); 88 | if (allowOverrideFill) { 89 | result = allowOverrideFillWithProp(result, removeFill); 90 | } 91 | result = removeFill ? deleteFill(result) : result; 92 | result = removeStroke ? deleteStroke(result) : result; 93 | 94 | return template(result); 95 | }; 96 | 97 | const makeName = (name: string): string => "SVG" + name; 98 | 99 | const transformFiles = ( 100 | files: File[], 101 | options: { 102 | withNative: boolean; 103 | withNativeForTypescript: boolean; 104 | withWeb: boolean; 105 | withWebForTypescript: boolean; 106 | removeFill: boolean; 107 | removeStroke: boolean; 108 | allowOverrideFill: boolean; 109 | }, 110 | ): File[] => { 111 | const { 112 | withNative, 113 | withNativeForTypescript, 114 | withWeb, 115 | withWebForTypescript, 116 | removeFill, 117 | removeStroke, 118 | allowOverrideFill, 119 | } = options; 120 | 121 | return files.reduce((acc, file) => { 122 | const name = makeName(file.name); 123 | const trsf = (options: { 124 | js: boolean; 125 | pascalCaseTag: boolean; 126 | template: (svg: string) => string; 127 | }) => 128 | transformSvg(file.content, { 129 | removeFill, 130 | removeStroke, 131 | allowOverrideFill, 132 | ...options, 133 | }); 134 | 135 | const trsfNative = () => 136 | trsf({ 137 | js: true, 138 | pascalCaseTag: true, 139 | template: (svg) => native(svg, name, allowOverrideFill), 140 | }); 141 | 142 | const trsfNativeForTs = () => 143 | trsf({ 144 | js: true, 145 | pascalCaseTag: true, 146 | template: (svg) => nativeForTypescript(svg, name, allowOverrideFill), 147 | }); 148 | 149 | const trsfWeb = () => 150 | trsf({ 151 | js: true, 152 | pascalCaseTag: false, 153 | template: (svg) => web(svg, name, allowOverrideFill), 154 | }); 155 | 156 | const trsfWebForTs = () => 157 | trsf({ 158 | js: true, 159 | pascalCaseTag: false, 160 | template: (svg) => webForTypescript(svg, name, allowOverrideFill), 161 | }); 162 | 163 | if ( 164 | !withNative && 165 | !withNativeForTypescript && 166 | !withWeb && 167 | !withWebForTypescript 168 | ) { 169 | return acc; 170 | } 171 | 172 | const newFiles: File[] = []; 173 | 174 | if (withNative) { 175 | newFiles.push({ 176 | name: file.name + ".js", 177 | content: trsfNative(), 178 | }); 179 | } 180 | 181 | if (withNativeForTypescript) { 182 | newFiles.push({ 183 | name: file.name + ".tsx", 184 | content: trsfNativeForTs(), 185 | }); 186 | } 187 | 188 | const webExtension = withNative || withNativeForTypescript ? ".web" : ""; 189 | 190 | if (withWeb) { 191 | newFiles.push({ 192 | name: file.name + webExtension + ".js", 193 | content: trsfWeb(), 194 | }); 195 | } 196 | 197 | if (withWebForTypescript) { 198 | newFiles.push({ 199 | name: file.name + webExtension + ".tsx", 200 | content: trsfWebForTs(), 201 | }); 202 | } 203 | 204 | return [...acc, ...newFiles]; 205 | }, [] as File[]); 206 | }; 207 | 208 | const write = (outputPath: string, files: File[]): File[] => { 209 | files.forEach((file) => { 210 | const filename = join(outputPath, makeName(file.name)); 211 | mkdirp.sync(dirname(filename)); 212 | writeFileSync(filename, file.content, "utf8"); 213 | }); 214 | return files; 215 | }; 216 | 217 | export const make = async ( 218 | [sourcePath, outputPath]: [string, string], 219 | flags: Flags, 220 | ): Promise => { 221 | const files = await get(join(sourcePath, "*.svg")); 222 | console.log("Files found", files.length); 223 | 224 | const transformedFiles = transformFiles(shortenFilenames(sourcePath, files), { 225 | withNative: flags.withNative ?? false, 226 | withNativeForTypescript: flags.withNativeForTypescript ?? false, 227 | withWeb: flags.withWeb ?? false, 228 | withWebForTypescript: flags.withWebForTypescript ?? false, 229 | removeFill: flags.removeFill ?? false, 230 | removeStroke: flags.removeStroke ?? false, 231 | allowOverrideFill: flags.allowOverrideFill ?? false, 232 | }); 233 | 234 | console.log("Files transformed", transformedFiles.length); 235 | 236 | const writtenFiles = write(outputPath, transformedFiles); 237 | console.log("Files written", writtenFiles.length); 238 | 239 | return writtenFiles; 240 | }; 241 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog of `react-from-svg` 2 | 3 | ## 8.0.2 - 2025-11-19 4 | 5 | - Remove Node 22 requirement 6 | 7 | ## 8.0.1 - 2025-09-16 8 | 9 | - Fix for Windows support 10 | 11 | ## 8.0.0 - 2025-04-29 12 | 13 | - Add new `--allow-override-fill` option 14 | - Add `{props.children}` injection so you can inject stuff in your svg (eg: `` that can be used with `--allow-override-fill`) 15 | 16 | Check the README for an example. 17 | 18 | ## 7.1.2 - 2025-04-29 19 | 20 | - Fix unnecessary `.web` suffix presence for web only exports 21 | 22 | ## 7.1.1 - 2025-04-08 23 | 24 | - Fix title & desc removal if there are attributes 25 | 26 | ## 7.1.0 - 2025-04-08 27 | 28 | - Add transform for `style="..."` as object 29 | - Fix support for `data-*` and `aria-*`attributes (no transformation) 30 | 31 | ## 7.0.1 - 2025-04-04 32 | 33 | - Fixed: issue with dash to camel case transforming incorrectly negative number 34 | 35 | ## 7.0.0 - 2025-04-03 36 | 37 | Rewritten in TypeScript. 38 | ReScript support as been removed (but feel free to add it back via a PR). 39 | 40 | - Remove `--commonjs` option 41 | - Remove `--with-*-for-rescript` options 42 | - Add `--with-web-for-typescript` option for DOM with TypeScript 43 | 44 | ## 6.0.0 - 2023-01-17 45 | 46 | - Add `--with-native-for-typescript` option for `react-native-svg` with TypeScript 47 | 48 | ## 5.1.3 - 2022-08-18 49 | 50 | - Handle `gradientTransform` for ReScript 51 | - Handle float without leading 0 for ReScript 52 | 53 | ## 5.1.2 - 2021-08-18 54 | 55 | - Fix style prop generation 56 | 57 | ## 5.1.1 - 2021-08-18 58 | 59 | - Fix published files 60 | 61 | ## 5.1.0 - 2021-08-18 62 | 63 | - Add support for style prop 64 | 65 | ## 5.0.3 - 2021-07-07 66 | 67 | - Fix negative number transformation for ReScript output. 68 | 69 | ## 5.0.2 - 2021-05-05 70 | 71 | - Fix \*-rescript options, round 2 72 | - Adjust a bit rescript output 73 | 74 | ## 5.0.1 - 2021-05-05 75 | 76 | Fix \*-rescript options 77 | 78 | ## 5.0.0 - 2021-05-05 79 | 80 | ### Breaking change for all users 81 | 82 | Some alias have been replaced. Please check the README for more information. 83 | 84 | ### Breaking change for user of `--with-**-reason` options 85 | 86 | ReasonML output has been replaced by ReScript. This means: 87 | 88 | - `--with-native-for-reason` has been replaced by `--with-native-for-rescript` 89 | - `--with-web-for-reason` has been replaced by `--with-web-for-rescript` 90 | 91 | Output is now ReScript code that works with `@rescript/react`, `rescript-react-native` and `@rescript-react-native/svg`. 92 | 93 | See for more informations. 94 | 95 | ## 4.0.6 - 2020-08-08 96 | 97 | - `--with-native-for-reason`: Fixed unwanted props transformation (eg: opacity) [b69604f](https://github.com/MoOx/react-from-svg/commit/b69604f) by [@MoOx](https://github.com/MoOx) 98 | 99 | ## 4.0.5 - 2020-08-08 100 | 101 | - `--with-native-for-reason`: Fixed untransformed `offset` prop for `Stop` component [cdcbf0e](https://github.com/MoOx/react-from-svg/commit/cdcbf0e) by [@MoOx](https://github.com/MoOx) 102 | 103 | ## 4.0.4 - 2020-07-15 104 | 105 | - Add missing `Stop` component [#15](https://github.com/MoOx/react-from-svg/pull/15) by [@Naturalclar](https://github.com/Naturalclar) 106 | 107 | ## 4.0.3 - 2020-06-11 108 | 109 | - `--with-native`: Fix JS output error "Error: Text strings must be rendered within a `` [#14](https://github.com/MoOx/react-from-svg/pull/14) by [@Freddy03h](https://github.com/Freddy03h) 110 | 111 | ## 4.0.2 - 2020-05-01 112 | 113 | - `--with-native-for-reason`: Fix 4.0.1 regression where size is undefined 114 | 115 | ## 4.0.1 - 2020-04-16 116 | 117 | - `--with-native-for-reason`: Avoid bucklescript shadow warnings for `ReactNative.Style.size` by [@MoOx](https://github.com/MoOx) 118 | 119 | ## 4.0.0 - 2020-04-16 120 | 121 | In addition to some fixes, this release introduce a breaking change for the CLI. 122 | Now you must use one of the `--with-*` options options to have output for you desired platform/language: 123 | 124 | - `--with-native`: Output code using React Native & `react-native-svg` (compatible with React Native Web) 125 | - `--with-web`: Output code using React DOM. If `--with-native` is also used, will be output as `.web.js` files 126 | - `--with-native-for-reason`: Output code for Reason React Native & `@reason-react-native/svg` 127 | - `--with-web-for-reason`: Output code for Reason React DOM 128 | 129 | CLI has also been improved a little to be more gentle & can offer some `--help`. 130 | 131 | Also, now, no `postinstall` step are necessary for this package as we ship a bundled version. 132 | 133 | ### 💥 Breaking Changes 134 | 135 | - Add `--with-native`, & `--with-web` options ([070a85f](https://github.com/MoOx/react-from-svg/commit/070a85f)) by [@MoOx](https://github.com/MoOx) 136 | - Remove `--with-reason` & `--bs-module-path` ([8034065](https://github.com/MoOx/react-from-svg/commit/8034065)) by [@MoOx](https://github.com/MoOx) 137 | This change make sense as you can now directly output reason code that are directly svgs, not just bindings (see `--with*-for-reason` new options). 138 | - Add `--with-native-for-reason`, `--with-web-for-reason` ([8034065](https://github.com/MoOx/react-from-svg/commit/8034065)) by [@MoOx](https://github.com/MoOx) 139 | - File are now renamed to pascale case (eg: `some-file.svg` become `SVGSomeFile.*`) ([c62989f](https://github.com/MoOx/react-from-svg/commit/c62989f)) by [@MoOx](https://github.com/MoOx) 140 | 141 | ### 🐛 BugFixes 142 | 143 | - Fix `strokeLinejoin`, `strokeLinecap` & `strokeMiterlimit` props ([#8](https://github.com/MoOx/react-from-svg/pull/8)) by [@Freddy03h](https://github.com/Freddy03h) 144 | - Fix incorrect replacement for width/height/fill incorrectly removed ([4533c64](https://github.com/MoOx/react-from-svg/commit/4533c64)) by [@MoOx](https://github.com/MoOx) 145 | 146 | ### 🎉 New 147 | 148 | - Add `--remove-stroke` option + `stroke` component prop ([#8](https://github.com/MoOx/react-from-svg/pull/8)) by [@Freddy03h](https://github.com/Freddy03h) 149 | - Add `--commonjs` ([070a85f](https://github.com/MoOx/react-from-svg/commit/070a85f)) by [@MoOx](https://github.com/MoOx) 150 | 151 | ### 🚧 Notable Internal changes 152 | 153 | - We now serve the package as a bundle bin to avoid `bs-platform` build on postinstall + artifacts issues ([ed6262c](https://github.com/MoOx/react-from-svg/commit/ed6262c)) by [@MoOx](https://github.com/MoOx) 154 | - Codebase covered by tests (via snapshots) by [@MoOx](https://github.com/MoOx) 155 | - Upgrade to bs-platform 7.2 ([#7](https://github.com/MoOx/react-from-svg/pull/7)) by [@broerjuang](https://github.com/broerjuang) 156 | 157 | ## 3.1.0 - 2020-02-18 158 | 159 | - Fix TSpan import error ([#6](https://github.com/MoOx/react-from-svg/pull/6)) by [@broerjuang](https://github.com/broerjuang) 160 | - bump bs-platform to 7.1.0 ([#6](https://github.com/MoOx/react-from-svg/pull/6)) by [@broerjuang](https://github.com/broerjuang) 161 | 162 | ## 3.0.0 - 2020-01-23 163 | 164 | - Fixed reason generated module name to the js 165 | - `--reason-absolute-path` is now `--reason-module-path` & can support absolute and local path 166 | 167 | ## 2.1.1 - 2020-01-23 168 | 169 | - oopsy path 170 | 171 | ## 2.1.0 - 2020-01-23 172 | 173 | - Add `--reason-absolute-path` option for reason files ([#4](https://github.com/MoOx/react-from-svg/pull/4)) by [@Freddy03h](https://github.com/Freddy03h) 174 | - Fix fill reason type by [@MoOx](https://github.com/MoOx) 175 | 176 | ## 2.0.1 - 2020-01-22 177 | 178 | - Try to autorebuild if compiled artifacts are missing 179 | 180 | ## 2.0.0 - 2020-01-22 181 | 182 | - Try to load compiled transformer differently (not in-source as it's the recommended place - to avoid issue with existing bs compilation, which can override & break nodejs script due to not using commonjs). 183 | - Use bs-platform@^7.0.0 184 | 185 | We might in the future rebuild script before running it. 186 | 187 | ## 1.2.3 - 2020-01-03 188 | 189 | - Fix unwanted whitespace that create text nodes 190 | 191 | ## 1.2.2 - 2020-01-03 192 | 193 | - Fix removal of `