diff --git a/README.md b/README.md
index 5f936f94..4a4a513b 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,14 @@
# phosphor-react-native
+[](https://www.npmjs.com/package/phosphor-react-native)
+[](https://www.npmjs.com/package/phosphor-react-native)
+[](LICENSE)
+
Phosphor is a flexible icon family for interfaces, diagrams, presentations — whatever, really. Explore all our icons at [phosphoricons.com](https://phosphoricons.com).
-Inspired by [phosphor-react](https://github.com/phosphor-icons/phosphor-react).
+Inspired by [@phosphor-icons/react](https://github.com/phosphor-icons/react).
+
+This package ships 1512 icons in 6 weights, generated from [@phosphor-icons/core](https://github.com/phosphor-icons/core).
@@ -28,9 +34,15 @@ or
npm install --save phosphor-react-native react-native-svg
```
+Expo:
+
+```bash
+npx expo install phosphor-react-native react-native-svg
+```
+
## Usage
-Simply import the icons you need, and add them anywhere in your render method. Phosphor supports tree-shaking, so your bundle only includes code for the icons you use.
+Import the icons you need, and add them anywhere in your render method.
```tsx
import React from 'react';
@@ -48,6 +60,31 @@ const App = () => {
};
```
+### Bundle size
+
+Metro does not tree-shake by default, so the import above pulls **all 1512 icons** into your bundle even if you use three of them. See [#61](https://github.com/duongdev/phosphor-react-native/issues/61).
+
+Two ways to avoid that:
+
+**1. Import each icon directly** — works on every setup, no configuration:
+
+```tsx
+import { StarIcon } from 'phosphor-react-native/src/icons/Star';
+```
+
+**2. Enable Expo's experimental tree-shaking** — see [the Expo guide](https://docs.expo.dev/guides/tree-shaking/). Then the barrel import is just as small.
+
+Measured with `yarn bundle-bench` (real Metro, iOS, minified, v3.0.5):
+
+| Scenario | Bundle | vs baseline |
+| --- | --- | --- |
+| Barrel import, 1 icon, no tree-shaking | 8597 kB | +182% |
+| Barrel import, 3 icons, no tree-shaking | 8598 kB | +182% |
+| Direct import, 1 icon, no tree-shaking | 1876 kB | +10% |
+| Barrel import, 1 icon, tree-shaking on | 1854 kB | +10% |
+
+Icons are generated per icon, not per weight, so a single icon always carries all 6 weights.
+
### Typescript support
If you get this error...
```
@@ -55,33 +92,39 @@ Property 'className' does not exist on type 'IntrinsicAttributes & IntrinsicClas
```
Add this code to your `global.d.ts` file
```ts
-import type { SvgProps as DefaultSvgProps } from 'react-native-svg';
+import 'react-native-svg';
+import 'phosphor-react-native';
declare module 'react-native-svg' {
- interface SvgProps extends DefaultSvgProps {
+ interface SvgProps {
className?: string;
}
}
-declare module "phosphor-react-native" {
- interface IconProps extends DefaultIconProps {
+declare module 'phosphor-react-native' {
+ interface IconProps {
className?: string;
}
}
```
+Module augmentation merges into the existing interface, so declare only the extra members — writing `interface SvgProps extends DefaultSvgProps` makes the type reference itself (`TS2310`).
+
### Props
-Icon components accept all props that you can pass to a normal SVG element, including inline `style` objects, `onClick` handlers, and more. The main way of styling them will usually be with the following props:
+Icons are styled with the following props:
-- **color?**: `string` – Icon stroke/fill color. Can be any CSS color string, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors.
-- **size?**: `number | string` – Icon height & width. As with standard React elements, this can be a number, or a string with units in `px`, `%`, `em`, `rem`, `pt`, `cm`, `mm`, `in`.
-- **weight?**: `"thin" | "light" | "regular" | "bold" | "fill" | "duotone"` – Icon weight/style. Can also be used, for example, to "toggle" an icon's state: a rating component could use Stars with `weight="regular"` to denote an empty star, and `weight="fill"` to denote a filled star.
-- **mirrored?**: `boolean` – Flip the icon horizontally. Can be useful in RTL languages where normal icon orientation is not appropriate.
+- **color?**: `string` – Icon stroke/fill color. Any color string React Native accepts, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors. Default `#000`.
+- **size?**: `number | string` – Icon height & width. Default `24`. Use a number, or a percentage string such as `"50%"`. Other unit suffixes are parsed with `parseInt`, so `"24px"` is `24` — but `"2rem"` is also `2`, not 32.
+- **weight?**: `"thin" | "light" | "regular" | "bold" | "fill" | "duotone"` – Icon weight/style. Default `regular`. Can also be used, for example, to "toggle" an icon's state: a rating component could use Stars with `weight="regular"` to denote an empty star, and `weight="fill"` to denote a filled star.
+- **mirrored?**: `boolean` – Flip the icon horizontally. Default `false`. Can be useful in RTL languages where normal icon orientation is not appropriate.
+- **style?**: `StyleProp>` – Style applied to the underlying `Svg`.
- **title?**: `string` – Accessibility label
- **titleId?**: `string` – Accessibility label ID
-- **testID?**: `string` – testID for tests
-- **duotoneColor?**: `string` – Duotone fill color. Can be any CSS color string, including `hex`, `rgb`, `rgba`, `hsl`, `hsla`, named colors. Default value to black.
-- **duotoneOpacity?**: `number` – The opacity of the duotoneColor. Default value to 0.2.
+- **testID?**: `string` – testID for tests. Falls back to `phosphor-react-native--`, where `` is the weight you passed explicitly.
+- **duotoneColor?**: `string` – Fill color of the duotone background layer. Defaults to `color`, so an icon with `color="teal"` gets a teal background layer — not a black one.
+- **duotoneOpacity?**: `number` – The opacity of the duotoneColor. Default `0.2`.
+
+`IconProps` is a closed type: props outside this list (`onPress`, `fill`, …) are forwarded to the underlying `Svg` at runtime, but TypeScript rejects them. Widen `IconProps` with [module augmentation](#typescript-support) if you need more.
### Context
@@ -111,11 +154,13 @@ const App = () => {
};
```
+Every styling prop is context-able: `color`, `size`, `weight`, `mirrored`, `style`, `duotoneColor` and `duotoneOpacity`. Props set on an icon win over the Context. Defaults when neither is set: `color: '#000'`, `size: 24`, `weight: 'regular'`, `mirrored: false`, `duotoneOpacity: 0.2`.
+
You may create multiple Contexts for styling icons differently in separate regions of an application; icons use the nearest Context above them to determine their style.
### Imports
-You may wish to import all icons at once for use in your project, though depending on your bundler this could prevent tree-shaking and make your app's bundle larger.
+You may wish to import all icons at once for use in your project. Without tree-shaking this pulls every icon into your bundle — see [Bundle size](#bundle-size).
```tsx
import * as Icon from "phosphor-react-native";
@@ -129,25 +174,42 @@ import * as Icon from "phosphor-react-native";
In cases where tree shaking does not work (resulting in large bundle size), you can import icons individually in this format:
```tsx
-// Javascript
-import { StarIcon } from "phosphor-react-native/lib/commonjs/icons/Star";
-
-// Typescript
import { StarIcon } from 'phosphor-react-native/src/icons/Star';
-
+
+```
+
+The file name is the icon name in PascalCase (`arrow-left` → `ArrowLeft`), and the export is that name suffixed with `Icon`. `src/icons/*` is the only subpath this package exports — importing from `lib/commonjs/...` fails with `ERR_PACKAGE_PATH_NOT_EXPORTED` on any bundler that honours `exports`, which Metro does by default since React Native 0.79.
+
+### Migrating from v2
+
+Since v3 every icon is exported with an `Icon` suffix: `Horse` → `HorseIcon`. The old names still work but are marked `@deprecated`, except for three whose bare names collide with other identifiers and were removed outright:
+
+| v2 | v3 |
+| --- | --- |
+| `Circle` | `CircleIcon` |
+| `Path` | `PathIcon` |
+| `Infinity` | `InfinityIcon` |
+
+## Contributing
+
+See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow. A runnable Expo app lives in [`example/`](example). Icons are generated from the `core` git submodule, so start with:
+
+```bash
+git submodule update --init --recursive
```
## Related Projects
-- [phosphor-home](https://github.com/phosphor-icons/phosphor-home) ▲ Phosphor homepage and general info
-- [phosphor-react](https://github.com/phosphor-icons/phosphor-react) ▲ Phosphor icon component library for React
-- [phosphor-vue](https://github.com/phosphor-icons/phosphor-vue) ▲ Phosphor icon component library for Vue
-- [phosphor-icons](https://github.com/phosphor-icons/phosphor-icons) ▲ Phosphor icons for Vanilla JS
-- [phosphor-flutter](https://github.com/phosphor-icons/phosphor-flutter) ▲ Phosphor IconData library for Flutter
-- [phosphor-webcomponents](https://github.com/phosphor-icons/phosphor-webcomponents) ▲ Phosphor icons as Web Components
-- [phosphor-figma](https://github.com/phosphor-icons/phosphor-figma) ▲ Phosphor icons Figma plugin
-- [phosphor-sketch](https://github.com/phosphor-icons/phosphor-sketch) ▲ Phosphor icons Sketch plugin
+- [homepage](https://github.com/phosphor-icons/homepage) ▲ Phosphor homepage and general info
+- [core](https://github.com/phosphor-icons/core) ▲ Phosphor icon assets, the source this package generates from
+- [react](https://github.com/phosphor-icons/react) ▲ Phosphor icon component library for React
+- [vue](https://github.com/phosphor-icons/vue) ▲ Phosphor icon component library for Vue
+- [web](https://github.com/phosphor-icons/web) ▲ Phosphor icons for Vanilla JS
+- [flutter](https://github.com/phosphor-icons/flutter) ▲ Phosphor IconData library for Flutter
+- [webcomponents](https://github.com/phosphor-icons/webcomponents) ▲ Phosphor icons as Web Components
+- [figma](https://github.com/phosphor-icons/figma) ▲ Phosphor icons Figma plugin
+- [sketch](https://github.com/phosphor-icons/sketch) ▲ Phosphor icons Sketch plugin
## License
diff --git a/global.d.ts b/global.d.ts
index 88840e3c..72f73dd8 100644
--- a/global.d.ts
+++ b/global.d.ts
@@ -1,7 +1,7 @@
-import type { SvgProps as DefaultSvgProps } from 'react-native-svg';
+import 'react-native-svg';
declare module 'react-native-svg' {
- interface SvgProps extends DefaultSvgProps {
+ interface SvgProps {
className?: string;
}
}