@robosophy/ui-vue 1.1.12 → 1.1.13

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/icon-scanner.md CHANGED
@@ -1,293 +1,388 @@
1
- # Icon Scanner — @robosophy/ui-vue
2
-
3
- ## Overview
4
-
5
- The Vite plugin `robosophyMaterialSymbols()` automatically detects which Material Symbols
6
- icons are used in source code and generates an SVG sprite with only those icons.
7
- No fonts are loaded.
8
-
9
- The scanner works at **build time** (and in dev mode via file watching).
10
- It scans every `.vue`, `.ts`, `.tsx`, `.js`, `.jsx`, and `.mjs` file in the project's `src/` directory
11
- (or custom `roots`), extracts icon names, families, and weights, then downloads the matching SVGs
12
- from the Google Material Design Icons repository.
13
-
14
- When the package is built (`npm run build`), a **pre-scan** (the manifest script in
15
- `scripts/generate-icon-manifest.mjs`) identifies icons used by the library's own components
16
- (`RsSidebar`, `RsAccountSelector`, etc.) and writes them to `dist/icon-manifest.json`.
17
- The Vite plugin loads this manifest at dev/build time as a baseline, then adds icons found
18
- by scanning the consuming project's source.
19
-
20
- ---
21
-
22
- ## Detection Patterns
23
-
24
- The scanner uses five patterns to find icon usage in source code.
25
- Patterns 4 and 5 were added for cases that the original three could not handle.
26
-
27
- ### Pattern 1: `<RsIcon>` Component Tag
28
-
29
- **Regex:** `/ <RsIcon\b([^>]*)>/g`
30
-
31
- Parses the attributes with `parseStaticAttributes` and reads `name`, `:name`, `family`,
32
- `:family`, `weight`, `:weight`.
33
-
34
- **Detected:**
35
- ```vue
36
- <RsIcon name="home" />
37
- <RsIcon name="home" family="rounded" />
38
- <RsIcon :name="cond ? 'home' : 'settings'" family="rounded" />
39
- <RsIcon name="home" weight="200" />
40
- ```
41
-
42
- **Not detected** (variable references):
43
- ```vue
44
- <RsIcon :name="iconVar" />
45
- <RsIcon :name="item.icon" />
46
- ```
47
-
48
- **Filter:** icon names must match `/^[a-z0-9_]+$/` (lowercase with underscores).
49
-
50
- **Dynamic `:name` with ternaries:** any string literal inside the `:name` expression
51
- is extracted. For example `:name="cond ? 'add' : 'remove'"` extracts both `add` and `remove`.
52
-
53
- **Dynamic `:name` without string literals:** if the binding is a plain variable reference
54
- like `:name="current_icon"`, the scanner no longer treats it as an icon name
55
- (improvement 3, see changelog). Use `include` or magic comments for these cases.
56
-
57
- ### Pattern 2: `rsPrimeIcon()` Helper
58
-
59
- **Regex:** `/\brsPrimeIcon\(\s*["']([a-z0-9_]+)["'](?:\s*,\s*\{([^)]*)\})?/g`
60
-
61
- **Detected:**
62
- ```ts
63
- rsPrimeIcon("home")
64
- rsPrimeIcon('settings', { family: 'rounded' })
65
- ```
66
-
67
- **Not detected:**
68
- ```ts
69
- rsPrimeIcon(dynamicName)
70
- ```
71
-
72
- ### Pattern 3: Object Literal `icon:` Property
73
-
74
- **Regex:** `/\bicon\s*:\s*["']([a-z0-9_]+)["']/g`
75
-
76
- After matching, the scanner finds the enclosing `{...}` object and extracts `weight` and
77
- `family` from its body (using `findEnclosingObject`). Comments are stripped from the body
78
- before searching for these properties.
79
-
80
- **Detected:**
81
- ```ts
82
- const items = [
83
- { label: "Inbox", icon: "inbox" },
84
- { label: "Settings", icon: "settings", family: "rounded", weight: 200 },
85
- ];
86
- ```
87
-
88
- **Not detected** (no `icon:` string literal):
89
- ```ts
90
- const items = [{ icon: dynamicVar }]; // variable reference
91
- { icon } // shorthand property
92
- { ["icon"]: "home" } // computed property
93
- ```
94
-
95
- **`findEnclosingObject` behavior:**
96
- - Scans backward from the `icon:` match to find the nearest opening `{`
97
- - Skips over strings, template literals, escaped quotes, and comments (`//` and `/* */`)
98
- - Scans forward to find the matching `}`
99
- - Returns the body content between `{` and `}`
100
- - The body is then cleaned of comments before searching for `weight:` and `family:`
101
-
102
- ```ts
103
- // This correctly reads weight=200 and family="rounded":
104
- { icon: "home", weight: 200, family: "rounded" }
105
-
106
- // Comments are ignored:
107
- { /* weight: 200, family: "rounded" */ icon: "home" }
108
- // → default weight 400, default family "outlined"
109
- ```
110
-
111
- ### Pattern 4: Magic Comments
112
-
113
- **Regex:** `/\/\/\s*@robosophy-icon:\s*([a-z0-9_]+)(?:\s+family=(\w+))?(?:\s+weight=(\d+))?/g`
114
-
115
- For cases where the scanner cannot detect an icon statically (props, variables, API responses,
116
- computed properties), use magic comments to declare them explicitly.
117
-
118
- **Usage:**
119
- ```ts
120
- // @robosophy-icon: home
121
- // @robosophy-icon: settings family=rounded
122
- // @robosophy-icon: warning weight=200
123
- // @robosophy-icon: manage_accounts family=rounded weight=200
124
-
125
- const sidebarItems = [
126
- { id: "home", label: "Home", icon: "home" },
127
- { id: "settings", label: "Settings", icon: "settings" },
128
- ];
129
- ```
130
-
131
- **Best for:**
132
- - Icon names passed as props to parent components
133
- - Icon names in constants, enums, or configuration objects
134
- - Icon names from API responses
135
- - Icon names in computed properties or functions
136
-
137
- **Placement:** anywhere in the source file. The scanner reads the entire file content.
138
-
139
- ### Pattern 5: Arrays of Icon Strings
140
-
141
- **Regex:** `/\/\/\s*@robosophy-icon:\s*([a-z0-9_]+)(?:\s+family=(\w+))?(?:\s+weight=(\d+))?/g`
142
-
143
- Wait, that's the same as Pattern 4. Let me check the actual regex I used...
144
-
145
- Actually, Pattern 5 detects arrays assigned to variables whose name contains "icon" (case-insensitive).
146
-
147
- **Regex:** `/(?:const|let|var)\s+(\w*[Ii]con\w*)\s*=\s*\[/g`
148
-
149
- After finding the start of an icon array, it extracts all string literals from the brackets.
150
-
151
- **Detected:**
152
- ```ts
153
- const iconNames = ["home", "settings", "info"];
154
- const sidebarIcons = ["home", "search"];
155
- const ICON_LIST = ["warning", "error"];
156
- ```
157
-
158
- **Not detected** (no "icon" in variable name):
159
- ```ts
160
- const names = ["home", "settings"]; // variable name doesn't contain "icon"
161
- const items = [{ icon: "home" }]; // already handled by Pattern 3
162
- ```
163
-
164
- **Caveat:** This pattern uses a heuristic (variable name contains "icon"). It may miss icons
165
- stored in arrays with unrelated names. Use magic comments for those.
166
-
167
- ---
168
-
169
- ## Plugin Options
170
-
171
- | Option | Type | Default | Description |
172
- |--------|------|---------|-------------|
173
- | `include` | `IconInput[]` | `[]` | Icons to include regardless of detection. Each entry is a string (name) or `{ family, name, weight? }`. If weight is omitted, all valid weights (100-700) are included. |
174
- | `scan` | `boolean` | `true` | Set to `false` to disable source scanning entirely. All icons must be in `include`. |
175
- | `roots` | `string[]` | `["./src"]` | Directories to scan for icon usage. |
176
- | `outputDir` | `string` | `"assets"` | Output directory for the SVG sprite. |
177
- | `fontDisplay` | `string` | — | CSS `font-display` value. |
178
- | `preload` | `boolean` | `false` | Preload the SVG sprite in the `<head>`. |
179
-
180
- ---
181
-
182
- ## `icon-manifest.json`
183
-
184
- The build script (`scripts/generate-icon-manifest.mjs`) scans the library's own components
185
- under `src/components/` and produces `dist/icon-manifest.json`.
186
-
187
- **File format:**
188
- ```json
189
- {
190
- "outlined": ["home", "search", "settings"],
191
- "rounded": ["settings"],
192
- "sharp": []
193
- }
194
- ```
195
-
196
- **Role in the pipeline:**
197
- 1. Build generates the manifest from the library's component source
198
- 2. Vite plugin loads the manifest as a baseline
199
- 3. Plugin then scans the consuming project's source for additional icons
200
- 4. Plugin fetches SVGs for the combined set
201
-
202
- **Why not just use the manifest alone?**
203
- The manifest ensures that icons required by library components are always available,
204
- even if the consuming project doesn't use those components. However, the manifest may
205
- include icons that the consumer never uses (it's a conservative baseline). The plugin's
206
- source scan adds only the icons that the consumer's own code references.
207
-
208
- ---
209
-
210
- ## Known Limitations
211
-
212
- ### Icon names passed as props
213
-
214
- ```vue
215
- <!-- RsSidebar uses :name="icon" which is a prop -->
216
- <RsIcon :name="icon" />
217
-
218
- <!-- RsSidebar uses :name="item.icon" from v-for iteration -->
219
- <RsIcon :name="item.icon" />
220
- ```
221
-
222
- The scanner cannot resolve the runtime value of `icon` or `item.icon`.
223
-
224
- **Solutions:**
225
- 1. Use `include` in the Vite plugin config
226
- 2. Add magic comments (`// @robosophy-icon: icon_name`) in the component file
227
- 3. Declare the icon in the same file as the data source (Pattern 3 will detect it)
228
-
229
- ### Icon names in arrays of strings
230
-
231
- ```ts
232
- const iconNames = ["home", "settings"];
233
- ```
234
-
235
- Pattern 5 detects these only if the variable name contains "icon".
236
-
237
- ### Icon names in enums or constants
238
-
239
- ```ts
240
- export enum Icons {
241
- HOME = "home",
242
- SETTINGS = "settings",
243
- }
244
- ```
245
-
246
- Not detected. Use magic comments or `include`.
247
-
248
- ### Icon names from API responses
249
-
250
- ```ts
251
- const config = await fetchConfig();
252
- return <RsIcon :name="config.iconName" />;
253
- ```
254
-
255
- Cannot be detected statically. Use `include` or magic comments.
256
-
257
- ---
258
-
259
- ## Best Practices
260
-
261
- ### For AI agents editing consuming projects
262
-
263
- 1. **Static icons:** use `<RsIcon name="icon_name" />` — always detected by Pattern 1
264
- 2. **Object configs:** use `{ icon: "icon_name" }` — detected by Pattern 3
265
- 3. **Dynamic icons:** use magic comments or `include`
266
- 4. **PrimeVue buttons:** use `rsPrimeIcon('icon_name')` — detected by Pattern 2
267
- 5. **Props to RsSidebar:** icons in the `items` array objects are detected by Pattern 3
268
-
269
- ### For humans
270
-
271
- When adding a new icon to the codebase:
272
- 1. Check if it's statically detectable (direct string literal)
273
- 2. If not, add a magic comment near the usage
274
- 3. If the icon is used in many places, add it to the plugin config's `include`
275
-
276
- ### Tag helper
277
-
278
- To quickly test if an icon name exists in the Material Symbols set:
279
-
280
- ```
281
- https://fonts.google.com/icons?icon.query=icon_name
282
- ```
283
-
284
- ---
285
-
286
- ## Changelog
287
-
288
- | Date | Change |
289
- |------|--------|
290
- | 2026-07-13 | **Pattern 4** (magic comments) and **Pattern 5** (icon arrays) added |
291
- | 2026-07-13 | `findEnclosingObject`: now handles comments, escaped quotes, and template literals |
292
- | 2026-07-13 | `resolveNames`: dynamic `:name` bindings no longer fall back to treating variable names as icon names |
293
- | 2026-07-13 | Pattern 3: weight and family are now extracted from the enclosing object literal |
1
+ # Icon Scanner — @robosophy/ui-vue
2
+
3
+ ## Overview
4
+
5
+ `robosophyMaterialSymbols()` es un plugin de Vite que genera un sprite SVG con solo los
6
+ iconos de **Material Symbols** que tu codigo realmente usa. Sin fuentes tipograficas,
7
+ sin subset fonts, sin dependencias npm.
8
+
9
+ **Pipeline:**
10
+
11
+ ```
12
+ source code → scan (8 patterns) → merge with manifest → download SVGs → inline SVG sprite
13
+ ```
14
+
15
+ El scanner opera en **build time** y en **dev mode** (con file watching). Escanea archivos
16
+ `.vue`, `.ts`, `.tsx`, `.js`, `.jsx`, y `.mjs` del proyecto, extrae nombres de icono,
17
+ familias y pesos, y descarga los SVGs correspondientes del repositorio oficial de Google.
18
+
19
+ Los iconos que usan los componentes internos de la libreria (`RsSidebar`, `RsAccountSelector`,
20
+ etc.) se precargan en `dist/icon-manifest.json` durante el build del paquete y se fusionan
21
+ con los detectados en el proyecto consumidor.
22
+
23
+ ---
24
+
25
+ ## Quick Reference
26
+
27
+ | # | Pattern | Categoria | Detecta | Ejemplo |
28
+ |---|---------|-----------|---------|---------|
29
+ | 1 | `<RsIcon>` tag | Componente | `name` estatico + ternarias | `<RsIcon name="home" />` |
30
+ | 2 | `rsPrimeIcon()` | Componente | String literal en helper | `rsPrimeIcon("home")` |
31
+ | 3 | `icon:` property | Dato | Objeto con `icon:` key | `{ icon: "home" }` |
32
+ | 5 | Icon arrays | Dato | Array en variable `*icon*` | `const iconNames = ["home"]` |
33
+ | 5b | Icon objects | Dato | Objeto en variable `*icon*` | `const iconMap = { pc: "article" }` |
34
+ | 6a | Component icon prop | Cross-file | `icon=` en tag PascalCase | `<CustomButton icon="home" />` |
35
+ | 6b | Proxy components | Cross-file | Prop forwarding a `<RsIcon :name>` | `<ProxyIcon icon="home" />` |
36
+ | 4 | Magic comments | Fallback | Declaracion explicita | `// @robosophy-icon: home` |
37
+
38
+ ---
39
+
40
+ ## Automatic Detection
41
+
42
+ Estos 7 patrones se activan solos. No requieren configuracion manual, solo codigo fuente
43
+ donde los nombres de icono aparezcan como **string literals**.
44
+
45
+ ### Component Patterns
46
+
47
+ #### Pattern 1: `<RsIcon>` tag
48
+
49
+ **Regex:** `/ <RsIcon\b([\s\S]*?)>/g`
50
+
51
+ Detecta usos directos del componente `<RsIcon>` con `name` estatico, ternarias en `:name`,
52
+ template literals, y tags multi-linea. Soporta `family`, `:family`, `weight`, `:weight`.
53
+
54
+ **Detectado:**
55
+ ```vue
56
+ <RsIcon name="home" />
57
+ <RsIcon name="home" family="rounded" />
58
+ <RsIcon :name="cond ? 'home' : 'settings'" family="rounded" weight="200" />
59
+ <RsIcon
60
+ name="home"
61
+ family="rounded"
62
+ />
63
+ <RsIcon :name="`home`" />
64
+ ```
65
+
66
+ **No detectado** (variables en `:name`):
67
+ ```vue
68
+ <RsIcon :name="iconVar" />
69
+ <RsIcon :name="item.icon" />
70
+ <RsIcon v-for="name in list" :name="name" />
71
+ ```
72
+
73
+ > 💡 Si el binding tiene ternarias con string literals, ambas ramas se extraen.
74
+ > Si es solo una variable (`:name="iconProp"`), usa Pattern 3 en la fuente de datos
75
+ > o Magic Comments como ultimo recurso.
76
+
77
+ ---
78
+
79
+ #### Pattern 2: `rsPrimeIcon()` helper
80
+
81
+ **Regex:** `/\brsPrimeIcon\(\s*["'`]([a-z0-9_]+)["'`](?:\s*,\s*\{([^)]*)\})?/g`
82
+
83
+ Detecta el helper que PrimeVue usa como string de clases para `Button.icon`,
84
+ `MenuItem.icon`, etc. Soporta `family` opcional.
85
+
86
+ **Detectado:**
87
+ ```ts
88
+ rsPrimeIcon("home")
89
+ rsPrimeIcon('settings', { family: 'rounded' })
90
+ rsPrimeIcon(`home`)
91
+ ```
92
+
93
+ **No detectado:**
94
+ ```ts
95
+ rsPrimeIcon(variableName)
96
+ ```
97
+
98
+ ---
99
+
100
+ ### Data Patterns
101
+
102
+ #### Pattern 3: `icon:` property
103
+
104
+ **Regex:** `/\bicon\s*:\s*["'`]([a-z0-9_]+)["'`]/g`
105
+
106
+ Detecta objetos con una propiedad `icon:` y extrae `weight:` y `family:` del mismo objeto.
107
+ Usa `findEnclosingObject` para encontrar los limites del objeto, ignorando comentarios,
108
+ strings escapados y template literals.
109
+
110
+ **Detectado:**
111
+ ```ts
112
+ const items = [
113
+ { label: "Inbox", icon: "inbox" },
114
+ { label: "Settings", icon: "settings", family: "rounded", weight: 200 },
115
+ { icon: `home` },
116
+ ]
117
+ ```
118
+
119
+ **No detectado:**
120
+ ```ts
121
+ { icon: dynamicVar } // variable reference
122
+ { icon } // shorthand property
123
+ { ["icon"]: "home" } // computed property key
124
+ ```
125
+
126
+ > 💡 Pattern 3 es la forma mas comun de declarar iconos en datos de navegacion.
127
+ > RsSidebar recibe `items` con `icon:` — se detecta automaticamente.
128
+
129
+ ---
130
+
131
+ #### Pattern 5: Icon arrays
132
+
133
+ **Regex:** `/(?:const|let|var)\s+(\w*[Ii]con\w*)\s*=\s*\[/g`
134
+
135
+ Detecta arrays asignados a variables cuyo nombre contiene "icon" (case-insensitive).
136
+ Extrae strings del nivel superior del array, incluyendo arrays anidados y template literals.
137
+
138
+ **Detectado:**
139
+ ```ts
140
+ const iconNames = ["home", "settings", "info"]
141
+ const sidebarIcons = ["home", "search"]
142
+ const ICON_LIST = ["warning", "error"]
143
+ ```
144
+
145
+ ```ts
146
+ // Arrays anidados
147
+ const iconGroups = [
148
+ ["home", "settings"], // ✅ detectados
149
+ "search" // ✅ detectado
150
+ ]
151
+ ```
152
+
153
+ **No detectado:**
154
+ ```ts
155
+ const names = ["home", "settings"] // sin "icon" en nombre
156
+ const items = [{ icon: "home" }] // Pattern 3 lo cubre
157
+ ```
158
+
159
+ ---
160
+
161
+ #### Pattern 5b: Icon objects
162
+
163
+ **Regex:** `/(?:const|let|var)\s+(\w*[Ii]con\w*)[^=]*=\s*\{/g`
164
+
165
+ Detecta objetos literales asignados a variables con "icon" en el nombre y extrae todos
166
+ los string values que matchean el patron de nombre de icono. Soporta anotaciones de tipo
167
+ TypeScript (`: Record<K, V>`) y TypeScript generics con `<>`.
168
+
169
+ **Detectado:**
170
+ ```ts
171
+ const variantIconMap: Record<string, string> = {
172
+ pc: "article",
173
+ alta: "account_circle",
174
+ cc: "account_balance_wallet",
175
+ cyo: "nest_eco_leaf",
176
+ }
177
+ ```
178
+
179
+ ```ts
180
+ const iconConfig = {
181
+ default: "home",
182
+ active: "settings",
183
+ }
184
+ ```
185
+
186
+ **No detectado:**
187
+ ```ts
188
+ const names = { key: "article" } // sin "icon" en nombre
189
+ ```
190
+
191
+ > 💡 Pattern 5b fue creado especificamente para `variantIconMap` en RsSidebar,
192
+ > donde las claves son nombres de variante y los valores son iconos.
193
+
194
+ ---
195
+
196
+ ### Cross-file Patterns
197
+
198
+ #### Pattern 6a: Component icon prop
199
+
200
+ **Regex:** `/<([A-Z][a-zA-Z0-9_]*)\b([\s\S]*?)>/g`
201
+
202
+ Detecta el atributo `icon`, `iconName` o `icon-name` en cualquier tag PascalCase
203
+ (excepto `<RsIcon>` que usa `name`). Funciona sin analisis cross-file.
204
+
205
+ **Detectado:**
206
+ ```vue
207
+ <CustomButton icon="home" />
208
+ <AnotherComponent iconName="settings" />
209
+ <ThirdThing icon-name="search" />
210
+ ```
211
+
212
+ **No detectado:**
213
+ ```vue
214
+ <RsIcon icon="home" /> <!-- RsIcon usa name, no icon -->
215
+ <CustomButton :icon="var" /> <!-- dynamic binding -->
216
+ ```
217
+
218
+ > 💡 Este patron es util cuando un componente expone un prop `icon` y el valor
219
+ > se pasa como string literal en el template del consumidor.
220
+
221
+ ---
222
+
223
+ #### Pattern 6b: Proxy components
224
+
225
+ **Analisis en dos fases:**
226
+
227
+ 1. **Fase 1** — Encuentra componentes que hacen forwarding de un prop a `<RsIcon>`:
228
+ - Tienen `defineProps` con al menos un prop
229
+ - Tienen `<RsIcon :name="propName">` donde `propName` es un prop
230
+ - Tienen `defineOptions({ name: "ComponentName" })`
231
+ 2. **Fase 2** — Escanea los consumos de esos componentes y extrae valores del prop `icon`
232
+
233
+ **Detectado:**
234
+
235
+ Componente (`CustomIconButton.vue`):
236
+ ```vue
237
+ <script setup lang="ts">
238
+ defineOptions({ name: "CustomIconButton" })
239
+ defineProps<{ icon: string }>()
240
+ </script>
241
+ <template>
242
+ <RsIcon :name="icon" />
243
+ </template>
244
+ ```
245
+
246
+ Consumo (`App.vue`):
247
+ ```vue
248
+ <CustomIconButton icon="home" /> <!-- ✅ detectado -->
249
+ <CustomIconButton icon="settings" /> <!-- ✅ detectado -->
250
+ ```
251
+
252
+ **No detectado:**
253
+ - Componentes sin `defineProps`
254
+ - Componentes sin `defineOptions({ name: ... })`
255
+ - Props que no se pasan a `<RsIcon :name="prop">`
256
+ - Bindings dinamicos (`:icon="variable"`)
257
+
258
+ ---
259
+
260
+ ## Manual Fallbacks
261
+
262
+ Cuando ningun patron automatico detecta tu icono (ej: viene de una API, de un enum,
263
+ o de una variable calculada), tenes dos opciones. **Usalas solo cuando los patrones
264
+ automaticos no alcancen.**
265
+
266
+ ### Magic comments (Pattern 4)
267
+
268
+ **Regex:** `/(?:\/\/|\/\*)\s*@robosophy-icon:\s*([a-z0-9_]+)/g`
269
+
270
+ Declara el icono explicitamente en el mismo archivo donde se usa:
271
+
272
+ ```ts
273
+ // @robosophy-icon: manage_accounts
274
+ const item = { icon: props.iconName }
275
+ ```
276
+
277
+ Soporta `family=` y `weight=` opcionales en la misma linea:
278
+
279
+ ```ts
280
+ // @robosophy-icon: settings family=rounded weight=200
281
+ ```
282
+
283
+ ### `include` (plugin config)
284
+
285
+ Para iconos usados en muchos lugares o controlados por configuracion remota:
286
+
287
+ ```ts
288
+ robosophyMaterialSymbols({
289
+ include: [
290
+ "home",
291
+ { family: "rounded", name: "settings", weight: 200 },
292
+ ],
293
+ })
294
+ ```
295
+
296
+ Si se omite `weight`, se incluyen todos los pesos validos (100-700).
297
+
298
+ ---
299
+
300
+ ## Plugin Options
301
+
302
+ | Option | Type | Default | Description |
303
+ |--------|------|---------|-------------|
304
+ | `include` | `IconInput[]` | `[]` | Iconos forzados. String = nombre, objeto = `{ family?, name, weight? }` |
305
+ | `scan` | `boolean` | `true` | `false` desactiva el escaneo. Todos los iconos deben ir en `include` |
306
+ | `roots` | `string[]` | `["./src"]` | Directorios a escanear |
307
+ | `outputDir` | `string` | `"assets"` | Directorio de salida del sprite SVG |
308
+ | `fontDisplay` | `string` | — | CSS `font-display` |
309
+ | `preload` | `boolean` | `false` | Precarga el sprite en el `<head>` |
310
+
311
+ ---
312
+
313
+ ## `icon-manifest.json`
314
+
315
+ Generado por `scripts/generate-icon-manifest.mjs` durante el build del paquete.
316
+ Escanea `src/components/` y produce `dist/icon-manifest.json`.
317
+
318
+ ```json
319
+ {
320
+ "outlined": ["home", "search", "settings"],
321
+ "rounded": ["settings"],
322
+ "sharp": []
323
+ }
324
+ ```
325
+
326
+ **Rol en el pipeline:**
327
+ 1. Build genera el manifiesto desde los componentes de la libreria
328
+ 2. Plugin de Vite carga el manifiesto como baseline
329
+ 3. Plugin escanea el proyecto consumidor para iconos adicionales
330
+ 4. Plugin descarga los SVGs del set combinado
331
+
332
+ El manifiesto asegura que los iconos de `RsSidebar`, `RsAccountSelector`, etc. esten
333
+ siempre disponibles, incluso si el proyecto consumidor no usa esos componentes.
334
+
335
+ ---
336
+
337
+ ## Best Practices
338
+
339
+ ### Para escribir codigo que se detecta solo
340
+
341
+ 1. **Usa `<RsIcon name="home" />`** — siempre detectado por Pattern 1
342
+ 2. **Declara iconos en objetos con `icon:`** — Pattern 3 extrae automaticamente
343
+ 3. **Nombra variables con "icon"** cuando almacenes nombres de icono — Patterns 5 y 5b se activan
344
+ 4. **Pasa iconos como string literal** a componentes con prop `icon` — Pattern 6a lo detecta
345
+ 5. **Usa `rsPrimeIcon("home")`** para PrimeVue — Pattern 2 lo cubre
346
+
347
+ ### Para componentes que envuelven RsIcon
348
+
349
+ Si creas un componente que recibe un icono por prop y lo pasa a `<RsIcon :name>`:
350
+
351
+ - Usa `defineProps` con el nombre del prop tipado
352
+ - Usa `defineOptions({ name: "ComponentName" })` para registrar el nombre
353
+ - Pattern 6b lo detectara automaticamente
354
+
355
+ Ejemplo:
356
+ ```vue
357
+ <script setup lang="ts">
358
+ defineOptions({ name: "MyIconButton" })
359
+ defineProps<{ icon: string }>()
360
+ </script>
361
+ <template>
362
+ <button><RsIcon :name="icon" /></button>
363
+ </template>
364
+ ```
365
+
366
+ ### Cuando nada funciona
367
+
368
+ Usa magic comments o `include` — pero considera si podes reescribir el codigo para
369
+ que el scanner lo detecte automaticamente. Es menos mantenimiento a futuro.
370
+
371
+ ### Testing de nombres
372
+
373
+ ```
374
+ https://fonts.google.com/icons?icon.query=icon_name
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Changelog
380
+
381
+ | Date | Change |
382
+ |------|--------|
383
+ | 2026-07-17 | Documentacion reestructurada: 8 patrones agrupados por categoria, automaticos primero |
384
+ | 2026-07-17 | **Pattern 5b** (icon objects), **Pattern 6a** (component icon prop), **Pattern 6b** (proxy components) added |
385
+ | 2026-07-13 | **Pattern 4** (magic comments) and **Pattern 5** (icon arrays) added |
386
+ | 2026-07-13 | `findEnclosingObject`: ahora maneja comentarios, strings escapados y template literals |
387
+ | 2026-07-13 | `resolveNames`: bindings `:name` dinamicos ya no tratan nombres de variable como iconos |
388
+ | 2026-07-13 | Pattern 3: weight y family se extraen del objeto contenedor |