├── .gitignore
├── LICENSE
├── README.md
├── bin
├── build.ts
├── template.ts
├── tsconfig.json
└── types.d.ts
├── cleanup.sh
├── compile.js
├── package.json
├── pnpm-lock.yaml
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | solid/
4 | outline/
5 | mini/
6 | micro/
7 | src/
8 | build/
9 | heroicons/
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 impulse
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/react-native-heroicons)
2 | [](https://www.npmjs.com/package/react-native-heroicons)
3 |
4 | # React Native Heroicons
5 |
6 | Heroicons are designed by [Steve Schoger](https://twitter.com/steveschoger) and published by [Tailwind Labs](https://github.com/tailwindlabs/heroicons).
7 |
8 | A full directory of all available icons can be found here:
9 |
10 | https://heroicons.com/
11 |
12 | ## Installation
13 |
14 | **react-native-heroicons requires react-native-svg v9 or higher**
15 |
16 | ### yarn
17 |
18 | ```sh
19 | yarn add react-native-heroicons react-native-svg
20 | ```
21 |
22 | ### npm
23 |
24 | ```sh
25 | npm i react-native-heroicons react-native-svg
26 | ```
27 |
28 | ## Usage
29 |
30 | Specific icons:
31 |
32 | ```tsx
33 | import React from "react";
34 | import { View } from "react-native";
35 | import { SparklesIcon as SparklesIconMicro } from "react-native-heroicons/micro";
36 | // Old solid style from heroicons v1
37 | import { SparklesIcon as SparklesIconMini } from "react-native-heroicons/mini";
38 | import { SparklesIcon } from "react-native-heroicons/solid";
39 | import { SparklesIcon as SparklesIconOutline } from "react-native-heroicons/outline";
40 |
41 | const App = () => {
42 | return (
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | };
51 |
52 | export default App;
53 | ```
54 |
55 | Entire icon pack:
56 |
57 | ```tsx
58 | import React from "react";
59 | import * as Icons from "react-native-heroicons/solid";
60 |
61 | const App = () => {
62 | return ;
63 | };
64 |
65 | export default App;
66 | ```
67 |
68 | ## Customization
69 |
70 | Icons can be adjusted with the `size` prop.
71 |
72 | Defaults are `16` for `micro`, `20` for `mini` and `24` for `solid`/`outline`):
73 |
74 | ```tsx
75 | import { SparklesIcon as SparklesIconOutline } from "react-native-heroicons/outline";
76 | // ...
77 | ;
78 | ```
79 |
--------------------------------------------------------------------------------
/bin/build.ts:
--------------------------------------------------------------------------------
1 | import { transform } from "@svgr/core";
2 | import { promises as fs } from "fs";
3 | import { Template, template16, template20, template24 } from "./template";
4 | import junk from "junk";
5 | import camelcase from "camelcase";
6 |
7 | const ICON_STYLES = ["micro", "mini", "solid", "outline"] as const;
8 | type IconStyle = (typeof ICON_STYLES)[number];
9 |
10 | const resetSrcDir = async () => {
11 | try {
12 | await fs.rm(`./src`, { recursive: true });
13 | } catch (error) {
14 | // Allowed to fail
15 | }
16 | try {
17 | await fs.mkdir(`./src`);
18 | ICON_STYLES.forEach(async (style) => {
19 | await fs.mkdir(`./src/${style}`);
20 | });
21 | } catch (error) {
22 | throw new Error("Failed wiping src folders");
23 | }
24 | };
25 |
26 | const genComponentFromBuffer = async (
27 | componentName: string,
28 | svgBuffer: Buffer,
29 | templateIconSize: 16 | 20 | 24
30 | ): Promise => {
31 | const template = {
32 | 16: template16,
33 | 20: template20,
34 | 24: template24,
35 | }[templateIconSize];
36 |
37 | try {
38 | return await transform(
39 | svgBuffer,
40 | {
41 | template,
42 | native: true,
43 | typescript: true,
44 | svgProps: { width: "{size}", height: "{size}" },
45 | svgo: true,
46 | svgoConfig: {
47 | plugins: [
48 | "removeXMLNS",
49 | {
50 | name: "sortAttrs",
51 | params: {
52 | xmlnOrder: "alphabetical",
53 | },
54 | },
55 | {
56 | name: "removeAttrs",
57 | params: {
58 | attrs: ["aria-hidden"],
59 | },
60 | },
61 | ],
62 | },
63 | plugins: [
64 | "@svgr/plugin-svgo",
65 | "@svgr/plugin-jsx",
66 | "@svgr/plugin-prettier",
67 | ],
68 | },
69 | { componentName }
70 | );
71 | } catch (error) {
72 | throw new Error("Failed generating components");
73 | }
74 | };
75 |
76 | const getIcons = async (style: IconStyle) => {
77 | const iconDir = "./heroicons/optimized";
78 |
79 | const stylePath = {
80 | micro: "16/solid",
81 | mini: "20/solid",
82 | outline: "24/outline",
83 | solid: "24/solid",
84 | }[style];
85 |
86 | let files = await fs.readdir(`${iconDir}/${stylePath}`);
87 | return Promise.all(
88 | files.filter(junk.not).map(async (file) => ({
89 | svg: await fs.readFile(`${iconDir}/${stylePath}/${file}`),
90 | componentName: `${camelcase(file.replace(/\.svg$/, ""), {
91 | pascalCase: true,
92 | })}Icon`,
93 | }))
94 | );
95 | };
96 |
97 | const exportIcons = async (style: IconStyle) => {
98 | const sizeMap: Record = {
99 | micro: 16,
100 | mini: 20,
101 | outline: 24,
102 | solid: 24,
103 | };
104 |
105 | const icons = await getIcons(style);
106 | for (let { componentName, svg } of icons) {
107 | const jsx = await genComponentFromBuffer(
108 | componentName,
109 | svg,
110 | sizeMap[style]
111 | );
112 | await fs.writeFile(`./src/${style}/${componentName}.tsx`, jsx);
113 | const exportStr = `export { default as ${componentName} } from './${componentName}';\n`;
114 | await fs.writeFile(`./src/${style}/index.ts`, exportStr, { flag: "a" });
115 | }
116 | };
117 |
118 | (async () => {
119 | await resetSrcDir();
120 | ICON_STYLES.forEach(async (s) => {
121 | await exportIcons(s);
122 | });
123 | })();
124 |
--------------------------------------------------------------------------------
/bin/template.ts:
--------------------------------------------------------------------------------
1 | import type { Options as TransformOptions } from "@svgr/babel-preset";
2 | export type Template = TransformOptions["template"];
3 |
4 | const template16: Template = (variables, { tpl }) => {
5 | return tpl`
6 | import * as React from "react";
7 | import Svg, { Path, SvgProps, NumberProp } from "react-native-svg";
8 |
9 | interface Props extends SvgProps {
10 | size?: NumberProp;
11 | }
12 |
13 | const ${variables.componentName} = ({ size = 16, ...props }: Props) => {
14 | return (
15 | ${variables.jsx}
16 | )
17 | };
18 |
19 | ${variables.exports};
20 | `;
21 | };
22 |
23 | const template20: Template = (variables, { tpl }) => {
24 | return tpl`
25 | import * as React from "react";
26 | import Svg, { Path, SvgProps, NumberProp } from "react-native-svg";
27 |
28 | interface Props extends SvgProps {
29 | size?: NumberProp;
30 | }
31 |
32 | const ${variables.componentName} = ({ size = 20, ...props }: Props) => {
33 | return (
34 | ${variables.jsx}
35 | )
36 | };
37 |
38 | ${variables.exports};
39 | `;
40 | };
41 |
42 | const template24: Template = (variables, { tpl }) => {
43 | return tpl`
44 | import * as React from "react";
45 | import Svg, { Path, SvgProps, NumberProp } from "react-native-svg";
46 |
47 | interface Props extends SvgProps {
48 | size?: NumberProp;
49 | }
50 |
51 | const ${variables.componentName} = ({ size = 24, ...props }: Props) => {
52 | return (
53 | ${variables.jsx}
54 | )
55 | };
56 |
57 | ${variables.exports};
58 | `;
59 | };
60 |
61 | export { template16, template20, template24 };
62 |
--------------------------------------------------------------------------------
/bin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Basic Options */
4 | // "incremental": true, /* Enable incremental compilation */
5 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
6 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
7 | // "lib": [], /* Specify library files to be included in the compilation. */
8 | // "allowJs": true, /* Allow javascript files to be compiled. */
9 | // "checkJs": true, /* Report errors in .js files. */
10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
13 | // "sourceMap": true, /* Generates corresponding '.map' file. */
14 | // "outFile": "./", /* Concatenate and emit output to single file. */
15 | // "outDir": "./", /* Redirect output structure to the directory. */
16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
17 | // "composite": true, /* Enable project compilation */
18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
19 | // "removeComments": true, /* Do not emit comments to output. */
20 | // "noEmit": true, /* Do not emit outputs. */
21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
24 |
25 | /* Strict Type-Checking Options */
26 | "strict": true /* Enable all strict type-checking options. */,
27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
28 | // "strictNullChecks": true, /* Enable strict null checks. */
29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
34 |
35 | /* Additional Checks */
36 | // "noUnusedLocals": true, /* Report errors on unused locals. */
37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
40 |
41 | /* Module Resolution Options */
42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
46 | // "typeRoots": [], /* List of folders to include type definitions from. */
47 | // "types": [], /* Type declaration files to be included in compilation. */
48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
49 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
52 |
53 | /* Source Map Options */
54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
58 |
59 | /* Experimental Options */
60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
62 |
63 | /* Advanced Options */
64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/bin/types.d.ts:
--------------------------------------------------------------------------------
1 | declare module "@svgr/core";
2 |
--------------------------------------------------------------------------------
/cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | npm pack --dry-run
--------------------------------------------------------------------------------
/compile.js:
--------------------------------------------------------------------------------
1 | const { build } = require("esbuild");
2 | const glob = require("tiny-glob");
3 | const fs = require("fs/promises");
4 |
5 | (async () => {
6 | const entryPoints = ["solid", "outline", "mini", "micro"];
7 |
8 | entryPoints.forEach(async (ep) => {
9 | const entryPoints = await glob(`./src/${ep}/*.{ts,tsx}`);
10 |
11 | await build({
12 | entryPoints,
13 | format: "cjs",
14 | minify: true,
15 | outdir: `./${ep}`,
16 | });
17 |
18 | await build({
19 | entryPoints,
20 | format: "esm",
21 | minify: true,
22 | outdir: `./${ep}/esm`,
23 | });
24 |
25 | await fs.writeFile(`./${ep}/package.json`, `{"module": "./esm/index.js"}`);
26 | });
27 | })();
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-heroicons",
3 | "version": "4.0.0",
4 | "description": "React Native components for heroicons",
5 | "files": [
6 | "solid",
7 | "outline",
8 | "mini",
9 | "micro"
10 | ],
11 | "sideEffects": false,
12 | "scripts": {
13 | "fetch": "rimraf heroicons/ && git clone https://github.com/tailwindlabs/heroicons/",
14 | "gen": "npm run fetch && ts-node --project bin/tsconfig.json --files bin/build.ts",
15 | "gen:no": "ts-node --project bin/tsconfig.json --files bin/build.ts",
16 | "cleanup": "./cleanup.sh",
17 | "compile": "rimraf solid && rimraf outline && rimraf mini && rimraf micro && node compile.js && tsc --emitDeclarationOnly --outDir . && cp solid/*.d.ts solid/esm && cp outline/*.d.ts outline/esm && cp mini/*.d.ts mini/esm && cp micro/*.d.ts micro/esm",
18 | "build:fetch": "npm run gen && npm run compile && npm run cleanup",
19 | "build": "npm run compile && npm run cleanup",
20 | "release": "npm run build:fetch && release-it"
21 | },
22 | "keywords": [
23 | "react",
24 | "react native",
25 | "heroicons",
26 | "heroiconsui"
27 | ],
28 | "repository": {
29 | "type": "git",
30 | "url": "git+https://github.com/ecklf/react-native-heroicons"
31 | },
32 | "bugs": {
33 | "url": "https://github.com/ecklf/react-native-heroicons/issues"
34 | },
35 | "author": "ecklf",
36 | "license": "MIT",
37 | "devDependencies": {
38 | "@svgr/babel-preset": "^8.1.0",
39 | "@svgr/core": "^6.5.1",
40 | "@svgr/plugin-jsx": "^6.5.1",
41 | "@svgr/plugin-prettier": "^6.5.1",
42 | "@svgr/plugin-svgo": "^6.5.1",
43 | "@types/node": "^18.19.3",
44 | "@types/react": "^18.2.45",
45 | "@types/react-native": "^0.70.19",
46 | "camelcase": "^6.3.0",
47 | "esbuild": "^0.13.15",
48 | "junk": "^3.1.0",
49 | "react": "^18.2.0",
50 | "react-native-svg": "^13.14.0",
51 | "release-it": "^15.6.0",
52 | "rimraf": "^3.0.2",
53 | "tiny-glob": "^0.2.9",
54 | "ts-node": "^10.9.1",
55 | "typescript": "^4.9.4"
56 | },
57 | "peerDependencies": {
58 | "react": ">=16.8",
59 | "react-native-svg": ">=9"
60 | },
61 | "release-it": {
62 | "git": {
63 | "commitMessage": "chore: release v${version}",
64 | "tagName": "v${version}",
65 | "requireCleanWorkingDir": false
66 | },
67 | "github": {
68 | "release": true
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
4 | "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
5 | "jsx": "react-native" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
6 | "outDir": "dist" /* Redirect output structure to the directory. */,
7 | "declaration": true /* Generates corresponding '.d.ts' file. */,
8 | "sourceMap": false /* Generates corresponding '.map' file. */,
9 | "strict": true /* Enable all strict type-checking options. */,
10 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
11 | "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
12 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
13 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
14 | "isolatedModules": true,
15 | "skipLibCheck": true
16 | },
17 | "include": ["src/**/*"]
18 | }
19 |
--------------------------------------------------------------------------------