siesa-ui-kit 1.0.5 → 1.0.6

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.
Files changed (198) hide show
  1. package/dist/index.cjs +1479 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.js +1479 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +23 -14
  6. package/claude/agents/siesa-ui-kit-specialist.md +0 -2401
  7. package/claude/prompts/component-template.md +0 -121
  8. package/claude/settings.local.json +0 -61
  9. package/docs/border-radius.md +0 -1261
  10. package/docs/colors.md +0 -832
  11. package/docs/dark-mode-guide.md +0 -1426
  12. package/docs/filters.md +0 -1243
  13. package/docs/icons.md +0 -1283
  14. package/docs/shadows.md +0 -1377
  15. package/docs/spacing.md +0 -1684
  16. package/docs/typography.md +0 -1268
  17. package/postcss.config.cjs +0 -6
  18. package/src/App.css +0 -42
  19. package/src/App.tsx +0 -8
  20. package/src/ButtonTest.tsx +0 -147
  21. package/src/assets/fonts/README.md +0 -261
  22. package/src/assets/fonts/SiesaBT/SiesaBT-Bold.otf +0 -0
  23. package/src/assets/fonts/SiesaBT/SiesaBT-Light.otf +0 -0
  24. package/src/assets/fonts/SiesaBT/SiesaBT-Regular.otf +0 -0
  25. package/src/assets/react.svg +0 -1
  26. package/src/components/Alert/Alert.stories.tsx +0 -332
  27. package/src/components/Alert/Alert.tsx +0 -106
  28. package/src/components/Alert/Alert.types.ts +0 -54
  29. package/src/components/Avatar/Avatar.stories.tsx +0 -494
  30. package/src/components/Avatar/Avatar.tsx +0 -143
  31. package/src/components/Avatar/Avatar.types.ts +0 -53
  32. package/src/components/Badge/Badge.stories.tsx +0 -339
  33. package/src/components/Badge/Badge.tsx +0 -278
  34. package/src/components/Badge/Badge.types.ts +0 -58
  35. package/src/components/Button/Button.stories.tsx +0 -950
  36. package/src/components/Button/Button.tsx +0 -337
  37. package/src/components/Button/Button.types.ts +0 -180
  38. package/src/components/Button/icons.tsx +0 -87
  39. package/src/components/Button/index.ts +0 -3
  40. package/src/components/Checkbox/Checkbox.stories.tsx +0 -453
  41. package/src/components/Checkbox/Checkbox.tsx +0 -208
  42. package/src/components/Checkbox/Checkbox.types.ts +0 -61
  43. package/src/components/DescriptionList/DescriptionList.stories.tsx +0 -250
  44. package/src/components/DescriptionList/DescriptionList.tsx +0 -96
  45. package/src/components/DescriptionList/DescriptionList.types.ts +0 -29
  46. package/src/components/Divider/Divider.stories.tsx +0 -263
  47. package/src/components/Divider/Divider.tsx +0 -80
  48. package/src/components/Divider/Divider.types.ts +0 -24
  49. package/src/components/Dropdown/Dropdown.stories.tsx +0 -552
  50. package/src/components/Dropdown/Dropdown.tsx +0 -422
  51. package/src/components/Dropdown/Dropdown.types.ts +0 -146
  52. package/src/components/Dropdown/README.md +0 -266
  53. package/src/components/Dropdown/icons.tsx +0 -72
  54. package/src/components/Dropdown/index.ts +0 -8
  55. package/src/components/Input/Input.stories.tsx +0 -583
  56. package/src/components/Input/Input.tsx +0 -204
  57. package/src/components/Input/Input.types.ts +0 -80
  58. package/src/components/Input/icons.tsx +0 -145
  59. package/src/components/Input/index.ts +0 -2
  60. package/src/components/LoginView/LoginView.stories.tsx +0 -148
  61. package/src/components/LoginView/LoginView.tsx +0 -426
  62. package/src/components/LoginView/LoginView.types.ts +0 -52
  63. package/src/components/LoginView/README.md +0 -396
  64. package/src/components/LoginView/icons.tsx +0 -85
  65. package/src/components/LoginView/index.ts +0 -3
  66. package/src/components/Navbar/Navbar.stories.tsx +0 -810
  67. package/src/components/Navbar/Navbar.tsx +0 -755
  68. package/src/components/Navbar/Navbar.types.ts +0 -219
  69. package/src/components/Navbar/README.md +0 -279
  70. package/src/components/Navbar/icons.tsx +0 -102
  71. package/src/components/Navbar/index.ts +0 -8
  72. package/src/components/NavigationBar/NavigationBar.stories.tsx +0 -406
  73. package/src/components/NavigationBar/NavigationBar.tsx +0 -246
  74. package/src/components/NavigationBar/NavigationBar.types.ts +0 -74
  75. package/src/components/NavigationBar/README.md +0 -469
  76. package/src/components/NavigationBar/index.ts +0 -2
  77. package/src/components/NavigationRail/NavigationRail.stories.tsx +0 -417
  78. package/src/components/NavigationRail/NavigationRail.tsx +0 -418
  79. package/src/components/NavigationRail/NavigationRail.types.ts +0 -109
  80. package/src/components/NavigationRail/README.md +0 -224
  81. package/src/components/NavigationRail/index.ts +0 -2
  82. package/src/components/Notification/Notification.stories.tsx +0 -513
  83. package/src/components/Notification/Notification.tsx +0 -145
  84. package/src/components/Notification/Notification.types.ts +0 -142
  85. package/src/components/Notification/README.md +0 -409
  86. package/src/components/Notification/index.ts +0 -3
  87. package/src/components/POSConvention/POSConvention.stories.tsx +0 -235
  88. package/src/components/POSConvention/POSConvention.tsx +0 -129
  89. package/src/components/POSConvention/POSConvention.types.ts +0 -38
  90. package/src/components/POSConvention/README.md +0 -123
  91. package/src/components/POSConvention/icons.tsx +0 -45
  92. package/src/components/POSConvention/index.ts +0 -3
  93. package/src/components/POSLocationButton/POSLocationButton.stories.tsx +0 -531
  94. package/src/components/POSLocationButton/POSLocationButton.tsx +0 -247
  95. package/src/components/POSLocationButton/POSLocationButton.types.ts +0 -87
  96. package/src/components/POSLocationButton/README.md +0 -253
  97. package/src/components/POSLocationButton/icons.tsx +0 -120
  98. package/src/components/POSLocationButton/index.ts +0 -14
  99. package/src/components/POSNumberButton/POSNumberButton.stories.tsx +0 -415
  100. package/src/components/POSNumberButton/POSNumberButton.tsx +0 -179
  101. package/src/components/POSNumberButton/POSNumberButton.types.ts +0 -51
  102. package/src/components/POSNumberButton/README.md +0 -321
  103. package/src/components/POSNumberButton/index.ts +0 -3
  104. package/src/components/POSProductButton/POSProductButton.stories.tsx +0 -318
  105. package/src/components/POSProductButton/POSProductButton.tsx +0 -152
  106. package/src/components/POSProductButton/POSProductButton.types.ts +0 -46
  107. package/src/components/POSProductButton/README.md +0 -269
  108. package/src/components/POSProductButton/index.ts +0 -2
  109. package/src/components/POSProductCard/POSProductCard.stories.tsx +0 -642
  110. package/src/components/POSProductCard/POSProductCard.tsx +0 -208
  111. package/src/components/POSProductCard/POSProductCard.types.ts +0 -76
  112. package/src/components/POSProductCard/README.md +0 -179
  113. package/src/components/POSProductCard/icons.tsx +0 -26
  114. package/src/components/POSProductCard/index.ts +0 -2
  115. package/src/components/POSProductSidebarItems/POSProductSidebarItems.stories.tsx +0 -753
  116. package/src/components/POSProductSidebarItems/POSProductSidebarItems.tsx +0 -332
  117. package/src/components/POSProductSidebarItems/POSProductSidebarItems.types.ts +0 -119
  118. package/src/components/POSProductSidebarItems/README.md +0 -198
  119. package/src/components/POSProductSidebarItems/icons.tsx +0 -21
  120. package/src/components/POSProductSidebarItems/index.ts +0 -3
  121. package/src/components/POSTable/POSTable.stories.tsx +0 -737
  122. package/src/components/POSTable/POSTable.tsx +0 -401
  123. package/src/components/POSTable/POSTable.types.ts +0 -83
  124. package/src/components/POSTable/README.md +0 -286
  125. package/src/components/POSTable/index.ts +0 -7
  126. package/src/components/Pagination/Pagination.stories.tsx +0 -555
  127. package/src/components/Pagination/Pagination.tsx +0 -286
  128. package/src/components/Pagination/Pagination.types.ts +0 -93
  129. package/src/components/Pagination/README.md +0 -298
  130. package/src/components/Pagination/icons.tsx +0 -47
  131. package/src/components/Pagination/index.ts +0 -3
  132. package/src/components/Quantity/Quantity.stories.tsx +0 -457
  133. package/src/components/Quantity/Quantity.tsx +0 -289
  134. package/src/components/Quantity/Quantity.types.ts +0 -70
  135. package/src/components/Radio/Radio.stories.tsx +0 -523
  136. package/src/components/Radio/Radio.tsx +0 -170
  137. package/src/components/Radio/Radio.types.ts +0 -122
  138. package/src/components/Select/README.md +0 -299
  139. package/src/components/Select/Select.stories.tsx +0 -673
  140. package/src/components/Select/Select.tsx +0 -454
  141. package/src/components/Select/Select.types.ts +0 -148
  142. package/src/components/Select/icons.tsx +0 -50
  143. package/src/components/Select/index.ts +0 -3
  144. package/src/components/SignUpView/SignUpView.stories.tsx +0 -129
  145. package/src/components/SignUpView/SignUpView.tsx +0 -503
  146. package/src/components/SignUpView/SignUpView.types.ts +0 -58
  147. package/src/components/SignUpView/icons.tsx +0 -71
  148. package/src/components/SignUpView/index.ts +0 -3
  149. package/src/components/Switch/README.md +0 -112
  150. package/src/components/Switch/Switch.stories.tsx +0 -550
  151. package/src/components/Switch/Switch.tsx +0 -246
  152. package/src/components/Switch/Switch.types.ts +0 -67
  153. package/src/components/Table/README.md +0 -369
  154. package/src/components/Table/Table.stories.tsx +0 -805
  155. package/src/components/Table/Table.tsx +0 -688
  156. package/src/components/Table/Table.types.ts +0 -204
  157. package/src/components/Table/index.ts +0 -9
  158. package/src/components/Tabs/README.md +0 -201
  159. package/src/components/Tabs/Tabs.stories.tsx +0 -580
  160. package/src/components/Tabs/Tabs.tsx +0 -356
  161. package/src/components/Tabs/Tabs.types.ts +0 -127
  162. package/src/components/Tabs/icons.tsx +0 -129
  163. package/src/components/Tabs/index.ts +0 -11
  164. package/src/components/Textarea/Textarea.stories.tsx +0 -535
  165. package/src/components/Textarea/Textarea.tsx +0 -188
  166. package/src/components/Textarea/Textarea.types.ts +0 -54
  167. package/src/context/ThemeContext.tsx +0 -99
  168. package/src/context/index.ts +0 -1
  169. package/src/index.css +0 -29
  170. package/src/index.ts +0 -39
  171. package/src/main.tsx +0 -10
  172. package/src/views/ProductsView/ProductsView.stories.tsx +0 -344
  173. package/src/views/ProductsView/ProductsView.tsx +0 -480
  174. package/src/views/ProductsView/ProductsView.types.ts +0 -238
  175. package/src/views/ProductsView/README.md +0 -312
  176. package/src/views/ProductsView/icons.tsx +0 -38
  177. package/src/views/ProductsView/index.ts +0 -8
  178. package/src/views/RecoverPasswordView/README.md +0 -269
  179. package/src/views/RecoverPasswordView/RecoverPasswordView.stories.tsx +0 -131
  180. package/src/views/RecoverPasswordView/RecoverPasswordView.tsx +0 -376
  181. package/src/views/RecoverPasswordView/RecoverPasswordView.types.ts +0 -56
  182. package/src/views/RecoverPasswordView/icons.tsx +0 -17
  183. package/src/views/RecoverPasswordView/index.ts +0 -2
  184. package/src/views/TableLayoutView/README.md +0 -268
  185. package/src/views/TableLayoutView/TableLayoutView.stories.tsx +0 -235
  186. package/src/views/TableLayoutView/TableLayoutView.tsx +0 -461
  187. package/src/views/TableLayoutView/TableLayoutView.types.ts +0 -209
  188. package/src/views/TableLayoutView/icons.tsx +0 -113
  189. package/src/views/TableLayoutView/index.ts +0 -6
  190. package/storybook/main.ts +0 -20
  191. package/storybook/preview.tsx +0 -84
  192. package/storybook/vitest.setup.ts +0 -7
  193. package/tailwind.config.js +0 -128
  194. /package/{public → dist}/,Business Logo.png +0 -0
  195. /package/{public → dist}/.Siesa Logo.png +0 -0
  196. /package/{public → dist}/bg_siesa.png +0 -0
  197. /package/{public → dist}/siesa_logo_mobile.png +0 -0
  198. /package/{public → dist}/vite.svg +0 -0
