├── .eslintrc ├── .gitignore ├── .npmignore ├── .prettierrc ├── DEVELOPMENT.md ├── LICENSE ├── Makefile ├── README.md ├── __tests__ ├── __snapshots__ │ ├── oldApiSnapshot.test.tsx.snap │ └── snapshot.test.tsx.snap ├── oldApiSnapshot.test.tsx └── snapshot.test.tsx ├── babel.config.js ├── example ├── .gitignore ├── App.tsx ├── app.json ├── assets │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── package-lock.json ├── package.json └── tsconfig.json ├── jest.config.js ├── package-lock.json ├── package.json ├── preview.png ├── publish.sh ├── src ├── index.tsx └── v3api.tsx └── tsconfig.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "plugins": ["prettier", "@typescript-eslint", "react", "react-native", "eslint-plugin-tsdoc"], 4 | "env": { 5 | "browser": true, 6 | }, 7 | "extends": [ 8 | "airbnb", 9 | "airbnb/hooks", 10 | "prettier", 11 | "plugin:@typescript-eslint/recommended", 12 | "plugin:@typescript-eslint/recommended", 13 | ], 14 | "rules": { 15 | "no-underscore-dangle": "off", 16 | "import/extensions": "off", 17 | "import/no-unresolved": ["off"], 18 | "prettier/prettier": "error", 19 | "react/jsx-filename-extension": "off", 20 | "react/require-default-props": "off", 21 | "eqeqeq": "off", 22 | "no-use-before-define": "off", 23 | "react/function-component-definition": [ 24 | 2, 25 | { "namedComponents": "arrow-function", "unnamedComponents": "arrow-function" }, 26 | ], 27 | // We're using the new JSX transform. 28 | "react/jsx-uses-react": "off", 29 | "react/react-in-jsx-scope": "off", 30 | "tsdoc/syntax": "warn", 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | dist/ 4 | coverage/ 5 | TODO 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | build 3 | publish.sh 4 | example 5 | TODO 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "es5", 4 | "semi": false, 5 | "singleQuote": true, 6 | "jsxSingleQuote": true 7 | } 8 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Document for Developers of this package 2 | 3 | In the published package, we want to have the content of `./dist` directory as the root of the package. Because it would be difficult if not imposible to make all systems resolve `./dist` correctly. 4 | 5 | To do so, our `make build` script copies the `package.json` to the `./dist` directory. In the main `package.json` file, we have `private=true` so we won't publish it by mistake. 6 | 7 | Then, in the `publish.sh` script, we also copy `README.md` and other files to the `./dist` directory before publishing. 8 | 9 | ## Run the example using local changes 10 | 11 | Unfortunately, Metro bundler cannot import from symlinks, so `npm link` won't work. 12 | 13 | Maybe we can follow this? https://medium.com/@alielmajdaoui/linking-local-packages-in-react-native-the-right-way-2ac6587dcfa2 14 | 15 | For now, the simplest solution is to just copy files from `./dist` to `example/node_modules/react-native-pie-chart`! 16 | 17 | Another way: 18 | 19 | ``` 20 | make build 21 | cd dist 22 | npm pack 23 | ``` 24 | 25 | Then in the example folder: 26 | 27 | ``` 28 | npm install ../dist/react-native-pie-chart-4.0.0.tgz 29 | ``` 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2017-2020 Gene Xu 4 | Copyright © 2021 Aidin Gharibnavaz 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | tsc: 2 | npm run tsc 3 | 4 | tsc-watch: 5 | npm run tsc:watch 6 | 7 | pretty: ## Runs Prettier on all files 8 | npm run pretty 9 | 10 | lint: ## Runs ESLint on all files 11 | npm run lint 12 | 13 | test: ## Run Jest tests 14 | npm run test 15 | 16 | check: pretty lint tsc test 17 | check: ## Runs all the checks and tests we have 18 | 19 | clean: ## Cleans ./dist 20 | rm -rf dist/* 21 | 22 | build: clean tsc 23 | build: ## Compile Typescript to Javascript 24 | npm run compile 25 | grep -v '\"private\":' package.json > ./dist/package.json 26 | 27 | publish: ## Build, tag, and publish to npmjs 28 | ./publish.sh 29 | 30 | .DEFAULT_GOAL := help 31 | 32 | help: ## Prints this help. 33 | @grep -h -E '^[a-zA-Z1-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-pie-chart 2 | 3 | [![npm version](https://img.shields.io/npm/v/react-native-pie-chart)](https://www.npmjs.com/package/react-native-pie-chart) 4 | [![npm downloads](https://img.shields.io/npm/dt/react-native-pie-chart?logo=npm)](https://www.npmjs.com/package/react-native-pie-chart) 5 | [![license](https://img.shields.io/npm/l/react-native-pie-chart)](https://github.com/aidin36/react-native-pie-chart/blob/master/LICENSE) 6 | 7 | Simple pie chart module for your React Native app, for both iOS and Android. 8 | 9 | 10 | 11 | ## Installation 12 | 13 | You need to have `react`, `react-native` and `react-native-svg` as your app's dependencies. 14 | 15 | `react-native-svg` can be installed both in `expo` and in an ejected app. If you had trouble installing `react-native-svg`, refer to the project's documentation: https://www.npmjs.com/package/react-native-svg 16 | 17 | Then install this package with: 18 | 19 | `~$ npm install react-native-pie-chart --save` 20 | 21 | If you're upgradeing from an old version, see the upgrade guide below. 22 | 23 | ## Usage 24 | 25 | Here's a quick start code. Refer to the `example` directory for a fully working app. 26 | 27 | ```javascript 28 | import React, { Component } from 'react' 29 | import { StyleSheet, ScrollView, Text, View } from 'react-native' 30 | import PieChart from 'react-native-pie-chart' 31 | 32 | export default class TestChart extends Component { 33 | render() { 34 | const widthAndHeight = 250 35 | 36 | const series = [ 37 | { value: 430, color: '#fbd203' }, 38 | { value: 321, color: '#ffb300' }, 39 | { value: 185, color: '#ff9100' }, 40 | { value: 123, color: '#ff6c00' }, 41 | ] 42 | 43 | return ( 44 | 45 | 46 | Basic 47 | 48 | 49 | Doughnut 50 | 51 | 52 | 53 | ) 54 | } 55 | } 56 | 57 | const styles = StyleSheet.create({ 58 | container: { 59 | flex: 1, 60 | alignItems: 'center', 61 | }, 62 | title: { 63 | fontSize: 24, 64 | margin: 10, 65 | }, 66 | }) 67 | ``` 68 | 69 | ### Adding labels to the chart 70 | 71 | For each element in the `series` list, you can also pass a `label` object. It allows you to adjust the font and position of each label. By default, the labels will appear at the center of each slice of the pie. You can use `offsetX` and `offsetY` to move the label. 72 | 73 | For example, in the above example code, you can add the labels like this: 74 | 75 | ```javascript 76 | const series = [ 77 | { value: 430, color: '#fbd203', label: { text: 'A', fontWeight: 'bold' } }, 78 | { value: 321, color: '#ffb300', label: { text: 'mobile', offsetY: 10, offsetX: 10 } }, 79 | { value: 185, color: '#ff9100', label: { text: '%22', fontSize: 8, fontStyle: 'italic', outline: 'white' } }, 80 | { value: 123, color: '#ff6c00' }, 81 | ] 82 | ``` 83 | 84 | ## Example App 85 | 86 | Have a look at the app in the `example` directory for a complete Typescript app that shows a few charts. 87 | To setup and run the example app follow these instructions: 88 | 89 | ```bash 90 | # Clone package 91 | ~$ git clone https://github.com/genexu/react-native-pie-chart.git 92 | 93 | # Install dependencies 94 | ~$ cd react-native-pie-chart/example 95 | ~$ npm install 96 | 97 | # Run simulator 98 | # Notice: please make sure your simulator state is normal 99 | ~$ npm run start 100 | 101 | # Then like usual, press 'a' for Android, 'i' for iOS, etc. 102 | ``` 103 | 104 | ## TypeScript 105 | 106 | The npm package includes TypeScript types. 107 | 108 | ## Upgrade guide 109 | 110 | ### Upgrade from 3.x.x to 4.x.x 111 | 112 | If you don't want to change your code, we still provide the old API. You only need to change your imports from `react-native-pie-chart` to `react-native-pie-chart/v3api`. Nothing else needs to be changed! 113 | 114 | But if you want to use the new features, you need to use the new API. Here's how to upgrade your code. 115 | 116 | `series` prop is now a list of an object, that includes the `value` and `color` of each pie's slice. You need to change this: 117 | 118 | ```javascript 119 | const series = [100, 120, 80] 120 | const sliceColors = ['red', 'blue', 'pink'] 121 | ``` 122 | 123 | to this: 124 | 125 | ```javascript 126 | const series = [ 127 | { value: 100, color: 'red' }, 128 | { value: 120, color: 'blue' }, 129 | { value: 80, color: 'pink' }, 130 | ] 131 | ``` 132 | 133 | `coverRadius` and `coverFill` props are also combined into a `cover` object. `cover` can be a `number` or an object containing `radius` and `color`. So, this: 134 | 135 | ``` 136 | 137 | ``` 138 | 139 | will change to this: 140 | 141 | ``` 142 | 143 | ``` 144 | 145 | And this: 146 | 147 | ``` 148 | 149 | ``` 150 | 151 | will change to this: 152 | 153 | ``` 154 | 155 | ``` 156 | 157 | ### Upgrade version 2.x.x to 3.x.x 158 | 159 | The package migrated from deprecated `@react-native-community/art` to `react-native-svg`. You need to install `react-native-svg` as per installation guide above. You can now remove `@react-native-community/art` if you didn't use it in your own code. 160 | 161 | `doughnut` property is removed. If you set the `coverFill` prop, the chart will become a doughnut. 162 | 163 | ### Upgrade version 1.x.x to 2.x.x 164 | 165 | The only breaking change between version one and two is `chart_wh` prop. It is renamed to `widthAndHeight`. Beside that, there shouldn't be any issue upgrading. 166 | 167 | ## Props 168 | 169 | ```Typescript 170 | export type SliceLabel = { 171 | /** 172 | * Text of the label 173 | */ 174 | text: string 175 | /** 176 | * Color to fill the font with 177 | */ 178 | fill?: string 179 | /** 180 | * Color of the font's outline 181 | */ 182 | stroke?: string 183 | /** 184 | * string or number 185 | */ 186 | fontSize?: NumberProp 187 | /** 188 | * Can be: 189 | *'normal', 'bold', 'bolder', 'lighter', '100', '200',... until '900' 190 | */ 191 | fontWeight?: FontWeight 192 | /** 193 | * Name of the font 194 | */ 195 | fontFamily?: string 196 | /** 197 | * Can be: 198 | * 'normal', 'italic', 'oblique' 199 | */ 200 | fontStyle?: FontStyle 201 | /** 202 | * By default, the label will be placed at the center of the slice. 203 | * You can change it by setting these offsets. These are offset from 204 | * the center. These can be negative. 205 | */ 206 | offsetX?: number 207 | offsetY?: number 208 | } 209 | 210 | /** 211 | * Represents one slice of the pie 212 | */ 213 | export type Slice = { 214 | /** 215 | * Value the slice represents. 216 | * Should be a positive number. 217 | */ 218 | value: number 219 | /** 220 | * Color of the slice. Can be any string that HTML & CSS accepts. 221 | */ 222 | color: string 223 | /** 224 | * Optional label that appears on top of the slice. 225 | */ 226 | label?: SliceLabel 227 | } 228 | 229 | /** 230 | * Represents the hole inside the doughnut chart 231 | */ 232 | export type Cover = { 233 | /** 234 | * Radius of the doughnut hole, in precentage. 235 | * For example 0.3 to cover 30% of the center of the chart. 236 | */ 237 | radius: number 238 | /** 239 | * Optional. Color of the doughnut hole. 240 | * If you want the hole to be transparent, don't provide this 241 | * field. 242 | */ 243 | color?: string 244 | } 245 | 246 | export type Props = { 247 | /** 248 | * Diameter of the chart. In otherwords, size of the square that wraps the chart's circle. 249 | */ 250 | widthAndHeight: number 251 | /** 252 | * Chart's data. 253 | * The sum of the series values cannot be zero. 254 | */ 255 | series: Slice[] 256 | /** 257 | * Optional. 258 | * If a `number`, it's the radius of the doughnut's hole, in percentage. 259 | * (The hole will be transparent). 260 | * Should be between zero and one. 261 | * It can be an object that also defined the color of the hole. 262 | */ 263 | cover?: number | Cover 264 | /** 265 | * Optional. 266 | * React-native's style object. This will apply to the chart's SVG. 267 | */ 268 | style?: StyleProp 269 | /** 270 | * If provided, it creates a gap between the slices. Use very small numbers, like `0.01`. 271 | */ 272 | padAngle?: number 273 | } 274 | ``` 275 | 276 | ### v3 API 277 | 278 | For backward compatibility, we still provide the older API from v3. If you import the component like this: 279 | 280 | ```javascript 281 | import PieChart from 'react-native-pie-chart/v3api' 282 | ``` 283 | 284 | It will have the following props. 285 | 286 | ```Typescript 287 | 288 | export type Props = { 289 | /** 290 | * Diameter of the chart. In otherwords, size of the square that wraps the chart's circle. 291 | */ 292 | widthAndHeight: number 293 | /** 294 | * Chart's data. Should be a list of all positive (or zero) numbers. 295 | * The sum of the series cannot be zero. 296 | */ 297 | series: number[] 298 | /** 299 | * Color of each slice. The first element is the color of the first slice, 300 | * the second one is the color of the second slice, and so on. 301 | * The size of the `sliceColor` array should be equal to the size of the `series` array. 302 | */ 303 | sliceColor: string[] 304 | /** 305 | * Color of the doughnut's hole. 306 | * Don't provide it or set it to null to make it transparent. 307 | */ 308 | coverFill?: string | null 309 | /** 310 | * Size of the doughnut's hole, in percentage. 311 | * Should be between zero and one. 312 | */ 313 | coverRadius?: number 314 | /** 315 | * React-native's style object. This will apply to the chart's SVG. 316 | */ 317 | style?: StyleProp 318 | } 319 | ``` 320 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/oldApiSnapshot.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`doughnut 1`] = ` 4 | 25 | 33 | 51 | 65 | 79 | 93 | 94 | 95 | 96 | `; 97 | 98 | exports[`doughnut with fill 1`] = ` 99 | 120 | 128 | 146 | 160 | 174 | 188 | 189 | 190 | 191 | `; 192 | 193 | exports[`five slices 1`] = ` 194 | 215 | 223 | 241 | 255 | 269 | 283 | 284 | 285 | 286 | `; 287 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/snapshot.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`big numbers 1`] = ` 4 | 25 | 33 | 51 | 65 | 79 | 93 | 94 | 95 | 96 | `; 97 | 98 | exports[`doughnut chart 1`] = ` 99 | 120 | 128 | 146 | 160 | 174 | 188 | 202 | 203 | 204 | 205 | `; 206 | 207 | exports[`doughnut with cover chart 1`] = ` 208 | 229 | 237 | 255 | 269 | 283 | 297 | 311 | 325 | 326 | 327 | 328 | `; 329 | 330 | exports[`five slices 1`] = ` 331 | 352 | 360 | 378 | 392 | 406 | 420 | 434 | 448 | 449 | 450 | 451 | `; 452 | 453 | exports[`labels 1`] = ` 454 | 475 | 483 | 501 | 515 | 547 | 562 | 563 | 577 | 605 | 620 | 621 | 635 | 663 | 678 | 679 | 680 | 681 | 682 | `; 683 | 684 | exports[`large series 1`] = ` 685 | 706 | 714 | 732 | 746 | 760 | 774 | 788 | 802 | 816 | 830 | 844 | 858 | 872 | 886 | 900 | 914 | 915 | 916 | 917 | `; 918 | 919 | exports[`pad angle 1`] = ` 920 | 941 | 949 | 967 | 981 | 995 | 1009 | 1023 | 1024 | 1025 | 1026 | `; 1027 | 1028 | exports[`small numbers 1`] = ` 1029 | 1050 | 1058 | 1076 | 1090 | 1104 | 1118 | 1119 | 1120 | 1121 | `; 1122 | 1123 | exports[`small series 1`] = ` 1124 | 1145 | 1153 | 1171 | 1185 | 1186 | 1187 | 1188 | `; 1189 | 1190 | exports[`zero in the series 1`] = ` 1191 | 1212 | 1220 | 1238 | 1252 | 1266 | 1280 | 1294 | 1308 | 1309 | 1310 | 1311 | `; 1312 | -------------------------------------------------------------------------------- /__tests__/oldApiSnapshot.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'react-native' 3 | 4 | import renderer from 'react-test-renderer' 5 | 6 | import { it, expect } from '@jest/globals' 7 | 8 | import PieChart from '../src/v3api' 9 | 10 | it('five slices', () => { 11 | const series = [100, 200, 50] 12 | const colors = ['red', '#ff88bb', 'black'] 13 | 14 | const rendered = renderer.create().toJSON() 15 | expect(rendered).toMatchSnapshot() 16 | }) 17 | 18 | it('doughnut', () => { 19 | const series = [100, 200, 50] 20 | const colors = ['red', '#ff88bb', 'black'] 21 | 22 | const rendered = renderer 23 | .create() 24 | .toJSON() 25 | expect(rendered).toMatchSnapshot() 26 | }) 27 | 28 | it('doughnut with fill', () => { 29 | const series = [100, 200, 50] 30 | const colors = ['red', '#ff88bb', 'black'] 31 | 32 | const rendered = renderer 33 | .create() 34 | .toJSON() 35 | expect(rendered).toMatchSnapshot() 36 | }) 37 | 38 | it('should throws error when length of color and series does not match', () => { 39 | const series = [100, 200, 50] 40 | const colors = ['red', '#ff88bb'] 41 | 42 | expect(() => renderer.create()).toThrow( 43 | 'Invalid "sliceColor": its length should be equal to the length of "series". sliceColor.length=2 series.length=3' 44 | ) 45 | }) 46 | -------------------------------------------------------------------------------- /__tests__/snapshot.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'react-native' 3 | 4 | import renderer from 'react-test-renderer' 5 | 6 | import { it, expect } from '@jest/globals' 7 | 8 | import PieChart from '../src' 9 | 10 | it('five slices', () => { 11 | const series = [ 12 | { value: 430, color: '#fbd203' }, 13 | { value: 321, color: '#ffb300' }, 14 | { value: 185, color: '#ff9100' }, 15 | { value: 123, color: '#ff6c00' }, 16 | { value: 80, color: '#ff3c00' }, 17 | ] 18 | 19 | const rendered = renderer.create().toJSON() 20 | expect(rendered).toMatchSnapshot() 21 | }) 22 | 23 | it('zero in the series', () => { 24 | const series = [ 25 | { value: 430, color: '#fbd203' }, 26 | { value: 0, color: '#ffb300' }, 27 | { value: 185, color: '#ff9100' }, 28 | { value: 0, color: '#ff6c00' }, 29 | { value: 80, color: '#ff3c00' }, 30 | ] 31 | 32 | const rendered = renderer.create().toJSON() 33 | expect(rendered).toMatchSnapshot() 34 | }) 35 | 36 | it('small numbers', () => { 37 | const series = [ 38 | { value: 1, color: '#fbd203' }, 39 | { value: 0.5, color: '#ffb300' }, 40 | { value: 0.5, color: '#ff9100' }, 41 | ] 42 | 43 | const rendered = renderer.create().toJSON() 44 | expect(rendered).toMatchSnapshot() 45 | }) 46 | 47 | it('big numbers', () => { 48 | const series = [ 49 | { value: 999000, color: 'red' }, 50 | { value: 100000, color: 'blue' }, 51 | { value: 53000, color: '#000011' }, 52 | ] 53 | 54 | const rendered = renderer.create().toJSON() 55 | expect(rendered).toMatchSnapshot() 56 | }) 57 | 58 | it('small series', () => { 59 | const series = [{ value: 1, color: 'black' }] 60 | 61 | const rendered = renderer.create().toJSON() 62 | expect(rendered).toMatchSnapshot() 63 | }) 64 | 65 | it('large series', () => { 66 | const series = [ 67 | { value: 1, color: 'black' }, 68 | { value: 2, color: 'red' }, 69 | { value: 3, color: 'blue' }, 70 | { value: 4, color: 'pink' }, 71 | { value: 200, color: '#000000' }, 72 | { value: 300, color: '#001100' }, 73 | { value: 400, color: '#99ff00' }, 74 | { value: 100, color: '#ffaabb' }, 75 | { value: 1, color: 'white' }, 76 | { value: 1, color: '#ffaabb' }, 77 | { value: 1, color: '#987654' }, 78 | { value: 1, color: 'black' }, 79 | { value: 1, color: 'pink' }, 80 | ] 81 | 82 | const rendered = renderer.create().toJSON() 83 | expect(rendered).toMatchSnapshot() 84 | }) 85 | 86 | it('labels', () => { 87 | const series = [ 88 | { value: 10, color: '#ff00bb', label: { text: '10%', fill: 'red' } }, 89 | { value: 5, color: '#00ffbb', label: { text: '10%', fontSize: 12 } }, 90 | { value: 3.5, color: '#ffffbb', label: { text: '10%', fontWeight: 'bold', offsetX: 10, offsetY: -5 } }, 91 | ] 92 | 93 | const rendered = renderer.create().toJSON() 94 | expect(rendered).toMatchSnapshot() 95 | }) 96 | 97 | it('doughnut chart', () => { 98 | const series = [ 99 | { value: 200, color: '#fbd203' }, 100 | { value: 250, color: '#ffaabb' }, 101 | { value: 123, color: '#ff6c00' }, 102 | { value: 80, color: '#ff3c00' }, 103 | ] 104 | 105 | const rendered = renderer.create().toJSON() 106 | expect(rendered).toMatchSnapshot() 107 | }) 108 | 109 | it('doughnut with cover chart', () => { 110 | const series = [ 111 | { value: 200, color: '#fbd203' }, 112 | { value: 250, color: '#ffaabb' }, 113 | { value: 123, color: '#ff6c00' }, 114 | { value: 80, color: '#ff3c00' }, 115 | ] 116 | 117 | const rendered = renderer 118 | .create() 119 | .toJSON() 120 | expect(rendered).toMatchSnapshot() 121 | }) 122 | 123 | it('pad angle', () => { 124 | const series = [ 125 | { value: 50, color: '#fbd203' }, 126 | { value: 10, color: '#ffaabb' }, 127 | { value: 20, color: '#ff6c00' }, 128 | { value: 30, color: '#ff3c00' }, 129 | ] 130 | 131 | const rendered = renderer.create().toJSON() 132 | expect(rendered).toMatchSnapshot() 133 | }) 134 | 135 | it('check for negative in series', () => { 136 | const series = [ 137 | { value: 430, color: '#fbd203' }, 138 | { value: -120, color: '#ffb300' }, 139 | { value: 185, color: '#ff9100' }, 140 | ] 141 | 142 | expect(() => renderer.create()).toThrow( 143 | `Invalid series: all numbers should be positive. The invalid slice: {"value":-120,"color":"#ffb300"}` 144 | ) 145 | }) 146 | 147 | it('check for all zeros series', () => { 148 | const series = [ 149 | { value: 0, color: '#fbd203' }, 150 | { value: 0, color: '#ffb300' }, 151 | { value: 0, color: '#ff9100' }, 152 | ] 153 | 154 | expect(() => renderer.create()).toThrow( 155 | 'Invalid series: sum of series is zero' 156 | ) 157 | }) 158 | 159 | it('check for bad cover radius', () => { 160 | const series = [ 161 | { value: 100, color: '#fbd203' }, 162 | { value: 200, color: '#ffb300' }, 163 | { value: 50, color: '#ff9100' }, 164 | ] 165 | 166 | const expectedError = (val: string) => `Invalid "coverRadius": It should be between zero and one. But it's ${val}` 167 | expect(() => renderer.create()).toThrow( 168 | expectedError('1.1') 169 | ) 170 | expect(() => renderer.create()).toThrow( 171 | expectedError('-1') 172 | ) 173 | expect(() => renderer.create()).toThrow( 174 | expectedError('0') 175 | ) 176 | }) 177 | 178 | it('color is mandatory', () => { 179 | const series = [{ value: 430, color: '#fbd203' }, { value: 123 }, { value: 80, color: '#ff3c00' }] 180 | 181 | expect(() => renderer.create()).toThrow( 182 | `'color' is mandatory in the series. The invalid slice: {"value":123}` 183 | ) 184 | }) 185 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:@react-native/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | import { StatusBar } from 'expo-status-bar' 2 | import { StyleSheet, Text, View, ScrollView } from 'react-native' 3 | import PieChart from 'react-native-pie-chart' 4 | 5 | export default function App() { 6 | const widthAndHeight = 250 7 | const series = [ 8 | { value: 430, color: '#fbd203' }, 9 | { value: 321, color: '#ffb300' }, 10 | { value: 185, color: '#ff9100' }, 11 | { value: 123, color: '#ff6c00' }, 12 | { value: 80, color: '#ff3c00' }, 13 | ] 14 | const seriesWithLabel = [ 15 | { value: 40, color: '#fbd203', label: { text: '40%', fontWeight: 'bold' } }, 16 | { value: 30, color: '#ffb300', label: { text: '30%' } }, 17 | { value: 20, color: '#ff9100', label: { text: '20%' } }, 18 | { value: 10, color: '#ff6c00' }, 19 | ] 20 | 21 | return ( 22 | 23 | 24 | 25 | 26 | Pie 27 | 28 | 29 | Doughnut 30 | 31 | 32 | Doughnut with fill & Pad Angle 33 | 39 | 40 | With Labels 41 | 42 | 43 | 44 | ) 45 | } 46 | 47 | const styles = StyleSheet.create({ 48 | scrollContainer: { 49 | flex: 1, 50 | }, 51 | container: { 52 | flex: 1, 53 | backgroundColor: '#fff', 54 | alignItems: 'center', 55 | justifyContent: 'center', 56 | }, 57 | title: { 58 | fontSize: 24, 59 | margin: 10, 60 | }, 61 | }) 62 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "example", 4 | "slug": "example", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "newArchEnabled": true, 10 | "splash": { 11 | "image": "./assets/splash.png", 12 | "resizeMode": "contain", 13 | "backgroundColor": "#ffffff" 14 | }, 15 | "ios": { 16 | "supportsTablet": true 17 | }, 18 | "android": { 19 | "adaptiveIcon": { 20 | "foregroundImage": "./assets/adaptive-icon.png", 21 | "backgroundColor": "#ffffff" 22 | } 23 | }, 24 | "web": { 25 | "favicon": "./assets/favicon.png" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidin36/react-native-pie-chart/1137d09543da11e77249268a870a5ef8d77e64fd/example/assets/adaptive-icon.png -------------------------------------------------------------------------------- /example/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidin36/react-native-pie-chart/1137d09543da11e77249268a870a5ef8d77e64fd/example/assets/favicon.png -------------------------------------------------------------------------------- /example/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidin36/react-native-pie-chart/1137d09543da11e77249268a870a5ef8d77e64fd/example/assets/icon.png -------------------------------------------------------------------------------- /example/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidin36/react-native-pie-chart/1137d09543da11e77249268a870a5ef8d77e64fd/example/assets/splash.png -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "main": "expo/AppEntry.js", 5 | "scripts": { 6 | "start": "expo start", 7 | "start:clean": "expo start -c", 8 | "android": "expo start --android", 9 | "ios": "expo start --ios", 10 | "web": "expo start --web", 11 | "tsc": "tsc" 12 | }, 13 | "dependencies": { 14 | "expo": "52.0.23", 15 | "expo-status-bar": "2.0.0", 16 | "react": "18.2.0", 17 | "react-native": "0.76.5", 18 | "react-native-pie-chart": "4.0.0", 19 | "react-native-svg": "15.8.0" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "7.26.0", 23 | "@types/react": "18.3.12", 24 | "typescript": "5.7.2" 25 | }, 26 | "private": true, 27 | "volta": { 28 | "node": "22.12.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'react-native', 3 | collectCoverage: true, 4 | collectCoverageFrom: ["./src/**"], 5 | moduleNameMapper: { 6 | // Jest has issues with 'd3' package. This is not a perfect solution because 7 | // I'm not sure what version of `d3-shape` do we ship with our bundle. 8 | '^d3-shape$': '/node_modules/d3-shape/dist/d3-shape.min.js', 9 | '^d3-path$': '/node_modules/d3-path/dist/d3-path.min.js', 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pie-chart", 3 | "version": "4.0.1", 4 | "description": "pie chart for react native", 5 | "scripts": { 6 | "tsc": "tsc", 7 | "tsc:watch": "tsc --watch", 8 | "pretty": "prettier './src/**/*.ts*' --write --config .prettierrc", 9 | "lint": "eslint --quiet './src/**/*.ts*'", 10 | "check": "npm run pretty && npm run lint && npm run tsc", 11 | "compile": "babel src --out-dir dist --extensions '.ts,.tsx'", 12 | "build": "echo 'Error: use make build instead' && exit 3", 13 | "test": "jest" 14 | }, 15 | "private": true, 16 | "main": "index.js", 17 | "types": "index.d.ts", 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/aidin36/react-native-pie-chart" 21 | }, 22 | "author": "Aidin Gharibnavaz", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/aidin36/react-native-pie-chart/issues" 26 | }, 27 | "keywords": [ 28 | "react", 29 | "react-native", 30 | "chart", 31 | "pie-chart", 32 | "visualization" 33 | ], 34 | "peerDependencies": { 35 | "react": ">=18.2.0", 36 | "react-native": ">=0.73.0", 37 | "react-native-svg": ">=15.8.0" 38 | }, 39 | "devDependencies": { 40 | "@babel/cli": "7.26.4", 41 | "@babel/core": "7.26.0", 42 | "@babel/eslint-parser": "7.25.9", 43 | "@babel/runtime": "7.26.0", 44 | "@jest/globals": "^29.7.0", 45 | "@react-native/babel-preset": "0.76.5", 46 | "@react-native/eslint-config": "0.76.5", 47 | "@types/react": "18.3.12", 48 | "@typescript-eslint/eslint-plugin": "8.18.0", 49 | "@typescript-eslint/parser": "8.18.0", 50 | "babel-jest": "29.7.0", 51 | "eslint": "8.57.0", 52 | "eslint-config-airbnb": "19.0.4", 53 | "eslint-config-prettier": "9.1.0", 54 | "eslint-plugin-import": "2.31.0", 55 | "eslint-plugin-jsx-a11y": "6.10.2", 56 | "eslint-plugin-prettier": "5.2.1", 57 | "eslint-plugin-react": "7.37.2", 58 | "eslint-plugin-react-native": "4.1.0", 59 | "eslint-plugin-tsdoc": "0.4.0", 60 | "jest": "29.7.0", 61 | "prettier": "3.4.2", 62 | "react": "18.3.1", 63 | "react-native": "0.76.5", 64 | "react-test-renderer": "18.3.1", 65 | "typescript": "5.7.2" 66 | }, 67 | "dependencies": { 68 | "d3-shape": "3.2.0" 69 | }, 70 | "volta": { 71 | "node": "22.12.0" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aidin36/react-native-pie-chart/1137d09543da11e77249268a870a5ef8d77e64fd/preview.png -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | GIT_STATUS=$(git status --porcelain=1) 6 | if [ -n "$GIT_STATUS" ]; then 7 | echo 8 | echo "The repo is not clean!" 9 | exit 1 10 | fi 11 | 12 | npm install 13 | make clean 14 | make check 15 | make build 16 | 17 | echo 18 | read -p "Publish to npmjs? (y/n) " choice 19 | if [ $choice != 'y' ] 20 | then 21 | exit 0 22 | fi 23 | 24 | echo "Tagging git..." 25 | VERSION=$(node -p "require('./package.json').version") 26 | git tag "v""$VERSION" 27 | git push --tags 28 | 29 | echo "Publishing to npmjs..." 30 | cp README.md LICENSE preview.png dist/ 31 | cd dist 32 | npm login 33 | npm publish --access public 34 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Aidin Gharibnavaz 2 | 3 | import { Fragment } from 'react' 4 | import { StyleProp, ViewStyle } from 'react-native' 5 | import { Svg, G, Path, Text, FontWeight, NumberProp, FontStyle } from 'react-native-svg' 6 | import * as d3 from 'd3-shape' 7 | 8 | export type SliceLabel = { 9 | /** 10 | * Text of the label 11 | */ 12 | text: string 13 | /** 14 | * Color to fill the font with 15 | */ 16 | fill?: string 17 | /** 18 | * Color of the font's outline 19 | */ 20 | stroke?: string 21 | /** 22 | * string or number 23 | */ 24 | fontSize?: NumberProp 25 | /** 26 | * Can be: 27 | *'normal', 'bold', 'bolder', 'lighter', '100', '200',... until '900' 28 | */ 29 | fontWeight?: FontWeight 30 | /** 31 | * Name of the font 32 | */ 33 | fontFamily?: string 34 | /** 35 | * Can be: 36 | * 'normal', 'italic', 'oblique' 37 | */ 38 | fontStyle?: FontStyle 39 | /** 40 | * By default, the label will be placed at the center of the slice. 41 | * You can change it by setting these offsets. These are offset from 42 | * the center. These can be negative. 43 | */ 44 | offsetX?: number 45 | offsetY?: number 46 | } 47 | 48 | /** 49 | * Represents one slice of the pie 50 | */ 51 | export type Slice = { 52 | /** 53 | * Value the slice represents. 54 | * Should be a positive number. 55 | */ 56 | value: number 57 | /** 58 | * Color of the slice. Can be any string that HTML & CSS accepts. 59 | */ 60 | color: string 61 | /** 62 | * Optional label that appears on top of the slice. 63 | */ 64 | label?: SliceLabel 65 | } 66 | 67 | /** 68 | * Represents the hole inside the doughnut chart 69 | */ 70 | export type Cover = { 71 | /** 72 | * Radius of the doughnut hole, in precentage. 73 | * For example 0.3 to cover 30% of the center of the chart. 74 | */ 75 | radius: number 76 | /** 77 | * Optional. Color of the doughnut hole. 78 | * If you want the hole to be transparent, don't provide this 79 | * field. 80 | */ 81 | color?: string 82 | } 83 | 84 | export type Props = { 85 | /** 86 | * Diameter of the chart. In otherwords, size of the square that wraps the chart's circle. 87 | */ 88 | widthAndHeight: number 89 | /** 90 | * Chart's data. 91 | * The sum of the series values cannot be zero. 92 | */ 93 | series: Slice[] 94 | /** 95 | * Optional. 96 | * If a `number`, it's the radius of the doughnut's hole, in percentage. 97 | * (The hole will be transparent). 98 | * Should be between zero and one. 99 | * It can be an object that also defined the color of the hole. 100 | */ 101 | cover?: number | Cover 102 | /** 103 | * Optional. 104 | * React-native's style object. This will apply to the chart's SVG. 105 | */ 106 | style?: StyleProp 107 | /** 108 | * If provided, it creates a gap between the slices. Use very small numbers, like `0.01`. 109 | */ 110 | padAngle?: number 111 | } 112 | 113 | const PieChart = ({ widthAndHeight, series, cover, style = {}, padAngle }: Props): JSX.Element => { 114 | // Validating props 115 | series.forEach((s) => { 116 | if (s.value < 0) { 117 | throw Error(`Invalid series: all numbers should be positive. The invalid slice: ${JSON.stringify(s)}`) 118 | } 119 | if (!s.color) { 120 | throw Error(`'color' is mandatory in the series. The invalid slice: ${JSON.stringify(s)}`) 121 | } 122 | }) 123 | 124 | const sum = series.reduce((acc, current) => acc + current.value, 0) 125 | if (sum <= 0) { 126 | throw Error('Invalid series: sum of series is zero') 127 | } 128 | 129 | const coverRadius: number | undefined = typeof cover === 'object' ? cover.radius : cover 130 | const coverColor: string | undefined = typeof cover === 'object' ? cover.color : undefined 131 | 132 | if (coverRadius != null && (coverRadius <= 0 || coverRadius >= 1)) { 133 | throw Error(`Invalid "coverRadius": It should be between zero and one. But it's ${coverRadius}`) 134 | } 135 | 136 | const radius = widthAndHeight / 2 137 | 138 | const arcs = d3 139 | .pie() 140 | .sort(null) 141 | // Using selector allows us to have the original data object in the 'arc.data'. 142 | .value((d) => d.value)(series) 143 | 144 | return ( 145 | 146 | 147 | {arcs.map((arc) => { 148 | let arcGenerator = d3.arc().outerRadius(radius).startAngle(arc.startAngle).endAngle(arc.endAngle) 149 | 150 | if (padAngle) { 151 | arcGenerator = arcGenerator.padAngle(padAngle) 152 | } 153 | 154 | // When 'coverColor' is also provided, instead of setting the 155 | // 'innerRadius', we draw a circle in the middle. See the 'Path' 156 | // after the 'map'. 157 | if (!coverRadius) { 158 | arcGenerator = arcGenerator.innerRadius(0) 159 | } else { 160 | arcGenerator = arcGenerator.innerRadius(coverRadius * radius) 161 | } 162 | 163 | const [sliceCenterX, sliceCenterY] = arcGenerator.centroid(arc) 164 | const sliceColor = arc.data.color 165 | const sliceLabel = arc.data.label 166 | 167 | return ( 168 | 169 | 170 | {sliceLabel && ( 171 | 183 | {sliceLabel.text} 184 | 185 | )} 186 | 187 | ) 188 | })} 189 | 190 | {coverRadius && coverRadius > 0 && coverColor && ( 191 | 201 | )} 202 | 203 | 204 | ) 205 | } 206 | 207 | export default PieChart 208 | -------------------------------------------------------------------------------- /src/v3api.tsx: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Aidin Gharibnavaz 2 | 3 | import { StyleProp, ViewStyle } from 'react-native' 4 | 5 | import PieChartV4 from './index' 6 | 7 | export type Props = { 8 | /** 9 | * Diameter of the chart. In otherwords, size of the square that wraps the chart's circle. 10 | */ 11 | widthAndHeight: number 12 | /** 13 | * Chart's data. Should be a list of all positive (or zero) numbers. 14 | * The sum of the series cannot be zero. 15 | */ 16 | series: number[] 17 | /** 18 | * Color of each slice. The first element is the color of the first slice, 19 | * the second one is the color of the second slice, and so on. 20 | * The size of the `sliceColor` array should be equal to the size of the `series` array. 21 | */ 22 | sliceColor: string[] 23 | /** 24 | * Color of the doughnut's hole. 25 | * Don't provide it or set it to null to make it transparent. 26 | */ 27 | coverFill?: string | null 28 | /** 29 | * Size of the doughnut's hole, in percentage. 30 | * Should be between zero and one. 31 | */ 32 | coverRadius?: number 33 | /** 34 | * React-native's style object. This will apply to the chart's SVG. 35 | */ 36 | style?: StyleProp 37 | } 38 | 39 | const PieChart = ({ 40 | widthAndHeight, 41 | series, 42 | sliceColor, 43 | coverFill = null, 44 | coverRadius, 45 | style = {}, 46 | }: Props): JSX.Element => { 47 | // Validating props 48 | if (sliceColor.length != series.length) { 49 | throw Error( 50 | `Invalid "sliceColor": its length should be equal to the length of "series". sliceColor.length=${sliceColor.length} series.length=${series.length}` 51 | ) 52 | } 53 | 54 | const newApiSeries = series.map((value, i) => ({ value, color: sliceColor[i] })) 55 | 56 | const coverRadiusObject = coverRadius ? { radius: coverRadius } : undefined 57 | const cover = coverRadiusObject && coverFill ? { ...coverRadiusObject, color: coverFill } : coverRadiusObject 58 | 59 | return 60 | } 61 | 62 | export default PieChart 63 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | "lib": ["es2019"], /* Specify library files to be included in the compilation. */ 7 | "allowJs": false, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | "jsx": "react-native", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | "emitDeclarationOnly": true, 12 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | "outDir": "./dist", /* Redirect output structure to the directory. */ 14 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 15 | // "removeComments": true, /* Do not emit comments to output. */ 16 | // "noEmit": true, /* Do not emit outputs. */ 17 | // "incremental": true, /* Enable incremental compilation */ 18 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 19 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 20 | "isolatedModules": false, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 21 | 22 | /* Strict Type-Checking Options */ 23 | "strict": true, /* Enable all strict type-checking options. */ 24 | "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | // "strictNullChecks": true, /* Enable strict null checks. */ 26 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 27 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 28 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 29 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 30 | 31 | /* Additional Checks */ 32 | "noUnusedLocals": true, /* Report errors on unused locals. */ 33 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 34 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 35 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 36 | 37 | /* Module Resolution Options */ 38 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 39 | "resolveJsonModule": true, 40 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 41 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 42 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 43 | "typeRoots": ["./node_modules/@types"], /* List of folders to include type definitions from. */ 44 | "types": ["react"], /* Type declaration files to be included in compilation. */ 45 | "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 46 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 47 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 48 | // I had to add this, otherwise react-native-svg throws errors. 49 | "skipLibCheck": true, 50 | 51 | /* Source Map Options */ 52 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 53 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 54 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 55 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 56 | 57 | /* Experimental Options */ 58 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 59 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 60 | 61 | }, 62 | "exclude": [ 63 | "node_modules", "babel.config.js", "metro.config.js", "dist", "example", "__tests__", 64 | ] 65 | } 66 | --------------------------------------------------------------------------------