Skip to content

Commit

Permalink
feat: Support for react native functionnal components (#217)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Bourgeois <lucas.bourgeois@blgcloud.com>
  • Loading branch information
LucasBourgeois and Lucas Bourgeois authored Dec 22, 2023
1 parent a8f36cd commit f38a936
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 4 deletions.
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 (<Text style={{ fontFamily: 'svgtofont', fontSize: 16, color: '#000000', ...rest }}>
{icons[name]}
</Text>);
};

```

### outSVGPath

> Type: `Boolean`
Expand Down Expand Up @@ -747,6 +768,21 @@ import { ReactComponent as ComLogo } from './logo.svg';
<ComLogo />
```

### 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';

<SvgToFont fontSize={32} color="#fefefe" name={"Git"} />
```


## Contributors

As always, thanks to our amazing contributors!
Expand Down
1 change: 1 addition & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
58 changes: 58 additions & 0 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,61 @@ async function outputReactFile(files: string[], options: SvgToFontOptions = {})
}),
);
}

const reactNativeSource = (fontName: string, defaultSize: number, iconMap: Map<string,string>) => `import { Text } from 'react-native';
const icons = ${JSON.stringify(Object.fromEntries(iconMap))};
export const ${fontName} = props => {
const {name, ...rest} = props;
return (<Text style={{fontFamily: '${fontName}', fontSize: ${defaultSize}, color: '#000000', ...rest}}>
{icons[name]}
</Text>);
};
`;

const reactNativeTypeSource = (name: string, iconMap: Map<string, string>) => `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<TextStyle, 'fontFamily' | 'fontStyle' | 'fontWeight'> {
name: ${name}Names
}
export declare const ${name}: (props: ${name}Props) => JSX.Element;
`;

/**
* Generate ReactNative Icon
* <font-name>.json
*/
export function generateReactNativeIcons(options: SvgToFontOptions = {}, unicodeObject: Record<string, string>) {
const ICONS_PATH = filterSvgFiles(options.src);
outputReactNativeFile(ICONS_PATH, options, unicodeObject);
}

function outputReactNativeFile(files: string[], options: SvgToFontOptions = {}, unicodeObject: Record<string, string>) {
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<string, string>();
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));
}
14 changes: 11 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -410,4 +418,4 @@ export default async (options: SvgToFontOptions = {}) => {
/**
* https://github.com/Microsoft/TypeScript/issues/5565#issuecomment-155226290
*/
module.exports = exports["default"];
module.exports = exports["default"];
1 change: 1 addition & 0 deletions test/example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
1 change: 1 addition & 0 deletions test/templates/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down

0 comments on commit f38a936

Please sign in to comment.