@shaquillehinds/react-native-svg-icons 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,470 +1,346 @@
1
- # react-native-svg-icons
1
+ # @shaquillehinds/react-native-svg-icons
2
2
 
3
- A comprehensive, type-safe SVG icon library for React Native with 997+ icons in both filled and outline variants.
3
+ A type-safe SVG icon set for React Native. 997 icons in each of two variants
4
+ `filled` and `outline` — with icon names validated at compile time and built-in
5
+ path animation.
4
6
 
5
- <p align="center">
6
- <img src="https://raw.githubusercontent.com/shaquillehinds/react-native-svg-icons/master/assets/svgicons.gif" alt="example" height="500"/>
7
- </p>
8
-
9
- ## Features
7
+ ---
10
8
 
11
- - 🎨 **997+ Icons** - Extensive collection covering UI elements, social media, crypto, arrows, shapes, and more
12
- - 🔒 **Fully Type-Safe** - TypeScript-first with auto-generated types ensuring icon names are validated at compile time
13
- - 🎭 **Dual Variants** - Every icon available in both `filled` and `outline` styles
14
- - ⚡ **Performance Optimized** - Tree-shakeable with efficient SVG rendering via `react-native-svg`
15
- - 🎨 **Highly Customizable** - Control size, color, and pass custom SVG/Path props
16
- - ✨ **Built-in Animations** - Powerful animation support with two modes: interpolation-based and property-based animations
17
- - 🔧 **Zero Configuration** - Works out of the box with sensible defaults
9
+ ## Contents
18
10
 
