From f38a9365d99094aaeace346c3046e1459158d060 Mon Sep 17 00:00:00 2001 From: LucasBourgeois Date: Fri, 22 Dec 2023 01:09:05 +0100 Subject: [PATCH] feat: Support for react native functionnal components (#217) Co-authored-by: Lucas Bourgeois --- README.md | 38 ++++++++++++++++++++++++++- src/cli.ts | 1 + src/generate.ts | 58 +++++++++++++++++++++++++++++++++++++++++ src/index.ts | 14 +++++++--- test/example/index.js | 1 + test/templates/index.js | 1 + 6 files changed, 109 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cd4f7a5f..2fbaf68e 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Read a set of SVG icons and ouput a TTF/EOT/WOFF/WOFF2/SVG font, Generator of fo - Supported font formats: `WOFF2`, `WOFF`, `EOT`, `TTF` and `SVG`. - Support SVG Symbol file. -- Support [`React`](https://github.com/facebook/react) & [`TypeScript`](https://github.com/microsoft/TypeScript). +- Support [`React`](https://github.com/facebook/react), [`ReactNative`](https://github.com/facebook/react-native) & [`TypeScript`](https://github.com/microsoft/TypeScript). - Support [`Less`](https://github.com/less/less.js)/[`Sass`](https://github.com/sass/sass)/[`Stylus`](https://github.com/stylus/stylus). - Allows to use custom templates (example `css`, `less` and etc). - Automatically generate a preview site. @@ -263,6 +263,27 @@ export const Git = props => ( ); ``` +### outSVGReactNative + +> Type: `Boolean` +> Default value: `false` + +Output `./dist/reactNative/`, SVG generates `reactNative` components. + +```js +import { Text } from 'react-native'; + +const icons = { "Git": "__GitUnicodeChar__", "Adobe": "__AdobeUnicodeChar__" }; + +export const RangeIconFont = props => { + const { name, ...rest } = props; + return ( + {icons[name]} + ); +}; + +``` + ### outSVGPath > Type: `Boolean` @@ -747,6 +768,21 @@ import { ReactComponent as ComLogo } from './logo.svg'; ``` +### Using With ReactNative + +A unique component named after the font name is generated. + +Props are TextProps and are used as inline style. + +In addition, the name prop is mandatory and refers to svg names + +```jsx +import { SvgToFont } from './SvgToFont'; + + +``` + + ## Contributors As always, thanks to our amazing contributors! diff --git a/src/cli.ts b/src/cli.ts index 3acc209b..f17ea895 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -44,6 +44,7 @@ svgtofont({ fontName: (argv.fontName) || "svgfont", // font name css: true, // Create CSS files. outSVGReact: true, + outSVGReactNative: false, outSVGPath: true, svgicons2svgfont: { fontHeight: 1000, diff --git a/src/generate.ts b/src/generate.ts index a49c5b1a..f8521f9a 100644 --- a/src/generate.ts +++ b/src/generate.ts @@ -99,3 +99,61 @@ async function outputReactFile(files: string[], options: SvgToFontOptions = {}) }), ); } + +const reactNativeSource = (fontName: string, defaultSize: number, iconMap: Map) => `import { Text } from 'react-native'; + +const icons = ${JSON.stringify(Object.fromEntries(iconMap))}; + +export const ${fontName} = props => { + const {name, ...rest} = props; + return ( + {icons[name]} + ); +}; +`; + +const reactNativeTypeSource = (name: string, iconMap: Map) => `import { TextStyle } from 'react-native'; + +export type ${name}Names = ${[...iconMap.keys()].reduce((acc, key, index) => { + if (index === 0) { + acc = `'${key}'` + } else { + acc += `| '${key}'` + } + return acc; +}, `${'string'}`)} + +export interface ${name}Props extends Omit { + name: ${name}Names +} + +export declare const ${name}: (props: ${name}Props) => JSX.Element; +`; + +/** + * Generate ReactNative Icon + * .json + */ +export function generateReactNativeIcons(options: SvgToFontOptions = {}, unicodeObject: Record) { + const ICONS_PATH = filterSvgFiles(options.src); + outputReactNativeFile(ICONS_PATH, options, unicodeObject); +} + +function outputReactNativeFile(files: string[], options: SvgToFontOptions = {}, unicodeObject: Record) { + const fontSizeOpt = typeof options.css !== 'boolean' && options.css.fontSize; + const fontSize = typeof fontSizeOpt === 'boolean' ? 16 : parseInt(fontSizeOpt); + const fontName = options.classNamePrefix || options.fontName + const iconMap = new Map(); + files.map(filepath => { + const baseFileName = path.basename(filepath, '.svg'); + let name = toPascalCase(baseFileName); + if (/^[rR]eactNative$/.test(name)) { + name = name + toPascalCase(fontName); + } + iconMap.set(name, unicodeObject[baseFileName]) + }); + const outDistPath = path.join(options.dist, 'reactNative', `${fontName}.js`); + const comName = isNaN(Number(fontName.charAt(0))) ? fontName : toPascalCase(fontName) + name; + fs.outputFileSync(outDistPath, reactNativeSource(comName, fontSize, iconMap)); + fs.outputFileSync(outDistPath.replace(/\.js$/, '.d.ts'), reactNativeTypeSource(comName, iconMap)); +} diff --git a/src/index.ts b/src/index.ts index c51f7684..b0883a48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,7 @@ import color from 'colors-cli'; import { autoConf, merge, AutoConfOption } from 'auto-config-loader'; import { Config } from 'svgo'; import { log } from './log'; -import { generateIconsSource, generateReactIcons } from './generate'; +import { generateIconsSource, generateReactIcons, generateReactNativeIcons } from './generate'; import { createSVG, createTTF, createEOT, createWOFF, createWOFF2, createSvgSymbol, copyTemplate, CSSOptions, createHTML, createTypescript, TypescriptOptions } from './utils'; export type SvgToFontOptions = { @@ -49,6 +49,10 @@ export type SvgToFontOptions = { * Output `./dist/react/`, SVG generates `react` components. */ outSVGReact?: boolean; + /** + * Output `./dist/reactNative/`, SVG generates `reactNative` component. + */ + outSVGReactNative?: boolean; /** * Output `./dist/svgtofont.json`, The content is as follows: * @example @@ -109,7 +113,7 @@ export type SvgToFontOptions = { */ useNameAsUnicode?: boolean; /** - * consoles whenever {{ cssString }} template outputs unicode characters or css vars + * consoles whenever {{ cssString }} template outputs unicode characters or css vars * @default false */ useCSSVars?: boolean; @@ -401,6 +405,10 @@ export default async (options: SvgToFontOptions = {}) => { const outPath = await generateReactIcons(options); log.log(`${color.green('SUCCESS')} Created React Components. `); } + if (options.outSVGReactNative) { + generateReactNativeIcons(options, unicodeObject); + log.log(`${color.green('SUCCESS')} Created React Native Components. `); + } } catch (error) { log.log('SvgToFont:CLI:ERR:', error); @@ -410,4 +418,4 @@ export default async (options: SvgToFontOptions = {}) => { /** * https://github.com/Microsoft/TypeScript/issues/5565#issuecomment-155226290 */ -module.exports = exports["default"]; \ No newline at end of file +module.exports = exports["default"]; diff --git a/test/example/index.js b/test/example/index.js index 05d08131..a7f9d41a 100644 --- a/test/example/index.js +++ b/test/example/index.js @@ -12,6 +12,7 @@ svgtofont({ fontName: "svgtofont", // font name css: true, // Create CSS files. outSVGReact: true, + outSVGReactNative: true, outSVGPath: true, startNumber: 20000, // unicode start number svgicons2svgfont: { diff --git a/test/templates/index.js b/test/templates/index.js index c69a60c5..da29a79d 100644 --- a/test/templates/index.js +++ b/test/templates/index.js @@ -17,6 +17,7 @@ const options = { fontName: "svgtofont", // font name css: true, // Create CSS files. outSVGReact: true, + outSVGReactNative: true, outSVGPath: true, startNumber: 20000, // unicode start number svgicons2svgfont: {