@robosophy/ui-vue 1.2.0 → 1.2.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/AGENTS.md +42 -40
- package/README.md +235 -235
- package/ai-context.md +56 -56
- package/components.md +468 -468
- package/dist/components/RsSidebar/RsSidebar.vue.d.ts.map +1 -1
- package/dist/index.css +535 -535
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +30 -31
- package/dist/vite.js.map +1 -1
- package/icon-scanner.md +388 -388
- package/package.json +72 -71
package/icon-scanner.md
CHANGED
|
@@ -1,388 +1,388 @@
|
|
|
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 |
|
|
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 |
|