19
- ## Installation
11
+ - [Installation](#installation)
12
+ - [Quick start](#quick-start)
13
+ - [Finding icon names](#finding-icon-names)
14
+ - [Props](#props)
15
+ - [Filled vs outline](#filled-vs-outline)
16
+ - [TypeScript](#typescript)
17
+ - [Animation](#animation)
18
+ - [Bundle size](#bundle-size)
19
+ - [Recipes](#recipes)
20
+ - [Troubleshooting](#troubleshooting)
21
+ - [AI agent rules](#ai-agent-rules)
20
22
 
21
- ```bash
22
- npm install react-native-svg-icons react-native-svg @shaquillehinds/react-native-essentials
23
- ```
23
+ ---
24
24
 
25
- or
25
+ ## Installation
26
26
 
27
27
  ```bash
28
- yarn add react-native-svg-icons react-native-svg @shaquillehinds/react-native-essentials
28
+ npm install @shaquillehinds/react-native-svg-icons react-native-svg @shaquillehinds/react-native-essentials
29
29
  ```
30
30
 
31
- **Note:** This package requires `react-native-svg` and `@shaquillehinds/react-native-essentials` as peer dependencies.
31
+ `react-native-svg` and `@shaquillehinds/react-native-essentials` are peer
32
+ dependencies.
32
33
 
33
- ### iOS Setup
34
-
35
- For iOS, you'll need to install pods:
34
+ iOS:
36
35
 
37
36
  ```bash
38
37
  cd ios && pod install
39
38
  ```
40
39
 
41
- ## Usage
40
+ ---
42
41
 
43
- ### Basic Usage
42
+ ## Quick start
44
43
 
45
44
  ```tsx
46
- import { SvgIcon } from 'react-native-svg-icons';
45
+ import { SvgIcon } from '@shaquillehinds/react-native-svg-icons';
47
46
 
48
47
  function MyComponent() {
49
- return <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />;
48
+ return (
49
+ <>
50
+ <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />
51
+ <SvgIcon type="outline" name="SearchNormal" size={20} color="#8E8E93" />
52
+ </>
53
+ );
50
54
  }
51
55
  ```
52
56
 
53
- ### With Outline Variant
57
+ `type` and `name` are required. `type` also selects which name union `name` is
58
+ checked against, so an outline-only name on `type="filled"` is a compile error.
54
59
 
55
- ```tsx
56
- <SvgIcon type="outline" name="Heart" size={24} color="#000000" />
57
- ```
60
+ ---
58
61
 
59
- ### Custom SVG Props
62
+ ## Finding icon names
60
63
 
61
- ```tsx
62
- <SvgIcon
63
- type="filled"
64
- name="Star"
65
- size={32}
66
- color="#FFD700"
67
- svgProps={{
68
- opacity: 0.8,
69
- style: { marginRight: 8 },
70
- }}
71
- />
72
- ```
64
+ Names are irregular. Some concepts have no obvious name (`Search` does not exist;
65
+ `SearchNormal` does), some families carry misspellings that are part of the real
66
+ name, and a handful of names start with a lowercase letter or a digit. Look names
67
+ up rather than guessing.
73
68
 
74
- ### Custom Path Props
69
+ ### CLI
75
70
 
76
- ```tsx
77
- <SvgIcon
78
- type="outline"
79
- name="User"
80
- size={28}
81
- color="#333"
82
- pathProps={{
83
- strokeWidth: 2,
84
- strokeLinecap: 'round',
85
- }}
86
- />
71
+ ```sh
72
+ npx rnsi-icons search # fuzzy match across both variants
73
+ npx rnsi-icons arrow --type outline # restrict to one variant
74
+ npx rnsi-icons Trash --exact # confirm a single name
75
+ npx rnsi-icons --diff # names missing from one variant
76
+ npx rnsi-icons --list --shared # every name present in both
77
+ npx rnsi-icons search --json # machine-readable
87
78
  ```
88
79
 
89
- ## API Reference
80
+ `--limit N` caps output (default 40; `--limit 0` for everything).
90
81
 
91
- ### `<SvgIcon />`
82
+ ### Editor
92
83
 
93
- The main component for rendering icons.
84
+ `name` is a string-literal union, so autocomplete lists valid names inline and
85
+ TypeScript rejects anything else. Do not silence that with a cast.
94
86
 
95
- #### Props
87
+ ### Names people expect that do not exist
96
88
 
97
- | Prop | Type | Default | Description |
98
- | ----------- | ----------------------------------- | ----------- | ------------------------------------------------ |
99
- | `type` | `'filled' \| 'outline'` | Required | The icon variant to render |
100
- | `name` | `FilledIconName \| OutlineIconName` | Required | The name of the icon (type-safe based on `type`) |
101
- | `size` | `number` | `24` | The size of the icon in pixels |
102
- | `color` | `string` | `'#000000'` | The color of the icon |
103
- | `svgProps` | `SvgProps` | `undefined` | Additional props to pass to the SVG component |
104
- | `pathProps` | `PathProps` | `undefined` | Additional props to pass to the Path component |
105
- | `animate` | `AnimateSVGPathComponentProps` | `undefined` | Animation configuration (see Animation section) |
89
+ | Expected | Actual |
90
+ | -------------------- | ---------------------------------------------- |
91
+ | `Search` | `SearchNormal`, `SearchStatus`, `SearchZoomIn` |
92
+ | `Delete` | `Trash` |
93
+ | `Loading`, `Spinner` | `Refresh`, `RotateLeft`, `RotateRight` |
94
+ | `Warning` | `Warning2` |
95
+ | `Info` | `InfoCircle`, `Information` |
96
+ | `Close` | `CloseCircle`, `CloseSquare` |
97
+ | `Bitcoin` | `BitcoinBtc`, `BitcoinCard`, `BitcoinConvert` |
106
98
 
107
- ### Type Exports
99
+ ### Misspellings that are part of the name
108
100
 
109
- ```tsx
110
- import type {
111
- FilledIconName, // Union type of all filled icon names
112
- OutlineIconName, // Union type of all outline icon names
113
- IconName, // Union of both filled and outline names
114
- SvgIconType, // 'filled' | 'outline'
115
- SvgIconProps, // Component props type
116
- } from 'react-native-svg-icons';
117
- ```
101
+ These are the correct spellings as shipped. The "corrected" version will not
102
+ compile:
118
103
 
119
- ## Available Icons
104
+ `MinusCirlce` · `UserCirlceAdd` · `SendSqaure2` · `MonitorMobbile` ·
105
+ `Battery3full` · `BrifecaseCross` · `BrifecaseTick` · `BrifecaseTimer`
120
106
 
121
- This library includes 997+ icons across various categories:
107
+ `Briefcase` on its own is spelled normally; only its compounds are not.
122
108
 
123
- ### Categories
109
+ ### Other conventions
124
110
 
125
- - **UI Elements**: Add, Remove, Edit, Delete, Search, Filter, Menu, Close, etc.
126
- - **Arrows & Navigation**: Arrow variations in all directions, chevrons, points, swaps
127
- - **Social Media**: Facebook, Twitter, Instagram, YouTube, LinkedIn, etc.
128
- - **Crypto**: Bitcoin, Ethereum, various altcoin logos
129
- - **Shapes**: Circles, squares, triangles, hexagons, etc.
130
- - **Media**: Play, Pause, Stop, Record, Camera, Video, Music
131
- - **Communication**: Message, Call, Email, Notification, Chat
132
- - **Files & Folders**: Document, Folder, Archive, Cloud, Download, Upload
133
- - **Commerce**: Shopping bag, cart, wallet, card, tag
134
- - **User & Profile**: User, Profile, Avatar, Account, Team
135
- - **Time & Calendar**: Clock, Calendar, Timer, Alarm
136
- - **Location**: Map, Location, GPS, Compass, Globe
137
- - **Weather**: Sun, Moon, Cloud, Rain, Storm
138
- - **Security**: Lock, Unlock, Shield, Key, Eye, Scan
139
- - **Devices**: Mobile, Tablet, Desktop, Laptop, Watch
140
- - **And many more...**
111
+ - Numeric suffixes mark variants, not sizes `Home`, `Home1`, `Home2` and
112
+ `HomeHashtag` are four distinct icons.
113
+ - A few names begin lowercase or with a digit: `square`, `dcube`, `dRotate`,
114
+ `dSquare`, `dCubeScan`, `4Support`.
115
+ - `4Support` is the name to pass, even though its source file is `FourSupport.tsx`.
141
116
 
142
- ### Example Icon Names
117
+ ### Variant coverage
143
118
 
144
- ```tsx
145
- // UI Elements
146
- ('Add',
147
- 'AddCircle',
148
- 'AddSquare',
149
- 'Remove',
150
- 'Edit',
151
- 'Delete',
152
- 'Search',
153
- 'Filter');
154
-
155
- // Arrows
156
- ('ArrowUp',
157
- 'ArrowDown',
158
- 'ArrowLeft',
159
- 'ArrowRight',
160
- 'ArrowChevronUp',
161
- 'ArrowCircleDown');
162
-
163
- // Social Media
164
- ('Facebook', 'Instagram', 'Twitter', 'Youtube', 'Linkedin', 'Tiktok');
165
-
166
- // Crypto
167
- ('Bitcoin', 'Ethereum', 'Binance', 'Cardano', 'Polygon', 'Solana');
168
-
169
- // Media
170
- ('Play',
171
- 'Pause',
172
- 'Stop',
173
- 'Record',
174
- 'VolumeUp',
175
- 'VolumeDown',
176
- 'Camera',
177
- 'Video');
178
-
179
- // Communication
180
- ('Message',
181
- 'Messages',
182
- 'Call',
183
- 'Calling',
184
- 'Sms',
185
- 'Notification',
186
- 'NotificationBing');
187
-
188
- // Files
189
- ('Document', 'Folder', 'FolderOpen', 'Archive', 'CloudAdd', 'CloudDownload');
190
-
191
- // Commerce
192
- ('Bag',
193
- 'ShoppingBag',
194
- 'ShoppingCart',
195
- 'Wallet',
196
- 'Card',
197
- 'Tag',
198
- 'TicketDiscount');
199
-
200
- // User
201
- ('User', 'Profile', 'ProfileCircle', 'People', 'UserAdd', 'UserRemove');
202
-
203
- // Time
204
- ('Clock', 'Calendar', 'Timer', 'Alarm', 'Watch', 'TimeCircle');
205
-
206
- // Location
207
- ('Location', 'Map', 'Gps', 'DirectionRight', 'GlobalSearch', 'RouteSquare');
208
-
209
- // Security
210
- ('Lock', 'Unlock', 'Shield', 'ShieldTick', 'Eye', 'EyeSlash', 'Scan', 'Key');
211
- ```
212
-
213
- ## TypeScript Support
119
+ 994 names exist in both variants. Three do not:
214
120
 
215
- This library is built with TypeScript and provides full type safety. Icon names are validated based on the selected type:
121
+ | `filled` only | `outline` only |
122
+ | ----------------------- | ----------------------- |
123
+ | `ArrowPointCircleup` | `ArrowPointCircleUp` |
124
+ | `ArrowPointCircleRight` | `ArrowPointCircleright` |
125
+ | `FlashCircle` | `FlashCircle2` |
216
126
 
217
- ```tsx
218
- // Valid - 'Heart' exists in filled icons
219
- <SvgIcon type="filled" name="Heart" />
127
+ Anything that switches `type` on a fixed name — a focused tab icon, a
128
+ pressed-state toggle should avoid these six.
220
129
 
221
- // ✅ Valid - 'Heart' exists in outline icons
222
- <SvgIcon type="outline" name="Heart" />
130
+ ---
223
131
 
224
- // ❌ TypeScript Error - 'InvalidIcon' doesn't exist
225
- <SvgIcon type="filled" name="InvalidIcon" />
132
+ ## Props
133
+
134
+ | Prop | Type | Default | Description |
135
+ | ----------- | ------------------------------ | ----------- | ------------------------------------------------ |
136
+ | `type` | `'filled' \| 'outline'` | required | Variant, and the union `name` is checked against |
137
+ | `name` | `IconNameByType[T]` | required | Icon name |
138
+ | `size` | `number` | `24` | Width and height, normalised for the device |
139
+ | `color` | `string` | `'#292D32'` | `fill` on filled icons, `stroke` on outline |
140
+ | `svgProps` | `SvgProps` | – | Spread onto the `<Svg>` element |
141
+ | `pathProps` | `PathProps` | – | Spread onto every `<Path>` in the icon |
142
+ | `animate` | `AnimateSVGPathComponentProps` | – | See [Animation](#animation) |
143
+
144
+ Three details worth knowing before you reach for `svgProps` or `pathProps`:
145
+
146
+ - **`size` is normalised.** It runs through `normalize()` from
147
+ `@shaquillehinds/react-native-essentials`, which scales against device
148
+ dimensions. Treat `size` as a design-scale value rather than exact points, and
149
+ don't compute it from `Dimensions` yourself.
150
+ - **`pathProps` overrides `color`.** It is spread after the fill/stroke
151
+ attribute. Same for `svgProps` and `size` — `svgProps={{ width: 40 }}` wins.
152
+ Prefer `color` and `size`.
153
+ - **`pathProps` hits every path.** Outline icons are usually several paths. There
154
+ is no per-path styling through this API.
155
+
156
+ The default colour is `#292D32`, a near-black grey. If you need true black, pass
157
+ `color="#000"` explicitly.
226
158
 
227
- // Type-safe with generics
228
- function IconWrapper<T extends SvgIconType>(props: SvgIconProps<T>) {
229
- return <SvgIcon {...props} />;
230
- }
231
- ```
159
+ ---
232
160
 
233
- ## Animation
161
+ ## Filled vs outline
234
162
 
235
- The `animate` prop provides powerful, built-in animation capabilities for your icons. There are two animation modes available:
163
+ The two variants are drawn differently, which changes what you can override and
164
+ animate.
236
165
 
237
- ### Animation Modes
166
+ | | `filled` | `outline` |
167
+ | ------------ | -------- | --------------- |
168
+ | Paths | One | Usually several |
169
+ | Coloured via | `fill` | `stroke` |
170
+ | Stroke width | – | `1.5` |
171
+ | SVG `fill` | `none` | `none` |
238
172
 
239
- #### 1. InterpolatePathProps Mode
173
+ Consequences:
240
174
 
241
- This mode gives you fine-grained control by providing an `Animated.Value` that you can interpolate to create complex animations. Perfect for custom animations where you need full control over the interpolation.
175
+ - `pathProps={{ fill: 'red' }}` does nothing to an outline icon.
176
+ - `pathProps={{ stroke: 'red' }}` does nothing to a filled icon.
177
+ - Stroke and dash animations only make sense on `outline`; fill animations on
178
+ `filled`.
179
+ - Adjust outline weight with `pathProps={{ strokeWidth: 2 }}`.
242
180
 
243
- **Key Features:**
181
+ `color` targets the right attribute for the variant automatically — prefer it.
244
182
 
245
- - Direct access to the animated value for interpolation
246
- - Support for multiple animation stages
247
- - Full control over timing, spring animations, and easing
183
+ ---
248
184
 
249
- **Props:**
185
+ ## TypeScript
250
186
 
251
- - `mode`: `"InterpolatePathProps"`
252
- - `animationConfig`: Single or array of animation configs (timing/spring)
253
- - `pathProps`: Function that receives the animated value and returns path properties
254
- - `autoStart`: Auto-start animation on mount (default: false)
255
- - `returnToStart`: Return to initial state after animation (default: false)
256
- - `loop`: Number of times to loop (-1 for infinite, default: 0)
187
+ ```tsx
188
+ import type {
189
+ FilledIconName, // union of all filled names
190
+ OutlineIconName, // union of all outline names
191
+ IconName, // both
192
+ SvgIconType, // 'filled' | 'outline'
193
+ SvgIconProps, // component props, generic over type
194
+ SvgIcon as SvgIconBaseProps,
195
+ } from '@shaquillehinds/react-native-svg-icons';
196
+ ```
257
197
 
258
- **Example - Color and Stroke Animation:**
198
+ ### Annotate icon arrays
259
199
 
260
200
  ```tsx
261
- <SvgIcon
262
- name="FingerScan"
263
- type="outline"
264
- size={100}
265
- animate={{
266
- mode: 'InterpolatePathProps',
267
- autoStart: true,
268
- loop: -1,
269
- returnToStart: true,
270
- pathProps: (value, { inputRange }) => ({
271
- strokeLinejoin: 'miter',
272
- stroke: value.interpolate({
273
- inputRange,
274
- outputRange: ['red', 'green'],
275
- }),
276
- strokeDashoffset: value.interpolate({
277
- inputRange,
278
- outputRange: [36, 0],
279
- }),
280
- strokeDasharray: '35, 35',
281
- }),
282
- animationConfig: [
283
- {
284
- type: 'timing',
285
- duration: 1000,
286
- useNativeDriver: true,
287
- },
288
- ],
289
- }}
290
- />
201
+ const icons: OutlineIconName[] = [
202
+ 'House',
203
+ 'Airplane',
204
+ 'Bookmark',
205
+ 'RepeatCircle',
206
+ ];
291
207
  ```
292
208
 
293
- **Example - Multi-stage Animation:**
209
+ Without the annotation the array widens to `string[]` and every name in it stops
210
+ being checked — the most common way an invalid name reaches runtime.
211
+
212
+ ### Keep the generic in wrappers
294
213
 
295
214
  ```tsx
296
- <SvgIcon
297
- name="Heart"
298
- type="filled"
299
- size={80}
300
- animate={{
301
- mode: 'InterpolatePathProps',
302
- autoStart: true,
303
- loop: -1,
304
- pathProps: (value, { inputRange }) => ({
305
- fill: value.interpolate({
306
- inputRange,
307
- outputRange: ['#FF0000', '#FF69B4', '#FF1493', '#FF0000'],
308
- }),
309
- opacity: value.interpolate({
310
- inputRange,
311
- outputRange: [0.5, 1, 0.8, 0.5],
312
- }),
313
- }),
314
- animationConfig: [
315
- { type: 'timing', duration: 500, useNativeDriver: false },
316
- { type: 'timing', duration: 500, useNativeDriver: false },
317
- { type: 'timing', duration: 500, useNativeDriver: false },
318
- ],
319
- }}
320
- />
215
+ function Icon<T extends SvgIconType>(props: SvgIconProps<T>) {
216
+ return <SvgIcon {...props} />;
217
+ }
321
218
  ```
322
219
 
323
- #### 2. AnimatedPathProps Mode
220
+ Writing `props: SvgIconProps` collapses the union and lets an outline-only name
221
+ pass on `type="filled"`.
324
222
 
325
- This mode provides a simpler, declarative API where you specify which properties to animate and their values. The library handles the interpolation for you.
223
+ ---
224
+
225
+ ## Animation
326
226
 
327
- **Key Features:**
227
+ Every icon accepts an `animate` prop. Two modes, with different config shapes.
328
228
 
329
- - Declarative API - just specify from/to values
330
- - Animate multiple properties simultaneously or in sequence
331
- - Support for numeric and string values (colors, dash arrays, etc.)
229
+ Shared options, both modes:
332
230
 
333
- **Props:**
231
+ | Option | Type | Default | Description |
232
+ | --------------- | ----------------------------------------------- | -------- | --------------------------------- |
233
+ | `mode` | `'AnimatedPathProps' \| 'InterpolatePathProps'` | required | Selects the shape below |
234
+ | `autoStart` | `boolean` | `false` | Start on mount |
235
+ | `loop` | `number` | `0` | `-1` for infinite |
236
+ | `returnToStart` | `boolean` | `false` | Reverse back to the initial state |
237
+ | `ref` | `AnimateSVGComponentValueRef` | – | Imperative control |
334
238
 
335
- - `mode`: `"AnimatedPathProps"`
336
- - `config`: Animation configuration (timing/spring)
337
- - `animatedPathProps`: Array of properties to animate
338
- - `isSequence`: Animate properties in sequence vs parallel (default: false)
339
- - `autoStart`: Auto-start animation on mount (default: false)
340
- - `returnToStart`: Return to initial state after animation (default: false)
341
- - `loop`: Number of times to loop (-1 for infinite, default: 0)
239
+ ### `AnimatedPathProps` — declarative
342
240
 
343
- **Example - Parallel Animation:**
241
+ Specify what to animate and its values; interpolation is handled for you. Start
242
+ here.
344
243
 
345
244
  ```tsx
346
245
  <SvgIcon
347
- name="Scanning"
348
246
  type="outline"
247
+ name="Scanning"
349
248
  size={100}
350
249
  animate={{
351
250
  mode: 'AnimatedPathProps',
352
251
  autoStart: true,
353
252
  loop: -1,
354
253
  returnToStart: true,
355
- config: {
356
- type: 'timing',
357
- duration: 2000,
358
- useNativeDriver: false,
359
- },
254
+ isSequence: false,
255
+ config: { type: 'timing', duration: 2000, useNativeDriver: false },
360
256
  animatedPathProps: [
361
- {
362
- name: 'stroke',
363
- from: 'red',
364
- to: ['green', 'blue'],
365
- },
366
- {
367
- name: 'strokeDasharray',
368
- from: '18, 18',
369
- to: ['36, 36', '18, 18'],
370
- },
371
- {
372
- name: 'strokeDashoffset',
373
- from: 72,
374
- to: [18, 36],
375
- },
257
+ { name: 'stroke', from: 'red', to: ['green', 'blue'] },
258
+ { name: 'strokeDasharray', from: '18, 18', to: ['36, 36', '18, 18'] },
259
+ { name: 'strokeDashoffset', from: 72, to: [18, 36] },
376
260
  ],
377
261
  }}
378
262
  />
379
263
  ```
380
264
 
381
- **Example - Sequential Animation:**
265
+ | Option | Type | Description |
266
+ | ------------------- | ----------------------- | -------------------------------------------------- |
267
+ | `config` | timing or spring config | Single config for the whole animation |
268
+ | `animatedPathProps` | `{ name, from, to }[]` | Properties to animate; `to` is an array of stages |
269
+ | `isSequence` | `boolean` | Run properties in sequence rather than in parallel |
270
+
271
+ ### `InterpolatePathProps` — manual
272
+
273
+ Gives you the `Animated.Value` to interpolate yourself. Use when the declarative
274
+ form can't express what you need.
382
275
 
383
276
  ```tsx
384
277
  <SvgIcon
385
- name="Star"
386
- type="filled"
387
- size={60}
278
+ type="outline"
279
+ name="FingerScan"
280
+ size={100}
388
281
  animate={{
389
- mode: 'AnimatedPathProps',
390
- isSequence: true,
282
+ mode: 'InterpolatePathProps',
391
283
  autoStart: true,
392
284
  loop: -1,
393
- config: {
394
- type: 'spring',
395
- tension: 40,
396
- friction: 7,
397
- useNativeDriver: false,
398
- },
399
- animatedPathProps: [
400
- {
401
- name: 'fill',
402
- from: '#FFD700',
403
- to: ['#FFA500', '#FFD700'],
404
- },
405
- {
406
- name: 'opacity',
407
- from: 1,
408
- to: [0.5, 1],
409
- },
285
+ returnToStart: true,
286
+ pathProps: (value, { inputRange }) => ({
287
+ strokeLinejoin: 'miter',
288
+ stroke: value.interpolate({ inputRange, outputRange: ['red', 'green'] }),
289
+ strokeDashoffset: value.interpolate({ inputRange, outputRange: [36, 0] }),
290
+ strokeDasharray: '35, 35',
291
+ }),
292
+ animationConfig: [
293
+ { type: 'timing', duration: 1000, useNativeDriver: false },
410
294
  ],
411
295
  }}
412
296
  />
413
297
  ```
414
298
 
415
- ### Animation Configuration Types
299
+ | Option | Type | Description |
300
+ | ----------------- | -------------------------------------- | ------------------------------------------------------------ |
301
+ | `animationConfig` | config or config array | One entry per stage; `inputRange` is derived from the length |
302
+ | `pathProps` | `(value, { inputRange }) => PathProps` | Returns path props from the animated value |
416
303
 
417
- Both modes support two types of animation configs:
304
+ Note `animate.pathProps` (a function) is distinct from the top-level `pathProps`
305
+ prop (a static object). Both can be present; the top-level object is applied
306
+ first and the animated result merged over it.
418
307
 
419
- #### Timing Animation
308
+ ### Config shapes
420
309
 
421
310
  ```tsx
422
- {
423
- type: "timing",
424
- duration: 1000,
425
- delay?: 0,
426
- easing?: Easing.linear,
427
- useNativeDriver: true, // or false for color/transform animations
428
- }
311
+ { type: 'timing', duration: 1000, delay: 0, easing: Easing.linear, useNativeDriver: false }
312
+ { type: 'spring', tension: 40, friction: 7, speed: 12, bounciness: 8, useNativeDriver: false }
429
313
  ```
430
314
 
431
- #### Spring Animation
315
+ ### `useNativeDriver`
432
316
 
433
- ```tsx
434
- {
435
- type: "spring",
436
- tension?: 40,
437
- friction?: 7,
438
- speed?: 12,
439
- bounciness?: 8,
440
- useNativeDriver: true, // or false for color/transform animations
441
- }
442
- ```
317
+ Use `false` for `stroke`, `fill`, `opacity` and dash properties — which covers
318
+ most icon animation. `true` is only valid for transform-based animation. The
319
+ native driver cannot animate SVG path attributes, and getting this wrong fails
320
+ silently on one platform and throws on the other.
321
+
322
+ ### Animation applies to every path
443
323
 
444
- ### Controlling Animations with Refs
324
+ Multi-path outline icons animate in lockstep. There is no per-path targeting
325
+ through this API.
445
326
 
446
- You can control animations programmatically using refs:
327
+ ### Imperative control
447
328
 
448
329
  ```tsx
449
330
  import { useRef } from 'react';
450
331
  import type { AnimateSVGComponentValueRef } from '@shaquillehinds/react-native-essentials';
451
332
 
452
333
  function ControlledIcon() {
453
- const animationRef = useRef<AnimateSVGComponentValueRef>(null);
454
-
455
- const handleStart = () => animationRef.current?.start();
456
- const handleStop = () => animationRef.current?.stop();
457
- const handleReset = () => animationRef.current?.reset();
458
- const handleReverse = () => animationRef.current?.reverse();
334
+ const ref = useRef<AnimateSVGComponentValueRef>(null);
459
335
 
460
336
  return (
461
337
  <>
462
338
  <SvgIcon
463
- name="Play"
464
339
  type="filled"
340
+ name="Play"
465
341
  size={60}
466
342
  animate={{
467
- ref: animationRef,
343
+ ref,
468
344
  mode: 'InterpolatePathProps',
469
345
  autoStart: false,
470
346
  pathProps: (value) => ({
@@ -480,118 +356,45 @@ function ControlledIcon() {
480
356
  },
481
357
  }}
482
358
  />
483
- <Button title="Start" onPress={handleStart} />
484
- <Button title="Stop" onPress={handleStop} />
485
- <Button title="Reset" onPress={handleReset} />
486
- <Button title="Reverse" onPress={handleReverse} />
359
+ <Button title="Start" onPress={() => ref.current?.start()} />
360
+ <Button title="Stop" onPress={() => ref.current?.stop()} />
361
+ <Button title="Reset" onPress={() => ref.current?.reset()} />
362
+ <Button title="Reverse" onPress={() => ref.current?.reverse()} />
487
363
  </>
488
364
  );
489
365
  }
490
366
  ```
491
367
 
492
- ### Common Animation Patterns
368
+ The ref type is exported from `@shaquillehinds/react-native-essentials`.
493
369
 
494
- #### Pulsing Effect
495
-
496
- ```tsx
497
- <SvgIcon
498
- name="Notification"
499
- type="filled"
500
- size={40}
501
- animate={{
502
- mode: 'AnimatedPathProps',
503
- autoStart: true,
504
- loop: -1,
505
- returnToStart: true,
506
- config: { type: 'timing', duration: 1000, useNativeDriver: false },
507
- animatedPathProps: [{ name: 'opacity', from: 1, to: [0.3, 1] }],
508
- }}
509
- />
510
- ```
511
-
512
- #### Rotating Stroke Dash
370
+ ---
513
371
 
514
- ```tsx
515
- <SvgIcon
516
- name="Loading"
517
- type="outline"
518
- size={50}
519
- animate={{
520
- mode: 'AnimatedPathProps',
521
- autoStart: true,
522
- loop: -1,
523
- config: { type: 'timing', duration: 1500, useNativeDriver: false },
524
- animatedPathProps: [
525
- {
526
- name: 'strokeDashoffset',
527
- from: 0,
528
- to: [100],
529
- },
530
- ],
531
- }}
532
- />
533
- ```
372
+ ## Bundle size
534
373
 
535
- #### Color Wave
374
+ `SvgIcon` resolves names through a registry that statically imports all 1,994 icon
375
+ modules. Importing `SvgIcon` anywhere brings the full set into the bundle —
376
+ unused icons are not tree-shaken away.
536
377
 
537
- ```tsx
538
- <SvgIcon
539
- name="Wave"
540
- type="outline"
541
- size={80}
542
- animate={{
543
- mode: 'InterpolatePathProps',
544
- autoStart: true,
545
- loop: -1,
546
- pathProps: (value) => ({
547
- stroke: value.interpolate({
548
- inputRange: [0, 0.33, 0.66, 1],
549
- outputRange: ['#FF0000', '#00FF00', '#0000FF', '#FF0000'],
550
- }),
551
- }),
552
- animationConfig: [
553
- { type: 'timing', duration: 3000, useNativeDriver: false },
554
- ],
555
- }}
556
- />
557
- ```
378
+ In practice the icons are small path strings and the cost is modest, but plan for
379
+ it rather than assuming per-icon shaking. There are currently no per-icon entry
380
+ points; the package exports `SvgIcon` and the name types.
558
381
 
559
- ### Performance Notes
560
-
561
- - Set `useNativeDriver: true` when animating transform properties for better performance
562
- - Set `useNativeDriver: false` when animating colors, stroke properties, or opacity
563
- - For complex animations, consider using `InterpolatePathProps` mode for better control
564
- - Use `AnimatedPathProps` mode for simpler, declarative animations
382
+ ---
565
383
 
566
- ## Examples
384
+ ## Recipes
567
385
 
568
- ### Creating an Icon Button
386
+ ### Icon button
569
387
 
570
388
  ```tsx
571
- import { TouchableOpacity } from 'react-native';
572
- import { SvgIcon } from 'react-native-svg-icons';
573
-
574
- function IconButton({ onPress }: { onPress: () => void }) {
575
- return (
576
- <TouchableOpacity onPress={onPress}>
577
- <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />
578
- </TouchableOpacity>
579
- );
580
- }
389
+ <TouchableOpacity onPress={onPress}>
390
+ <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />
391
+ </TouchableOpacity>
581
392
  ```
582
393
 
583
- ### Tab Bar Icons
394
+ ### Tab bar
584
395
 
585
396
  ```tsx
586
- import { SvgIcon } from 'react-native-svg-icons';
587
-
588
- function TabBarIcon({
589
- focused,
590
- name,
591
- }: {
592
- focused: boolean;
593
- name: 'Home' | 'Search' | 'Profile';
594
- }) {
397
+ function TabBarIcon({ focused, name }: { focused: boolean; name: IconName }) {
595
398
  return (
596
399
  <SvgIcon
597
400
  type={focused ? 'filled' : 'outline'}
@@ -603,84 +406,137 @@ function TabBarIcon({
603
406
  }
604
407
  ```
605
408
 
606
- ### Dynamic Icon List
409
+ Only safe for names present in both variants.
410
+
411
+ ### Icon grid
607
412
 
608
413
  ```tsx
609
- import { View } from 'react-native';
610
- import { SvgIcon } from 'react-native-svg-icons';
611
- import type { FilledIconName } from 'react-native-svg-icons';
414
+ import type { FilledIconName } from '@shaquillehinds/react-native-svg-icons';
612
415
 
613
- function IconGrid() {
614
- const icons: FilledIconName[] = ['Heart', 'Star', 'User', 'Setting', 'Home'];
416
+ const icons: FilledIconName[] = ['Heart', 'Star', 'User', 'Setting', 'Home'];
615
417
 
616
- return (
617
- <View style={{ flexDirection: 'row', gap: 16 }}>
618
- {icons.map((icon) => (
619
- <SvgIcon key={icon} type="filled" name={icon} size={32} color="#000" />
620
- ))}
621
- </View>
622
- );
623
- }
418
+ <View style={{ flexDirection: 'row', gap: 16 }}>
419
+ {icons.map((icon) => (
420
+ <SvgIcon key={icon} type="filled" name={icon} size={32} color="#000" />
421
+ ))}
422
+ </View>;
624
423
  ```
625
424
 
626
- ### Animated Icons
627
-
628
- See the [Animation](#animation) section for comprehensive examples of animating icons with the built-in `animate` prop.
425
+ ### Pulse
629
426
 
630
- ## Performance Tips
427
+ ```tsx
428
+ <SvgIcon
429
+ type="filled"
430
+ name="Notification"
431
+ size={40}
432
+ animate={{
433
+ mode: 'AnimatedPathProps',
434
+ autoStart: true,
435
+ loop: -1,
436
+ returnToStart: true,
437
+ config: { type: 'timing', duration: 1000, useNativeDriver: false },
438
+ animatedPathProps: [{ name: 'opacity', from: 1, to: [0.3, 1] }],
439
+ }}
440
+ />
441
+ ```
631
442
 
632
- 1. **Avoid Inline Styles**: Define styles outside of render functions
633
- 2. **Memoize Icon Components**: Use `React.memo` for frequently re-rendered icons
634
- 3. **Use Appropriate Sizes**: Stick to common sizes (16, 20, 24, 32, 48) for better caching
635
- 4. **Tree Shaking**: Only imported icons are included in your bundle
443
+ ### Draw-on stroke
636
444
 
637
445
  ```tsx
638
- import { memo } from 'react';
639
- import { SvgIcon } from 'react-native-svg-icons';
446
+ <SvgIcon
447
+ type="outline"
448
+ name="TickCircle"
449
+ size={64}
450
+ animate={{
451
+ mode: 'AnimatedPathProps',
452
+ autoStart: true,
453
+ config: { type: 'timing', duration: 800, useNativeDriver: false },
454
+ animatedPathProps: [{ name: 'strokeDashoffset', from: 100, to: [0] }],
455
+ }}
456
+ />
457
+ ```
640
458
 
641
- const MemoizedIcon = memo(SvgIcon);
459
+ Pair with `pathProps={{ strokeDasharray: '100, 100' }}` to set the dash pattern.
642
460
 
643
- // Use MemoizedIcon for better performance
644
- <MemoizedIcon type="filled" name="Heart" size={24} color="#FF0000" />;
645
- ```
461
+ ---
646
462
 
647
463
  ## Troubleshooting
648
464
 
649
- ### Icons not displaying
465
+ **Nothing renders where an icon should be.** Almost always a bad name. An unknown
466
+ `type` or `name` logs through `console.error` and returns `null` — it does not
467
+ throw. Check the console, then verify with `npx rnsi-icons <fragment>`.
650
468
 
651
- 1. Ensure `react-native-svg` is properly installed and linked
652
- 2. For iOS, run `pod install` in the ios directory
653
- 3. Rebuild your app after installation
469
+ **TypeScript rejects a name that looks right.** Check the misspelling list, and
470
+ check whether the name exists in the variant you passed to `type`
471
+ (`npx rnsi-icons --diff`).
654
472
 
655
- ### TypeScript errors with icon names
473
+ **Icon renders at the wrong size.** `size` is normalised for the device, so it
474
+ won't match physical points exactly. Also check nothing is passing `width` or
475
+ `height` through `svgProps`, which overrides it.
656
476
 
657
- 1. Ensure you're using the correct icon name (check the available icons list)
658
- 2. Verify the icon exists for the specified type (`filled` or `outline`)
659
- 3. Update your TypeScript version if you see unexpected errors
477
+ **`color` has no effect.** Something in `pathProps` is overriding it it is
478
+ spread last. Also check you aren't setting `fill` on an outline icon or `stroke`
479
+ on a filled one.
660
480
 
661
- ### Size or color not applying
481
+ **Animation doesn't run.** `autoStart` defaults to `false`. If it is set, check
482
+ `useNativeDriver` is `false` for colour, stroke, opacity and dash animation.
662
483
 
663
- 1. Verify you're passing valid numeric values for `size`
664
- 2. Ensure color values are valid CSS color strings
665
- 3. Check if parent components are overriding styles
484
+ **Animation config is ignored.** The two modes use different keys —
485
+ `AnimatedPathProps` takes `config` and `animatedPathProps`, `InterpolatePathProps`
486
+ takes `animationConfig` and a `pathProps` function. Mixing them silently drops
487
+ the unrecognised half.
666
488
 
667
- ## Contributing
489
+ **Icons missing entirely after install.** Confirm `react-native-svg` is linked,
490
+ run `pod install` on iOS, and rebuild — a Metro reload is not enough for a new
491
+ native dependency.
668
492
 
669
- Contributions are welcome! Please ensure:
493
+ ---
670
494
 
671
- - Icons follow the existing naming convention
672
- - Both filled and outline variants are provided
673
- - Types are auto-generated using the provided scripts
674
- - Examples are updated if adding new categories
495
+ ## AI agent rules
496
+
497
+ The package ships a rules file written for AI coding agents (Claude Code, Cursor,
498
+ Codex, Copilot, etc.) at `rules/AGENT_RULES.md`. It tells an agent to verify every
499
+ icon name against the shipped type union instead of guessing one, spells out the
500
+ misspelled names and variant mismatches it would otherwise "correct", and
501
+ documents both animation modes so it cannot mix their config keys. Point your
502
+ agent at it with any of the following.
503
+
504
+ **Copy it into your project (recommended)**
505
+
506
+ ```sh
507
+ npx rnsi-rules # writes ./AGENTS.md
508
+ npx rnsi-rules cursor # writes ./.cursor/rules/react-native-svg-icons.mdc (alwaysApply)
509
+ npx rnsi-rules claude # writes ./.claude/rules/react-native-svg-icons.md
510
+ npx rnsi-rules codex # writes ./.codex/rules/react-native-svg-icons.md
511
+ npx rnsi-rules copilot # writes ./.github/instructions/react-native-svg-icons.instructions.md
512
+ npx rnsi-rules windsurf # writes ./.windsurf/rules/react-native-svg-icons.md
513
+ npx rnsi-rules docs/ai/svg-icons.md # custom path
514
+ ```
675
515
 
676
- ## License
516
+ Add `--force` to overwrite an existing file. `--print` writes the rules to stdout
517
+ instead of to disk. Re-run after upgrading the package to pick up rule changes.
677
518
 
678
- MIT
519
+ **Reference it without copying (Claude Code)**
520
+
521
+ `CLAUDE.md` supports `@path` imports, so a single line keeps the rules in sync with
522
+ the installed version:
523
+
524
+ ```md
525
+ # CLAUDE.md
679
526
 
680
- ## Credits
527
+ @node_modules/@shaquillehinds/react-native-svg-icons/rules/AGENT_RULES.md
528
+ ```
529
+
530
+ **Reference it from a generic `AGENTS.md`**
681
531
 
682
- Icons curated and optimized for React Native. Built with TypeScript and `react-native-svg`.
532
+ ```md
533
+ Before using any icon, read and follow
534
+ node_modules/@shaquillehinds/react-native-svg-icons/rules/AGENT_RULES.md.
535
+ Never guess an icon name — verify it with `npx rnsi-icons <query>`.
536
+ ```
683
537
 
684
538
  ---
685
539
 
686
- **Made with ❤️ for the React Native community**
540
+ ## License
541
+
542
+ MIT