package/docs/icons.md DELETED
@@ -1,1283 +0,0 @@
1
- # Sistema de Iconos - Siesa UI Kit
2
-
3
- ## 📋 Tabla de Contenidos
4
-
5
- 1. [Introducción](#introducción)
6
- 2. [Librería de Iconos](#librería-de-iconos)
7
- 3. [Catálogo de Iconos](#catálogo-de-iconos)
8
- 4. [Implementación](#implementación)
9
- 5. [Guía de Uso](#guía-de-uso)
10
- 6. [Accesibilidad](#accesibilidad)
11
- 7. [Ejemplos de Código](#ejemplos-de-código)
12
- 8. [Mejores Prácticas](#mejores-prácticas)
13
- 9. [Referencia Rápida](#referencia-rápida)
14
-
15
- ---
16
-
17
- ## Introducción
18
-
19
- El sistema de iconos de Siesa UI Kit está basado en **Heroicons Micro**, una librería de iconos SVG de 16x16px diseñada específicamente para interfaces de usuario modernas. Los iconos están optimizados para claridad a tamaños pequeños y se integran perfectamente con nuestro sistema de diseño.
20
-
21
- ### Objetivos del Sistema de Iconos
22
-
23
- - **Consistencia Visual**: Todos los iconos mantienen el mismo peso visual y estilo
24
- - **Escalabilidad**: Iconos vectoriales que se adaptan a cualquier tamaño
25
- - **Accesibilidad**: Soporte para lectores de pantalla y temas oscuros
26
- - **Rendimiento**: SVG inline para carga rápida sin requests adicionales
27
- - **Flexibilidad**: Fácil personalización de tamaño, color y estilos
28
-
29
- ### Principios de Diseño
30
-
31
- 1. **Simplicidad**: Formas claras y reconocibles
32
- 2. **Peso Consistente**: Todos los iconos tienen el mismo grosor de línea
33
- 3. **Alineación Pixel-Perfect**: Optimizados para 16x16px
34
- 4. **Color Heredado**: Usan `currentColor` para adaptarse al contexto
35
-
36
- ---
37
-
38
- ## Librería de Iconos
39
-
40
- ### Heroicons Micro
41
-
42
- **Especificaciones Técnicas:**
43
- - **Tamaño Base**: 16x16px (viewBox="0 0 16 16")
44
- - **Formato**: SVG inline
45
- - **Estilo**: Solid (relleno completo)
46
- - **Grosor**: 1.5px stroke weight equivalent
47
- - **Licencia**: MIT License
48
-
49
- **Ventajas:**
50
- - ✅ Diseñados específicamente para UI de 16px
51
- - ✅ Optimizados para claridad a tamaños pequeños
52
- - ✅ Mantenidos por el equipo de Tailwind CSS
53
- - ✅ Biblioteca completa y consistente
54
- - ✅ Excelente legibilidad en pantallas de alta densidad
55
-
56
- ---
57
-
58
- ## Catálogo de Iconos
59
-
60
- ### Iconos de Botón (Button)
61
-
62
- Iconos disponibles en `src/components/Button/icons.tsx`
63
-
64
- | Icono | Nombre | Uso Principal | Ubicación |
65
- |-------|--------|---------------|-----------|
66
- | ➕ | `PlusIcon` | Acciones de añadir/crear | Button.tsx:12 |
67
- | 🔽 | `ChevronDownIcon` | Menús desplegables | Button.tsx:12 |
68
- | ➡️ | `ArrowRightIcon` | Navegación/siguiente | Button.tsx:12 |
69
- | ✓ | `CheckIcon` | Confirmación/éxito | Button.tsx:14 |
70
- | ✕ | `XIcon` | Cerrar/cancelar | Button.tsx:14 |
71
-
72
- ### Iconos de Input (Input)
73
-
74
- Iconos disponibles en `src/components/Input/icons.tsx`
75
-
76
- | Icono | Nombre | Uso Principal | Contexto |
77
- |-------|--------|---------------|----------|
78
- | ✉️ | `EnvelopeIcon` | Email input | Campo de correo electrónico |
79
- | ❓ | `QuestionMarkCircleIcon` | Ayuda contextual | Tooltips, hints |
80
- | 👤 | `UserIcon` | Usuario/perfil | Campos de nombre, login |
81
- | 🔒 | `LockClosedIcon` | Seguridad | Password, campos privados |
82
- | 🔍 | `MagnifyingGlassIcon` | Búsqueda | Search inputs |
83
- | 👁️ | `EyeIcon` | Ver contraseña | Toggle password visibility |
84
- | 👁️‍🗨️ | `EyeSlashIcon` | Ocultar contraseña | Toggle password visibility |
85
- | ✕ | `XMarkIcon` | Limpiar campo | Clear input |
86
- | ✓ | `CheckIcon` | Validación exitosa | Estado de éxito |
87
- | ⚠️ | `ExclamationCircleIcon` | Error/advertencia | Estado de error |
88
-
89
- **Total de Iconos Disponibles**: 16 (5 Button + 11 Input)
90
-
91
- ---
92
-
93
- ## Implementación
94
-
95
- ### Patrón de Implementación
96
-
97
- Todos los iconos siguen un patrón consistente:
98
-
99
- ```typescript
100
- interface IconProps {
101
- className?: string;
102
- }
103
-
104
- export const IconName: React.FC<IconProps> = ({ className = '' }) => (
105
- <svg
106
- xmlns="http://www.w3.org/2000/svg"
107
- viewBox="0 0 16 16"
108
- fill="currentColor"
109
- className={className}
110
- >
111
- <path d="..." />
112
- </svg>
113
- );
114
- ```
115
-
116
- ### Características Clave
117
-
118
- 1. **TypeScript**: Interfaz `IconProps` para type safety
119
- 2. **currentColor**: El fill hereda el color del texto padre
120
- 3. **className**: Permite personalización con Tailwind CSS
121
- 4. **viewBox 16x16**: Tamaño base optimizado
122
- 5. **Props mínimos**: Solo className para máxima flexibilidad
123
-
124
- ### Tamaños de Iconos
125
-
126
- Los iconos se adaptan usando clases de Tailwind CSS:
127
-
128
- ```typescript
129
- // En Button Component
130
- const iconSizeClasses = {
131
- xs: 'w-4 h-4', // 16px - todos los tamaños usan 16px
132
- sm: 'w-4 h-4', // 16px
133
- base: 'w-4 h-4', // 16px (default)
134
- l: 'w-4 h-4', // 16px
135
- xl: 'w-4 h-4', // 16px
136
- };
137
- ```
138
-
139
- **Decisión de Diseño**: Todos los botones usan iconos de 16px independientemente del tamaño del botón, según especificaciones de Figma.
140
-
141
- ---
142
-
143
- ## Guía de Uso
144
-
145
- ### 1. Importación
146
-
147
- ```typescript
148
- // Importar iconos específicos
149
- import { PlusIcon, CheckIcon } from '@/components/Button/icons';
150
- import { EnvelopeIcon, UserIcon } from '@/components/Input/icons';
151
- ```
152
-
153
- ### 2. Uso Básico
154
-
155
- ```tsx
156
- // Icono básico (hereda color del texto padre)
157
- <PlusIcon />
158
-
159
- // Con tamaño personalizado
160
- <UserIcon className="w-5 h-5" />
161
-
162
- // Con color personalizado
163
- <CheckIcon className="w-4 h-4 text-green-600" />
164
- ```
165
-
166
- ### 3. En Componentes
167
-
168
- #### Button con Iconos
169
-
170
- ```tsx
171
- import { Button } from '@/components/Button';
172
- import { PlusIcon, ArrowRightIcon } from '@/components/Button/icons';
173
-
174
- // Icon only button
175
- <Button iconOnly leftIcon={<PlusIcon />} ariaLabel="Añadir" />
176
-
177
- // Button con icono izquierdo
178
- <Button leftIcon={<PlusIcon />}>
179
- Crear Nuevo
180
- </Button>
181
-
182
- // Button con icono derecho
183
- <Button rightIcon={<ArrowRightIcon />}>
184
- Continuar
185
- </Button>
186
-
187
- // Button con ambos iconos
188
- <Button
189
- leftIcon={<CheckIcon />}
190
- rightIcon={<ArrowRightIcon />}
191
- >
192
- Guardar y Continuar
193
- </Button>
194
- ```
195
-
196
- #### Input con Iconos
197
-
198
- ```tsx
199
- import { Input } from '@/components/Input';
200
- import { EnvelopeIcon, EyeIcon } from '@/components/Input/icons';
201
-
202
- // Input con icono izquierdo
203
- <Input
204
- leftIcon={<EnvelopeIcon />}
205
- placeholder="correo@ejemplo.com"
206
- type="email"
207
- />
208
-
209
- // Input con icono derecho
210
- <Input
211
- rightIcon={<EyeIcon />}
212
- placeholder="Contraseña"
213
- type="password"
214
- />
215
- ```
216
-
217
- ### 4. Estados y Temas
218
-
219
- Los iconos heredan automáticamente el color del contexto:
220
-
221
- ```tsx
222
- // En modo claro (hereda color del texto)
223
- <Button type="default">
224
- <PlusIcon /> {/* Hereda text-primary-inverse-content */}
225
- </Button>
226
-
227
- // En modo oscuro (se adapta automáticamente)
228
- <div className="dark">
229
- <Button type="outline">
230
- <UserIcon /> {/* Hereda dark:text-dark-content-primary */}
231
- </Button>
232
- </div>
233
-
234
- // Estados disabled
235
- <Button disabled>
236
- <CheckIcon /> {/* Hereda opacity-50 del botón */}
237
- </Button>
238
- ```
239
-
240
- ---
241
-
242
- ## Modo Oscuro (Dark Mode)
243
-
244
- ### Configuración de Tailwind CSS
245
-
246
- El modo oscuro en Siesa UI Kit se basa en la estrategia de clases de Tailwind CSS:
247
-
248
- ```javascript
249
- // tailwind.config.js
250
- module.exports = {
251
- darkMode: 'class', // ✅ Estrategia basada en clases (NO 'media')
252
- // ...resto de la configuración
253
- }
254
- ```
255
-
256
- Con esta configuración, el modo oscuro se activa añadiendo la clase `.dark` al elemento `<html>`:
257
-
258
- ```html
259
- <!-- Modo claro -->
260
- <html>
261
- <body>
262
- <!-- Contenido en modo claro -->
263
- </body>
264
- </html>
265
-
266
- <!-- Modo oscuro -->
267
- <html class="dark">
268
- <body>
269
- <!-- Contenido en modo oscuro -->
270
- </body>
271
- </html>
272
- ```
273
-
274
- ### El Modificador `dark:`
275
-
276
- El modificador `dark:` de Tailwind funciona como un **prefijo condicional** que aplica estilos solo cuando la clase `.dark` está presente en un elemento padre (típicamente `<html>`).
277
-
278
- #### Sintaxis Básica
279
-
280
- ```tsx
281
- // Patrón básico
282
- <Icon className="text-content-primary dark:text-dark-content-primary" />
283
-
284
- // El icono usa:
285
- // - text-content-primary en modo claro
286
- // - text-dark-content-primary en modo oscuro
287
- ```
288
-
289
- #### Herencia de Color con currentColor
290
-
291
- Los iconos usan `fill="currentColor"`, lo que significa que heredan el color del texto del elemento padre:
292
-
293
- ```tsx
294
- // El icono hereda el color del div padre
295
- <div className="text-content-primary dark:text-dark-content-primary">
296
- <UserIcon /> {/* Automáticamente se adapta */}
297
- </div>
298
-
299
- // Equivalente a especificar el color directamente en el icono
300
- <UserIcon className="text-content-primary dark:text-dark-content-primary" />
301
- ```
302
-
303
- ### Combinando con Otros Modificadores
304
-
305
- El modificador `dark:` se puede combinar con hover, focus, active, y responsive:
306
-
307
- ```tsx
308
- // Dark mode + Hover
309
- <button className="text-gray-700 hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-400">
310
- <PlusIcon />
311
- </button>
312
-
313
- // Dark mode + Focus
314
- <input className="text-content-primary focus:text-primary-custom-600 dark:text-dark-content-primary dark:focus:text-blue-400">
315
- <MagnifyingGlassIcon />
316
- </input>
317
-
318
- // Dark mode + Responsive
319
- <div className="text-gray-900 md:text-blue-600 dark:text-white dark:md:text-blue-400">
320
- <CheckIcon />
321
- </div>
322
-
323
- // Dark mode + Group hover
324
- <div className="group">
325
- <button className="text-gray-700 dark:text-gray-300">
326
- <ArrowRightIcon className="
327
- text-gray-500
328
- group-hover:text-blue-600
329
- dark:text-gray-400
330
- dark:group-hover:text-blue-400
331
- " />
332
- </button>
333
- </div>
334
- ```
335
-
336
- ### Orden de Modificadores
337
-
338
- Tailwind CSS recomienda un orden específico para los modificadores:
339
-
340
- **Formato**: `{responsive}:{dark}:{state}:{utility}`
341
-
342
- ```tsx
343
- // ✅ CORRECTO - Orden: responsive → dark → state → utility
344
- <button className="
345
- md:text-gray-700
346
- md:dark:text-gray-300
347
- md:dark:hover:text-blue-400
348
- ">
349
- <PlusIcon />
350
- </button>
351
-
352
- // ❌ INCORRECTO - Orden equivocado
353
- <button className="
354
- dark:md:hover:text-blue-400
355
- ">
356
- <PlusIcon />
357
- </button>
358
- ```
359
-
360
- ### Tabla de Estados con Hover
361
-
362
- | Estado | Light Mode | Dark Mode | Descripción |
363
- |--------|------------|-----------|-------------|
364
- | **Default** | `text-content-primary` | `dark:text-dark-content-primary` | Color principal del icono |
365
- | **Hover** | `hover:text-primary-custom-600` | `dark:hover:text-blue-400` | Color al pasar el mouse |
366
- | **Focus** | `focus:text-primary-custom-600` | `dark:focus:text-blue-400` | Color al enfocar |
367
- | **Active** | `active:text-primary-custom-700` | `dark:active:text-blue-500` | Color al hacer clic |
368
- | **Disabled** | `text-content-tertiary` | `dark:text-dark-content-tertiary` | Color deshabilitado |
369
- | **Error** | `text-error-content` | `dark:text-red-400` | Color de error |
370
- | **Success** | `text-green-600` | `dark:text-green-400` | Color de éxito |
371
-
372
- ### Implementación del Toggle Dark Mode
373
-
374
- #### Implementación Básica con JavaScript
375
-
376
- ```typescript
377
- // utils/darkMode.ts
378
- export const toggleDarkMode = () => {
379
- const isDark = document.documentElement.classList.contains('dark');
380
-
381
- if (isDark) {
382
- document.documentElement.classList.remove('dark');
383
- localStorage.setItem('theme', 'light');
384
- } else {
385
- document.documentElement.classList.add('dark');
386
- localStorage.setItem('theme', 'dark');
387
- }
388
- };
389
-
390
- // Cargar el tema al iniciar la aplicación
391
- export const loadTheme = () => {
392
- const savedTheme = localStorage.getItem('theme');
393
- const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
394
-
395
- if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
396
- document.documentElement.classList.add('dark');
397
- } else {
398
- document.documentElement.classList.remove('dark');
399
- }
400
- };
401
- ```
402
-
403
- #### Prevenir Flash de Contenido (FOUC)
404
-
405
- Añadir este script en el `<head>` del HTML antes de que React se cargue:
406
-
407
- ```html
408
- <!-- index.html -->
409
- <head>
410
- <script>
411
- // Aplicar tema inmediatamente antes del render
412
- (function() {
413
- const theme = localStorage.getItem('theme');
414
- const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
415
-
416
- if (theme === 'dark' || (!theme && prefersDark)) {
417
- document.documentElement.classList.add('dark');
418
- }
419
- })();
420
- </script>
421
- </head>
422
- ```
423
-
424
- ### Ejemplos Completos
425
-
426
- #### Ejemplo 1: Toolbar de Iconos con Dark Mode
427
-
428
- ```tsx
429
- import { Button } from '@/components/Button';
430
- import { PlusIcon, CheckIcon, XIcon } from '@/components/Button/icons';
431
-
432
- export const IconToolbar = () => {
433
- return (
434
- <div className="
435
- flex gap-2 p-4
436
- bg-white dark:bg-dark-bg-primary
437
- border-b border-border-primary dark:border-dark-border-primary
438
- ">
439
- {/* Icono con hover adaptado */}
440
- <Button
441
- iconOnly
442
- type="outline"
443
- leftIcon={<PlusIcon />}
444
- ariaLabel="Añadir"
445
- className="
446
- text-content-primary dark:text-dark-content-primary
447
- hover:text-primary-custom-600 dark:hover:text-blue-400
448
- hover:bg-gray-100 dark:hover:bg-gray-800
449
- "
450
- />
451
-
452
- {/* Icono de éxito */}
453
- <Button
454
- iconOnly
455
- type="outline"
456
- leftIcon={<CheckIcon />}
457
- ariaLabel="Guardar"
458
- className="
459
- text-green-600 dark:text-green-400
460
- hover:text-green-700 dark:hover:text-green-300
461
- hover:bg-green-50 dark:hover:bg-green-900/20
462
- "
463
- />
464
-
465
- {/* Icono de error */}
466
- <Button
467
- iconOnly
468
- type="outline"
469
- leftIcon={<XIcon />}
470
- ariaLabel="Cancelar"
471
- className="
472
- text-error-content dark:text-red-400
473
- hover:text-red-700 dark:hover:text-red-300
474
- hover:bg-red-50 dark:hover:bg-red-900/20
475
- "
476
- />
477
- </div>
478
- );
479
- };
480
- ```
481
-
482
- #### Ejemplo 2: Formulario con Iconos Adaptativos
483
-
484
- ```tsx
485
- import { Input } from '@/components/Input';
486
- import { UserIcon, LockClosedIcon, EnvelopeIcon } from '@/components/Input/icons';
487
- import { Button } from '@/components/Button';
488
- import { ArrowRightIcon, CheckIcon } from '@/components/Button/icons';
489
-
490
- export const AdaptiveForm = () => {
491
- return (
492
- <div className="
493
- w-full max-w-md p-6
494
- bg-white dark:bg-dark-bg-primary
495
- border border-border-primary dark:border-dark-border-primary
496
- rounded-2xl
497
- shadow-base dark:shadow-lg
498
- ">
499
- <h2 className="
500
- mb-6
501
- text-content-primary dark:text-dark-content-primary
502
- font-bold text-xl
503
- ">
504
- Iniciar Sesión
505
- </h2>
506
-
507
- <form className="space-y-4">
508
- {/* Input de email con icono */}
509
- <Input
510
- label="Correo Electrónico"
511
- type="email"
512
- leftIcon={
513
- <EnvelopeIcon className="
514
- text-content-secondary dark:text-dark-content-secondary
515
- " />
516
- }
517
- placeholder="tu@email.com"
518
- className="
519
- text-content-primary dark:text-dark-content-primary
520
- bg-bg-primary dark:bg-dark-bg-secondary
521
- border-border-primary dark:border-dark-border-primary
522
- focus:border-primary-custom-600 dark:focus:border-blue-400
523
- "
524
- />
525
-
526
- {/* Input de usuario con icono */}
527
- <Input
528
- label="Usuario"
529
- leftIcon={
530
- <UserIcon className="
531
- text-content-secondary dark:text-dark-content-secondary
532
- " />
533
- }
534
- placeholder="Tu usuario"
535
- className="
536
- text-content-primary dark:text-dark-content-primary
537
- bg-bg-primary dark:bg-dark-bg-secondary
538
- "
539
- />
540
-
541
- {/* Input de contraseña con icono */}
542
- <Input
543
- label="Contraseña"
544
- type="password"
545
- leftIcon={
546
- <LockClosedIcon className="
547
- text-content-secondary dark:text-dark-content-secondary
548
- " />
549
- }
550
- placeholder="Tu contraseña"
551
- className="
552
- text-content-primary dark:text-dark-content-primary
553
- bg-bg-primary dark:bg-dark-bg-secondary
554
- "
555
- />
556
-
557
- {/* Botón de submit con icono */}
558
- <Button
559
- type="default"
560
- fullWidth
561
- rightIcon={<ArrowRightIcon />}
562
- className="
563
- bg-primary-custom-600 dark:bg-dark-bg-inverse
564
- text-primary-inverse-content dark:text-dark-content-inverse
565
- hover:bg-primary-custom-500 dark:hover:bg-dark-bg-inverse/90
566
- "
567
- >
568
- Continuar
569
- </Button>
570
- </form>
571
- </div>
572
- );
573
- };
574
- ```
575
-
576
- #### Ejemplo 3: Status Icons con Colores Adaptativos
577
-
578
- ```tsx
579
- import { CheckIcon, ExclamationCircleIcon, XMarkIcon } from '@/components/Input/icons';
580
-
581
- export const StatusMessages = () => {
582
- return (
583
- <div className="space-y-3">
584
- {/* Mensaje de éxito */}
585
- <div className="
586
- flex items-center gap-3 p-4
587
- bg-green-50 dark:bg-green-900/20
588
- border border-green-200 dark:border-green-800
589
- rounded-lg
590
- ">
591
- <CheckIcon className="
592
- w-5 h-5
593
- text-green-600 dark:text-green-400
594
- " />
595
- <p className="
596
- text-green-800 dark:text-green-300
597
- font-medium
598
- ">
599
- Operación completada con éxito
600
- </p>
601
- </div>
602
-
603
- {/* Mensaje de advertencia */}
604
- <div className="
605
- flex items-center gap-3 p-4
606
- bg-yellow-50 dark:bg-yellow-900/20
607
- border border-yellow-200 dark:border-yellow-800
608
- rounded-lg
609
- ">
610
- <ExclamationCircleIcon className="
611
- w-5 h-5
612
- text-yellow-600 dark:text-yellow-400
613
- " />
614
- <p className="
615
- text-yellow-800 dark:text-yellow-300
616
- font-medium
617
- ">
618
- Advertencia: Revisa la información
619
- </p>
620
- </div>
621
-
622
- {/* Mensaje de error */}
623
- <div className="
624
- flex items-center gap-3 p-4
625
- bg-red-50 dark:bg-red-900/20
626
- border border-red-200 dark:border-red-800
627
- rounded-lg
628
- ">
629
- <XMarkIcon className="
630
- w-5 h-5
631
- text-error-content dark:text-red-400
632
- " />
633
- <p className="
634
- text-red-800 dark:text-red-300
635
- font-medium
636
- ">
637
- Error: No se pudo completar la operación
638
- </p>
639
- </div>
640
- </div>
641
- );
642
- };
643
- ```
644
-
645
- #### Ejemplo 4: Icon Button con Group Hover
646
-
647
- ```tsx
648
- import { ArrowRightIcon } from '@/components/Button/icons';
649
-
650
- export const NavigationCard = () => {
651
- return (
652
- <button className="
653
- group
654
- w-full p-6
655
- bg-white dark:bg-dark-bg-primary
656
- border border-border-primary dark:border-dark-border-primary
657
- rounded-xl
658
- hover:border-primary-custom-600 dark:hover:border-blue-400
659
- hover:shadow-lg
660
- transition-all
661
- text-left
662
- ">
663
- <div className="flex items-center justify-between">
664
- <div>
665
- <h3 className="
666
- mb-2
667
- text-content-primary dark:text-dark-content-primary
668
- font-bold text-lg
669
- group-hover:text-primary-custom-600 dark:group-hover:text-blue-400
670
- ">
671
- Ir a la Configuración
672
- </h3>
673
- <p className="
674
- text-content-secondary dark:text-dark-content-secondary
675
- text-sm
676
- ">
677
- Administra las preferencias del sistema
678
- </p>
679
- </div>
680
-
681
- {/* Icono que se anima y cambia de color en hover */}
682
- <ArrowRightIcon className="
683
- w-6 h-6
684
- text-content-tertiary dark:text-dark-content-tertiary
685
- group-hover:text-primary-custom-600 dark:group-hover:text-blue-400
686
- group-hover:translate-x-1
687
- transition-all
688
- " />
689
- </div>
690
- </button>
691
- );
692
- };
693
- ```
694
-
695
- ### Mejores Prácticas para Iconos en Dark Mode
696
-
697
- #### ✅ Hacer
698
-
699
- 1. **Usar tokens semánticos que se adaptan automáticamente**
700
- ```tsx
701
- // ✅ CORRECTO - Los tokens ya incluyen dark mode
702
- <UserIcon className="text-content-primary dark:text-dark-content-primary" />
703
- ```
704
-
705
- 2. **Aprovechar currentColor para heredar colores del padre**
706
- ```tsx
707
- // ✅ CORRECTO - El icono hereda el color
708
- <div className="text-primary-custom-600 dark:text-blue-400">
709
- <EnvelopeIcon />
710
- </div>
711
- ```
712
-
713
- 3. **Usar colores más brillantes en dark mode**
714
- ```tsx
715
- // ✅ CORRECTO - Ajustar intensidad para dark mode
716
- <CheckIcon className="text-green-600 dark:text-green-400" />
717
- ```
718
-
719
- 4. **Combinar con estados hover y focus**
720
- ```tsx
721
- // ✅ CORRECTO - Estados completos
722
- <button className="
723
- text-gray-700 dark:text-gray-300
724
- hover:text-blue-600 dark:hover:text-blue-400
725
- ">
726
- <PlusIcon />
727
- </button>
728
- ```
729
-
730
- 5. **Reducir opacidad de iconos secundarios en dark mode**
731
- ```tsx
732
- // ✅ CORRECTO - Jerarquía visual
733
- <QuestionMarkCircleIcon className="
734
- text-content-secondary/70 dark:text-dark-content-secondary/60
735
- " />
736
- ```
737
-
738
- #### ❌ Evitar
739
-
740
- 1. **No usar el mismo color para light y dark mode**
741
- ```tsx
742
- // ❌ INCORRECTO - Sin dark variant
743
- <UserIcon className="text-gray-900" />
744
-
745
- // ✅ CORRECTO
746
- <UserIcon className="text-gray-900 dark:text-gray-100" />
747
- ```
748
-
749
- 2. **No hardcodear colores sin considerar contraste**
750
- ```tsx
751
- // ❌ INCORRECTO - Pobre contraste en dark mode
752
- <CheckIcon className="text-gray-300" />
753
-
754
- // ✅ CORRECTO - Buen contraste en ambos modos
755
- <CheckIcon className="text-green-600 dark:text-green-400" />
756
- ```
757
-
758
- 3. **No olvidar estados interactivos**
759
- ```tsx
760
- // ❌ INCORRECTO - Sin hover para dark mode
761
- <button className="hover:text-blue-600">
762
- <PlusIcon />
763
- </button>
764
-
765
- // ✅ CORRECTO
766
- <button className="hover:text-blue-600 dark:hover:text-blue-400">
767
- <PlusIcon />
768
- </button>
769
- ```
770
-
771
- 4. **No usar colores muy oscuros en dark mode**
772
- ```tsx
773
- // ❌ INCORRECTO - Invisible en fondo oscuro
774
- <XIcon className="text-gray-900 dark:text-gray-900" />
775
-
776
- // ✅ CORRECTO - Visible en ambos modos
777
- <XIcon className="text-gray-900 dark:text-gray-100" />
778
- ```
779
-
780
- ### Guía Rápida: Colores de Iconos por Contexto
781
-
782
- | Contexto | Light Mode | Dark Mode | Ejemplo |
783
- |----------|------------|-----------|---------|
784
- | **Icono Principal** | `text-content-primary` | `dark:text-dark-content-primary` | Iconos en botones principales |
785
- | **Icono Secundario** | `text-content-secondary` | `dark:text-dark-content-secondary` | Iconos decorativos |
786
- | **Icono Terciario** | `text-content-tertiary` | `dark:text-dark-content-tertiary` | Iconos de ayuda |
787
- | **Icono Interactivo** | `text-gray-700 hover:text-blue-600` | `dark:text-gray-300 dark:hover:text-blue-400` | Botones icon-only |
788
- | **Icono de Éxito** | `text-green-600` | `dark:text-green-400` | Check, confirmación |
789
- | **Icono de Error** | `text-error-content` | `dark:text-red-400` | X, advertencias |
790
- | **Icono de Info** | `text-blue-600` | `dark:text-blue-400` | Información, ayuda |
791
- | **Icono Deshabilitado** | `text-content-tertiary opacity-50` | `dark:text-dark-content-tertiary opacity-50` | Elementos inactivos |
792
-
793
- ### Recursos Adicionales
794
-
795
- Para más información sobre el modo oscuro:
796
- - Ver `docs/dark-mode-guide.md` - Guía completa de Dark Mode en Tailwind CSS
797
- - Ver `docs/colors.md` - Sistema de colores completo con tokens dark mode
798
- - [Documentación oficial de Tailwind Dark Mode](https://tailwindcss.com/docs/dark-mode)
799
-
800
- ---
801
-
802
- ## Accesibilidad
803
-
804
- ### Consideraciones de Accesibilidad
805
-
806
- #### 1. Iconos Decorativos
807
-
808
- Cuando el icono acompaña texto visible, es decorativo:
809
-
810
- ```tsx
811
- // ✅ CORRECTO: El texto describe la acción
812
- <Button leftIcon={<PlusIcon />}>
813
- Crear Usuario
814
- </Button>
815
- // No se necesita aria-label adicional
816
- ```
817
-
818
- #### 2. Iconos Funcionales (Icon-Only)
819
-
820
- Cuando el icono es el único elemento visual:
821
-
822
- ```tsx
823
- // ✅ CORRECTO: Usar aria-label
824
- <Button
825
- iconOnly
826
- leftIcon={<PlusIcon />}
827
- ariaLabel="Añadir nuevo elemento"
828
- />
829
-
830
- // ❌ INCORRECTO: Sin aria-label
831
- <Button iconOnly leftIcon={<PlusIcon />} />
832
- // Los lectores de pantalla no sabrán la función
833
- ```
834
-
835
- #### 3. Iconos con Significado
836
-
837
- En contextos donde el icono comunica información:
838
-
839
- ```tsx
840
- // ✅ CORRECTO: Añadir rol y aria-label
841
- <span role="img" aria-label="Estado: Exitoso">
842
- <CheckIcon className="text-green-600" />
843
- </span>
844
-
845
- // ✅ CORRECTO: Con texto de soporte visible
846
- <div className="flex items-center gap-2">
847
- <ExclamationCircleIcon className="text-error-content" />
848
- <span>Error en la validación</span>
849
- </div>
850
- ```
851
-
852
- #### 4. Tooltips para Contexto Adicional
853
-
854
- ```tsx
855
- // ✅ MEJOR PRÁCTICA: Icono + Tooltip
856
- <button
857
- className="p-2"
858
- aria-label="Ayuda"
859
- title="Obtener ayuda sobre este campo"
860
- >
861
- <QuestionMarkCircleIcon />
862
- </button>
863
- ```
864
-
865
- ### Directrices WCAG 2.1
866
-
867
- - **Nivel A**: Todos los iconos funcionales deben tener texto alternativo
868
- - **Nivel AA**: Contraste mínimo 3:1 para iconos (se cumple con currentColor)
869
- - **Nivel AAA**: Proveer texto descriptivo adicional cuando sea posible
870
-
871
- ---
872
-
873
- ## Ejemplos de Código
874
-
875
- ### Ejemplo 1: Toolbar de Acciones
876
-
877
- ```tsx
878
- import { Button } from '@/components/Button';
879
- import { PlusIcon, CheckIcon, XIcon } from '@/components/Button/icons';
880
-
881
- export const ActionToolbar = () => {
882
- return (
883
- <div className="flex gap-2 p-4 bg-bg-primary border-b border-border-primary">
884
- {/* Botones icon-only con tooltips */}
885
- <Button
886
- iconOnly
887
- size="base"
888
- type="default"
889
- leftIcon={<PlusIcon />}
890
- ariaLabel="Añadir nuevo registro"
891
- title="Añadir nuevo registro"
892
- />
893
-
894
- <Button
895
- iconOnly
896
- size="base"
897
- type="outline"
898
- leftIcon={<CheckIcon />}
899
- ariaLabel="Guardar cambios"
900
- title="Guardar cambios"
901
- />
902
-
903
- <Button
904
- iconOnly
905
- size="base"
906
- type="plain"
907
- leftIcon={<XIcon />}
908
- ariaLabel="Cancelar operación"
909
- title="Cancelar operación"
910
- />
911
- </div>
912
- );
913
- };
914
- ```
915
-
916
- ### Ejemplo 2: Formulario de Login
917
-
918
- ```tsx
919
- import { Input } from '@/components/Input';
920
- import { Button } from '@/components/Button';
921
- import {
922
- UserIcon,
923
- LockClosedIcon,
924
- EyeIcon,
925
- EyeSlashIcon
926
- } from '@/components/Input/icons';
927
- import { ArrowRightIcon } from '@/components/Button/icons';
928
- import { useState } from 'react';
929
-
930
- export const LoginForm = () => {
931
- const [showPassword, setShowPassword] = useState(false);
932
-
933
- return (
934
- <form className="space-y-4 w-full max-w-sm">
935
- {/* Usuario */}
936
- <Input
937
- label="Usuario"
938
- name="username"
939
- leftIcon={<UserIcon />}
940
- placeholder="Ingrese su usuario"
941
- required
942
- />
943
-
944
- {/* Contraseña con toggle */}
945
- <Input
946
- label="Contraseña"
947
- name="password"
948
- type={showPassword ? 'text' : 'password'}
949
- leftIcon={<LockClosedIcon />}
950
- rightIcon={
951
- <button
952
- type="button"
953
- onClick={() => setShowPassword(!showPassword)}
954
- className="cursor-pointer"
955
- aria-label={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
956
- >
957
- {showPassword ? <EyeSlashIcon /> : <EyeIcon />}
958
- </button>
959
- }
960
- placeholder="Ingrese su contraseña"
961
- required
962
- />
963
-
964
- {/* Submit */}
965
- <Button
966
- type="default"
967
- size="base"
968
- fullWidth
969
- rightIcon={<ArrowRightIcon />}
970
- htmlType="submit"
971
- >
972
- Iniciar Sesión
973
- </Button>
974
- </form>
975
- );
976
- };
977
- ```
978
-
979
- ### Ejemplo 3: Search Input con Estados
980
-
981
- ```tsx
982
- import { Input } from '@/components/Input';
983
- import {
984
- MagnifyingGlassIcon,
985
- XMarkIcon,
986
- CheckIcon,
987
- ExclamationCircleIcon
988
- } from '@/components/Input/icons';
989
- import { useState } from 'react';
990
-
991
- export const SearchInput = () => {
992
- const [query, setQuery] = useState('');
993
- const [status, setStatus] = useState<'idle' | 'searching' | 'success' | 'error'>('idle');
994
-
995
- const getStatusIcon = () => {
996
- switch (status) {
997
- case 'success':
998
- return <CheckIcon className="text-green-600" />;
999
- case 'error':
1000
- return <ExclamationCircleIcon className="text-error-content" />;
1001
- default:
1002
- return null;
1003
- }
1004
- };
1005
-
1006
- return (
1007
- <div className="w-full max-w-md">
1008
- <Input
1009
- label="Búsqueda"
1010
- value={query}
1011
- onChange={(e) => setQuery(e.target.value)}
1012
- leftIcon={<MagnifyingGlassIcon />}
1013
- rightIcon={
1014
- query ? (
1015
- <button
1016
- type="button"
1017
- onClick={() => setQuery('')}
1018
- aria-label="Limpiar búsqueda"
1019
- className="cursor-pointer hover:text-primary-custom-600"
1020
- >
1021
- <XMarkIcon />
1022
- </button>
1023
- ) : (
1024
- getStatusIcon()
1025
- )
1026
- }
1027
- placeholder="Buscar..."
1028
- helperText={
1029
- status === 'error' ? 'No se encontraron resultados' : undefined
1030
- }
1031
- error={status === 'error'}
1032
- />
1033
- </div>
1034
- );
1035
- };
1036
- ```
1037
-
1038
- ---
1039
-
1040
- ## Mejores Prácticas
1041
-
1042
- ### ✅ Hacer
1043
-
1044
- 1. **Usar iconos semánticamente apropiados**
1045
- ```tsx
1046
- // ✅ CORRECTO
1047
- <Button leftIcon={<PlusIcon />}>Añadir</Button>
1048
- <Button leftIcon={<CheckIcon />}>Guardar</Button>
1049
- ```
1050
-
1051
- 2. **Mantener el tamaño de 16px en la mayoría de casos**
1052
- ```tsx
1053
- // ✅ CORRECTO - tamaño por defecto
1054
- <UserIcon className="w-4 h-4" />
1055
- ```
1056
-
1057
- 3. **Usar currentColor para heredar el color del contexto**
1058
- ```tsx
1059
- // ✅ CORRECTO - el icono hereda el color
1060
- <div className="text-primary-custom-600">
1061
- <EnvelopeIcon />
1062
- </div>
1063
- ```
1064
-
1065
- 4. **Proveer aria-label en botones icon-only**
1066
- ```tsx
1067
- // ✅ CORRECTO
1068
- <Button iconOnly leftIcon={<XIcon />} ariaLabel="Cerrar" />
1069
- ```
1070
-
1071
- 5. **Agrupar iconos relacionados en el mismo archivo**
1072
- ```tsx
1073
- // ✅ CORRECTO - iconos de un componente juntos
1074
- // src/components/Button/icons.tsx
1075
- ```
1076
-
1077
- ### ❌ Evitar
1078
-
1079
- 1. **No mezclar diferentes estilos de iconos**
1080
- ```tsx
1081
- // ❌ INCORRECTO - mezclar Heroicons con otros
1082
- <PlusIcon /> {/* Heroicons Micro */}
1083
- <SomeOtherIcon /> {/* Otra librería */}
1084
- ```
1085
-
1086
- 2. **No usar tamaños inconsistentes sin razón**
1087
- ```tsx
1088
- // ❌ INCORRECTO - tamaños arbitrarios
1089
- <UserIcon className="w-7 h-7" />
1090
- <EnvelopeIcon className="w-3 h-3" />
1091
- ```
1092
-
1093
- 3. **No hardcodear colores directamente en el SVG**
1094
- ```tsx
1095
- // ❌ INCORRECTO - hardcodear fill
1096
- <svg fill="#0e79fd">...</svg>
1097
-
1098
- // ✅ CORRECTO - usar currentColor
1099
- <svg fill="currentColor">...</svg>
1100
- ```
1101
-
1102
- 4. **No omitir aria-label en iconos funcionales**
1103
- ```tsx
1104
- // ❌ INCORRECTO
1105
- <button><XIcon /></button>
1106
-
1107
- // ✅ CORRECTO
1108
- <button aria-label="Cerrar"><XIcon /></button>
1109
- ```
1110
-
1111
- 5. **No usar iconos como única forma de comunicación**
1112
- ```tsx
1113
- // ❌ INCORRECTO - solo icono sin contexto
1114
- <div><ExclamationCircleIcon /></div>
1115
-
1116
- // ✅ CORRECTO - icono + texto
1117
- <div className="flex gap-2">
1118
- <ExclamationCircleIcon />
1119
- <span>Error: Campo requerido</span>
1120
- </div>
1121
- ```
1122
-
1123
- ### Rendimiento
1124
-
1125
- - **✅ SVG Inline**: Mejor para iconos que se usan frecuentemente
1126
- - **✅ Tree-shaking**: Importar solo los iconos necesarios
1127
- - **✅ Evitar re-renders**: Los iconos son componentes puros
1128
- - **✅ Memoización**: React.memo si se pasan como props frecuentemente
1129
-
1130
- ```tsx
1131
- // ✅ CORRECTO - memoizar icono si se pasa como prop
1132
- const MemoizedIcon = React.memo(PlusIcon);
1133
-
1134
- // En componente padre
1135
- <Button leftIcon={<MemoizedIcon />}>Añadir</Button>
1136
- ```
1137
-
1138
- ---
1139
-
1140
- ## Referencia Rápida
1141
-
1142
- ### Cheat Sheet: Importaciones
1143
-
1144
- ```typescript
1145
- // Iconos de Button
1146
- import {
1147
- PlusIcon, // Añadir/Crear
1148
- ChevronDownIcon, // Dropdown
1149
- ArrowRightIcon, // Navegación
1150
- CheckIcon, // Confirmar
1151
- XIcon // Cerrar/Cancelar
1152
- } from '@/components/Button/icons';
1153
-
1154
- // Iconos de Input
1155
- import {
1156
- EnvelopeIcon, // Email
1157
- QuestionMarkCircleIcon, // Ayuda
1158
- UserIcon, // Usuario
1159
- LockClosedIcon, // Seguridad
1160
- MagnifyingGlassIcon, // Búsqueda
1161
- EyeIcon, // Ver password
1162
- EyeSlashIcon, // Ocultar password
1163
- XMarkIcon, // Limpiar
1164
- CheckIcon, // Éxito
1165
- ExclamationCircleIcon // Error
1166
- } from '@/components/Input/icons';
1167
- ```
1168
-
1169
- ### Cheat Sheet: Tamaños Comunes
1170
-
1171
- | Clase Tailwind | Tamaño | Uso |
1172
- |----------------|--------|-----|
1173
- | `w-4 h-4` | 16px | **Default** - Botones, inputs |
1174
- | `w-5 h-5` | 20px | Iconos destacados |
1175
- | `w-6 h-6` | 24px | Headers, títulos |
1176
- | `w-8 h-8` | 32px | Iconos grandes, heros |
1177
-
1178
- ### Cheat Sheet: Colores Comunes
1179
-
1180
- ```tsx
1181
- // Primary
1182
- <Icon className="text-primary-custom-600" />
1183
-
1184
- // Éxito (Verde)
1185
- <CheckIcon className="text-green-600" />
1186
-
1187
- // Error (Rojo)
1188
- <ExclamationCircleIcon className="text-error-content" />
1189
-
1190
- // Secundario (Gris)
1191
- <Icon className="text-content-secondary" />
1192
-
1193
- // Dark Mode (automático)
1194
- <Icon className="text-content-primary dark:text-dark-content-primary" />
1195
- ```
1196
-
1197
- ### Cheat Sheet: Patrones de Uso
1198
-
1199
- ```tsx
1200
- // 1. Icon-only Button
1201
- <Button iconOnly leftIcon={<PlusIcon />} ariaLabel="Añadir" />
1202
-
1203
- // 2. Button con texto e icono
1204
- <Button leftIcon={<CheckIcon />}>Guardar</Button>
1205
-
1206
- // 3. Input con icono
1207
- <Input leftIcon={<UserIcon />} placeholder="Usuario" />
1208
-
1209
- // 4. Toggle icon
1210
- {visible ? <EyeIcon /> : <EyeSlashIcon />}
1211
-
1212
- // 5. Status icon
1213
- {status === 'success' ? <CheckIcon /> : <ExclamationCircleIcon />}
1214
- ```
1215
-
1216
- ---
1217
-
1218
- ## Añadir Nuevos Iconos
1219
-
1220
- ### Proceso para Agregar un Icono
1221
-
1222
- 1. **Obtener el SVG de Heroicons Micro**
1223
- - Visitar: https://heroicons.com
1224
- - Seleccionar versión "Micro" (16px)
1225
- - Copiar el código SVG
1226
-
1227
- 2. **Crear el Componente React**
1228
- ```tsx
1229
- // En el archivo icons.tsx correspondiente
1230
- export const NewIcon: React.FC<IconProps> = ({ className = '' }) => (
1231
- <svg
1232
- xmlns="http://www.w3.org/2000/svg"
1233
- viewBox="0 0 16 16"
1234
- fill="currentColor"
1235
- className={className}
1236
- >
1237
- {/* Pegar path(s) del SVG */}
1238
- <path d="..." />
1239
- </svg>
1240
- );
1241
- ```
1242
-
1243
- 3. **Documentar el Nuevo Icono**
1244
- - Añadir a la tabla de catálogo
1245
- - Incluir ejemplo de uso
1246
- - Especificar contexto apropiado
1247
-
1248
- 4. **Testing**
1249
- - Verificar en modo claro y oscuro
1250
- - Probar diferentes tamaños
1251
- - Validar accesibilidad
1252
-
1253
- ### Decisiones de Organización
1254
-
1255
- - **¿Dónde colocar el nuevo icono?**
1256
- - ¿Se usa en Button? → `src/components/Button/icons.tsx`
1257
- - ¿Se usa en Input? → `src/components/Input/icons.tsx`
1258
- - ¿Se usa en múltiples componentes? → Crear `src/shared/icons.tsx`
1259
-
1260
- ---
1261
-
1262
- ## Recursos Adicionales
1263
-
1264
- ### Enlaces Útiles
1265
-
1266
- - **Heroicons**: https://heroicons.com
1267
- - **Documentación Heroicons**: https://github.com/tailwindlabs/heroicons
1268
- - **WCAG Guidelines**: https://www.w3.org/WAI/WCAG21/quickref/
1269
- - **SVG Accessibility**: https://css-tricks.com/accessible-svgs/
1270
-
1271
- ### Archivos Relacionados
1272
-
1273
- - `src/components/Button/icons.tsx` - Iconos de botones
1274
- - `src/components/Input/icons.tsx` - Iconos de inputs
1275
- - `src/components/Button/Button.tsx` - Implementación de iconos en Button
1276
- - `docs/colors.md` - Sistema de colores (para colores de iconos)
1277
- - `docs/typography.md` - Sistema tipográfico
1278
-
1279
- ---
1280
-
1281
- **Última actualización**: 2025-11-11
1282
- **Versión**: 1.0.0
1283
- **Mantenedor**: Siesa UI Kit Team