@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.
@@ -0,0 +1,353 @@
1
+ # Agent Rules — `@shaquillehinds/react-native-svg-icons`
2
+
3
+ Rules for AI coding agents writing or modifying code that uses this package.
4
+ Read this before rendering any icon.
5
+
6
+ The failure mode with an icon library is inventing names. This set has 997 icons
7
+ per variant with irregular, sometimes misspelled names. A plausible guess is
8
+ usually wrong, and a wrong name does not throw — it logs and renders nothing.
9
+ Rule 1 exists to stop that.
10
+
11
+ ---
12
+
13
+ ## 0. Non-negotiables
14
+
15
+ 1. **Never guess an icon name.** Verify it against the shipped type union before
16
+ you write it. See Rule 1.
17
+ 2. `type` is required and selects the name union. `filled` and `outline` are not
18
+ fully interchangeable — 3 names differ between them.
19
+ 3. Do not add `react-native-svg` `<Svg>` / `<Path>` around an icon. `SvgIcon`
20
+ renders a complete SVG.
21
+ 4. If a prop is not listed in this file, it does not exist.
22
+
23
+ ---
24
+
25
+ ## 1. Never guess an icon name
26
+
27
+ There is no `Search`, no `Delete`, no `Loading`, no `Bitcoin`, no `Home` outline
28
+ mismatch to rely on. Names come from a fixed generated union and include
29
+ misspellings that were baked in and must be reproduced exactly.
30
+
31
+ ### Verify first
32
+
33
+ ```sh
34
+ npx rnsi-icons search # fuzzy search both variants
35
+ npx rnsi-icons search --type outline
36
+ npx rnsi-icons Trash --exact # confirm one name
37
+ npx rnsi-icons --list > icons.txt
38
+ ```
39
+
40
+ Without the CLI, grep the shipped union directly:
41
+
42
+ ```sh
43
+ grep -oE "'[A-Za-z0-9]*Search[A-Za-z0-9]*'" \
44
+ node_modules/@shaquillehinds/react-native-svg-icons/src/svgs/types.ts | sort -u
45
+ ```
46
+
47
+ TypeScript will also reject an invalid name at compile time. Use that — do not
48
+ cast, do not widen to `string`, do not `as FilledIconName`. A type error here is
49
+ the system working.
50
+
51
+ ### Names that do not exist, and what to use instead
52
+
53
+ These are the ones models reach for most:
54
+
55
+ | Guess | Reality |
56
+ | --------------------- | ------------------------------------------------------------------ |
57
+ | `Search` | `SearchNormal`, `SearchNormal1`, `SearchStatus`, `SearchZoomIn` |
58
+ | `Delete` | `Trash` |
59
+ | `Loading` / `Spinner` | `Refresh`, `RotateRight`, `RotateLeft` |
60
+ | `Bitcoin` | `BitcoinBtc`, `BitcoinCard`, `BitcoinConvert` |
61
+ | `Ethereum` | grep — crypto icons use a `NameTicker` form (`AaveAave`, `ZelZel`) |
62
+ | `Warning` | `Warning2` — there is no `Warning` |
63
+ | `Info` | `InfoCircle` or `Information` |
64
+ | `Close` | `CloseCircle` or `CloseSquare` — no bare `Close` |
65
+ | `Check` / `Checkmark` | `Check`, `TickCircle`, `TickSquare` |
66
+
67
+ ### Misspellings that are load-bearing
68
+
69
+ These are the real, correct names. Spelling them properly breaks the build:
70
+
71
+ | Correct (use this) | Natural but wrong |
72
+ | --------------------------------------------------- | ----------------- |
73
+ | `MinusCirlce` | `MinusCircle` |
74
+ | `UserCirlceAdd` | `UserCircleAdd` |
75
+ | `SendSqaure2` | `SendSquare2` |
76
+ | `MonitorMobbile` | `MonitorMobile` |
77
+ | `Battery3full` | `Battery3Full` |
78
+ | `BrifecaseCross`, `BrifecaseTick`, `BrifecaseTimer` | `Briefcase*` |
79
+
80
+ Note `Briefcase` itself is spelled correctly while its compounds are not. Do not
81
+ normalise these. Do not "fix" one you encounter in existing code.
82
+
83
+ ### Other naming quirks
84
+
85
+ - Numeric suffixes are variants, not sizes: `Home`, `Home1`, `Home2`,
86
+ `HomeHashtag` are four different icons.
87
+ - A few names start lowercase or with a digit: `square`, `dcube`, `dRotate`,
88
+ `dSquare`, `dCubeScan`, `4Support`.
89
+ - `4Support` is the registry key; its file is `FourSupport.tsx`. Use the key.
90
+
91
+ ### Variant mismatches
92
+
93
+ 994 of 997 names exist in both variants. These three do not — check before
94
+ swapping `type`:
95
+
96
+ | `filled` only | `outline` only |
97
+ | ----------------------- | ----------------------- |
98
+ | `ArrowPointCircleup` | `ArrowPointCircleUp` |
99
+ | `ArrowPointCircleRight` | `ArrowPointCircleright` |
100
+ | `FlashCircle` | `FlashCircle2` |
101
+
102
+ Code that flips `type` on a variable name (a focused tab bar icon, for instance)
103
+ must use a name outside this list.
104
+
105
+ ---
106
+
107
+ ## 2. Basic usage
108
+
109
+ ```tsx
110
+ import { SvgIcon } from '@shaquillehinds/react-native-svg-icons';
111
+
112
+ <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />
113
+ <SvgIcon type="outline" name="SearchNormal" size={20} color="#8E8E93" />
114
+ ```
115
+
116
+ `type` and `name` are required. `size` defaults to 24, `color` defaults to
117
+ `#292D32` (a near-black grey — **not** pure black; set `color` explicitly if you
118
+ need `#000`).
119
+
120
+ ### Size is normalised
121
+
122
+ `size` is passed through `normalize()` from `@shaquillehinds/react-native-essentials`,
123
+ which scales to device dimensions. `size={24}` is a design-scale value, not a
124
+ guaranteed 24 physical points. Do not compensate by hand, and do not compute an
125
+ icon size from `Dimensions` — pass the design value.
126
+
127
+ ### `filled` vs `outline` are structurally different
128
+
129
+ - **filled** — one path, coloured with `fill`. No stroke.
130
+ - **outline** — usually several paths, coloured with `stroke` at
131
+ `strokeWidth="1.5"`, with `fill="none"` on the SVG.
132
+
133
+ This matters when overriding: `pathProps={{ fill: 'red' }}` does nothing to an
134
+ outline icon, and `pathProps={{ stroke: 'red' }}` does nothing to a filled one.
135
+ Prefer `color`, which targets the right attribute automatically.
136
+
137
+ ---
138
+
139
+ ## 3. Props
140
+
141
+ | Prop | Type | Default | Notes |
142
+ | ----------- | ------------------------------ | ----------- | ----------------------------------------------------- |
143
+ | `type` | `'filled' \| 'outline'` | required | Selects the `name` union |
144
+ | `name` | `IconNameByType[T]` | required | Verify it — see Rule 1 |
145
+ | `size` | `number` | `24` | Normalised; sets width and height |
146
+ | `color` | `string` | `'#292D32'` | `fill` on filled, `stroke` on outline |
147
+ | `svgProps` | `SvgProps` | – | Spread onto `<Svg>`, after `width`/`height`/`viewBox` |
148
+ | `pathProps` | `PathProps` | – | Spread onto **every** `<Path>`, after `color` |
149
+ | `animate` | `AnimateSVGPathComponentProps` | – | See Rule 4 |
150
+
151
+ Two ordering facts that decide behaviour:
152
+
153
+ - `pathProps` is spread **after** the colour attribute, so it wins over `color`.
154
+ - `svgProps` is spread after `width`/`height`/`viewBox`, so `svgProps={{ width: 40 }}`
155
+ overrides `size`. Use `size`; do not set dimensions through `svgProps`.
156
+ - `pathProps` applies to _every_ path in the icon. On a multi-path outline icon
157
+ you cannot style one path differently through this API.
158
+
159
+ ### Type-safe wrappers
160
+
161
+ ```tsx
162
+ import type {
163
+ SvgIconProps,
164
+ SvgIconType,
165
+ } from '@shaquillehinds/react-native-svg-icons';
166
+
167
+ function Icon<T extends SvgIconType>(props: SvgIconProps<T>) {
168
+ return <SvgIcon {...props} />;
169
+ }
170
+ ```
171
+
172
+ Keep the generic. Writing `props: SvgIconProps` collapses the union and lets an
173
+ outline-only name through on `type="filled"`.
174
+
175
+ ### Typing icon arrays
176
+
177
+ ```tsx
178
+ import type { OutlineIconName } from '@shaquillehinds/react-native-svg-icons';
179
+
180
+ const icons: OutlineIconName[] = [
181
+ 'House',
182
+ 'Airplane',
183
+ 'Bookmark',
184
+ 'RepeatCircle',
185
+ ];
186
+ ```
187
+
188
+ Always annotate. An unannotated array widens to `string[]` and every name in it
189
+ stops being checked — which is exactly how invented names reach production.
190
+
191
+ ---
192
+
193
+ ## 4. Animation
194
+
195
+ Two modes, set by `animate.mode`. They do not share a config shape; do not mix
196
+ their keys.
197
+
198
+ ### `AnimatedPathProps` — declarative
199
+
200
+ Use this by default.
201
+
202
+ ```tsx
203
+ <SvgIcon
204
+ type="outline"
205
+ name="Scanning"
206
+ size={100}
207
+ animate={{
208
+ mode: 'AnimatedPathProps',
209
+ autoStart: true,
210
+ loop: -1,
211
+ returnToStart: true,
212
+ isSequence: false,
213
+ config: { type: 'timing', duration: 2000, useNativeDriver: false },
214
+ animatedPathProps: [
215
+ { name: 'stroke', from: 'red', to: ['green', 'blue'] },
216
+ { name: 'strokeDashoffset', from: 72, to: [18, 36] },
217
+ ],
218
+ }}
219
+ />
220
+ ```
221
+
222
+ Keys: `config` (singular), `animatedPathProps`, `isSequence`.
223
+
224
+ ### `InterpolatePathProps` — manual
225
+
226
+ Use when you need interpolation the declarative form cannot express.
227
+
228
+ ```tsx
229
+ animate={{
230
+ mode: 'InterpolatePathProps',
231
+ autoStart: true,
232
+ loop: -1,
233
+ returnToStart: true,
234
+ pathProps: (value, { inputRange }) => ({
235
+ stroke: value.interpolate({ inputRange, outputRange: ['red', 'green'] }),
236
+ strokeDasharray: '35, 35',
237
+ }),
238
+ animationConfig: [{ type: 'timing', duration: 1000, useNativeDriver: true }],
239
+ }}
240
+ ```
241
+
242
+ Keys: `animationConfig` (array, one entry per stage), `pathProps` as a **function**.
243
+
244
+ Note `pathProps` means something different here from the top-level `pathProps`
245
+ prop. Inside `animate`, it is a function of the animated value. At the top level
246
+ it is a static object. Both can be present.
247
+
248
+ ### Rules for both modes
249
+
250
+ - Shared keys: `autoStart` (default `false`), `loop` (`-1` for infinite,
251
+ default `0`), `returnToStart` (default `false`), `ref`.
252
+ - `useNativeDriver: false` for anything animating `stroke`, `fill`, `opacity`, or
253
+ dash properties — which is most icon animation. `true` only for transforms.
254
+ Getting this wrong fails silently or throws at runtime depending on platform.
255
+ - The animation applies to **every path** in the icon. Multi-path outline icons
256
+ animate in lockstep; there is no per-path control.
257
+ - Match the mode to the variant: stroke and dash animations need `type="outline"`,
258
+ fill animations need `type="filled"`.
259
+
260
+ ### Imperative control
261
+
262
+ ```tsx
263
+ import type { AnimateSVGComponentValueRef } from '@shaquillehinds/react-native-essentials';
264
+
265
+ const ref = useRef<AnimateSVGComponentValueRef>(null);
266
+
267
+ <SvgIcon
268
+ type="filled"
269
+ name="Play"
270
+ animate={{ ref, autoStart: false /* ... */ }}
271
+ />;
272
+
273
+ ref.current?.start();
274
+ ref.current?.stop();
275
+ ref.current?.reset();
276
+ ref.current?.reverse();
277
+ ```
278
+
279
+ The ref type comes from `@shaquillehinds/react-native-essentials`, not this package.
280
+
281
+ ---
282
+
283
+ ## 5. Bundle size
284
+
285
+ `SvgIcon` resolves names through a registry that statically imports all 1,994 icon
286
+ modules. Importing `SvgIcon` anywhere pulls the whole set into the bundle.
287
+
288
+ - Do not claim or assume tree shaking removes unused icons. It does not.
289
+ - Do not build a "lighter" wrapper that maps a few names to `SvgIcon` — the
290
+ registry is already loaded.
291
+ - If a screen needs exactly one icon and bundle size is the concern, that is a
292
+ package-level change (deep exports), not something to work around in app code.
293
+ Raise it rather than inventing an import path that is not exported.
294
+
295
+ The package exports `SvgIcon` (named and default) and the name types. There are no
296
+ per-icon entry points.
297
+
298
+ ---
299
+
300
+ ## 6. Missing icons fail quietly
301
+
302
+ An unknown `type` or `name` logs via `console.error` and returns `null`. Nothing
303
+ throws, nothing renders, layout collapses where the icon should be.
304
+
305
+ So a blank space where an icon should be is almost always a bad name, not a
306
+ styling problem. Check the name before adjusting layout.
307
+
308
+ ---
309
+
310
+ ## 7. Common patterns
311
+
312
+ ### Tab bar
313
+
314
+ ```tsx
315
+ function TabIcon({ focused, name }: { focused: boolean; name: IconName }) {
316
+ return (
317
+ <SvgIcon
318
+ type={focused ? 'filled' : 'outline'}
319
+ name={name}
320
+ size={24}
321
+ color={focused ? '#007AFF' : '#8E8E93'}
322
+ />
323
+ );
324
+ }
325
+ ```
326
+
327
+ Only safe for names present in both variants — see the mismatch table in Rule 1.
328
+
329
+ ### Icon button
330
+
331
+ ```tsx
332
+ <TouchableOpacity onPress={onPress}>
333
+ <SvgIcon type="filled" name="Heart" size={24} color="#FF0000" />
334
+ </TouchableOpacity>
335
+ ```
336
+
337
+ Do not wrap in an extra `<View>` for sizing; `size` handles it.
338
+
339
+ ---
340
+
341
+ ## 8. Review checklist
342
+
343
+ - [ ] Every icon name verified against the type union, not guessed
344
+ - [ ] Misspelled names reproduced exactly (`MinusCirlce`, `SendSqaure2`, …)
345
+ - [ ] Icon name arrays annotated with `FilledIconName` / `OutlineIconName`
346
+ - [ ] No `as` cast or `string` widening on a `name`
347
+ - [ ] Names that flip between variants checked against the 3 mismatches
348
+ - [ ] `color` used rather than `pathProps` fill/stroke overrides
349
+ - [ ] `size` used rather than `svgProps` width/height
350
+ - [ ] `useNativeDriver: false` for colour, stroke, opacity and dash animation
351
+ - [ ] Animation mode keys not mixed (`config` vs `animationConfig`)
352
+ - [ ] Stroke animations on `outline`, fill animations on `filled`
353
+ - [ ] No claim that unused icons are tree-shaken away