ten-minds-beta 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +914 -0
- package/assets/fonts/PlusJakartaSans-VariableFont_wght.woff2 +0 -0
- package/fesm2022/ten-minds-beta.mjs +592 -0
- package/fesm2022/ten-minds-beta.mjs.map +1 -0
- package/package.json +40 -0
- package/styles/_typography.css +64 -0
- package/styles/_variables.css +200 -0
- package/styles/styles.css +5 -0
- package/types/ten-minds-beta.d.ts +238 -0
package/README.md
ADDED
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
# TenMindsBeta
|
|
2
|
+
|
|
3
|
+
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ng generate component component-name
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ng generate --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Building
|
|
20
|
+
|
|
21
|
+
To build the library, run:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ng build ten-minds-beta
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
|
|
28
|
+
|
|
29
|
+
### Publishing the Library
|
|
30
|
+
|
|
31
|
+
Once the project is built, you can publish your library by following these steps:
|
|
32
|
+
|
|
33
|
+
1. Navigate to the `dist` directory:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd dist/ten-minds-beta
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. Run the `npm publish` command to publish your library to the npm registry:
|
|
40
|
+
```bash
|
|
41
|
+
npm publish
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Running unit tests
|
|
45
|
+
|
|
46
|
+
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
ng test
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Running end-to-end tests
|
|
53
|
+
|
|
54
|
+
For end-to-end (e2e) testing, run:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
ng e2e
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
|
61
|
+
|
|
62
|
+
## Additional Resources
|
|
63
|
+
|
|
64
|
+
# ten-minds-beta
|
|
65
|
+
|
|
66
|
+
Librería de componentes UI para Angular, construida con Tailwind CSS v4 y Lucide Icons.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Instalación
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install ten-minds-beta lucide-angular
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Configuración inicial
|
|
79
|
+
|
|
80
|
+
En el `app.config.ts` de tu proyecto, registrá los íconos de Lucide que vas a usar:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
|
84
|
+
import { LucideAngularModule, Download, Trash2, Check, Plus, X, Pencil, Search } from 'lucide-angular';
|
|
85
|
+
|
|
86
|
+
export const appConfig: ApplicationConfig = {
|
|
87
|
+
providers: [
|
|
88
|
+
importProvidersFrom(
|
|
89
|
+
LucideAngularModule.pick({ Download, Trash2, Check, Plus, X, Pencil, Search })
|
|
90
|
+
)
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> Registrá solo los íconos que uses — eso mantiene el bundle liviano.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Estilos
|
|
100
|
+
|
|
101
|
+
Importá los estilos de la librería en el `styles.css` de tu proyecto:
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
@import 'ten-minds-beta/styles/styles.css';
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Componentes
|
|
110
|
+
|
|
111
|
+
### `<btn-primary>`
|
|
112
|
+
|
|
113
|
+
Botón con soporte para múltiples variantes, tamaños, estados y íconos.
|
|
114
|
+
|
|
115
|
+
#### Importar
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { BtnPrimary } from 'ten-minds-beta';
|
|
119
|
+
|
|
120
|
+
@Component({
|
|
121
|
+
imports: [BtnPrimary],
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Inputs
|
|
126
|
+
|
|
127
|
+
| Input | Tipo | Default | Descripción |
|
|
128
|
+
|------------|-----------------------------------------------|-------------|------------------------------------|
|
|
129
|
+
| `color` | `'primary' \| 'danger' \| 'success' \| 'warning'` | `'primary'` | Color del botón |
|
|
130
|
+
| `size` | `'lg' \| 'md' \| 'sm'` | `'md'` | Tamaño del botón |
|
|
131
|
+
| `type` | `'filled' \| 'outlined' \| 'ghost'` | `'filled'` | Estilo visual del botón |
|
|
132
|
+
| `disabled` | `boolean` | `false` | Deshabilita el botón |
|
|
133
|
+
| `active` | `boolean` | `false` | Aplica estado activo |
|
|
134
|
+
| `iconLeft` | `string` | — | Nombre del ícono Lucide a la izquierda |
|
|
135
|
+
| `iconRight`| `string` | — | Nombre del ícono Lucide a la derecha |
|
|
136
|
+
|
|
137
|
+
#### Outputs
|
|
138
|
+
|
|
139
|
+
| Output | Tipo | Descripción |
|
|
140
|
+
|-----------|--------------|------------------------------------|
|
|
141
|
+
| `clicked` | `MouseEvent` | Se emite al hacer click en el botón |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
#### Ejemplos de uso
|
|
146
|
+
|
|
147
|
+
**Variantes de color:**
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<btn-primary color="primary" type="filled">Primary</btn-primary>
|
|
151
|
+
<btn-primary color="danger" type="filled">Danger</btn-primary>
|
|
152
|
+
<btn-primary color="success" type="filled">Success</btn-primary>
|
|
153
|
+
<btn-primary color="warning" type="filled">Warning</btn-primary>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Variantes de tipo:**
|
|
157
|
+
|
|
158
|
+
```html
|
|
159
|
+
<btn-primary type="filled" >Filled</btn-primary>
|
|
160
|
+
<btn-primary type="outlined">Outlined</btn-primary>
|
|
161
|
+
<btn-primary type="ghost" >Ghost</btn-primary>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Tamaños:**
|
|
165
|
+
|
|
166
|
+
```html
|
|
167
|
+
<btn-primary size="lg">Large</btn-primary>
|
|
168
|
+
<btn-primary size="md">Medium</btn-primary>
|
|
169
|
+
<btn-primary size="sm">Small</btn-primary>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Estado disabled:**
|
|
173
|
+
|
|
174
|
+
```html
|
|
175
|
+
<btn-primary [disabled]="true">Deshabilitado</btn-primary>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Con íconos:**
|
|
179
|
+
|
|
180
|
+
```html
|
|
181
|
+
<!-- Ícono izquierdo -->
|
|
182
|
+
<btn-primary iconLeft="download">Exportar</btn-primary>
|
|
183
|
+
|
|
184
|
+
<!-- Ícono derecho -->
|
|
185
|
+
<btn-primary iconRight="arrow-right">Siguiente</btn-primary>
|
|
186
|
+
|
|
187
|
+
<!-- Ambos íconos -->
|
|
188
|
+
<btn-primary iconLeft="upload" iconRight="check">Subir archivo</btn-primary>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> Los nombres de íconos van en kebab-case exactamente como aparecen en [lucide.dev](https://lucide.dev).
|
|
192
|
+
> Recordá registrar cada ícono que uses en el `app.config.ts`.
|
|
193
|
+
|
|
194
|
+
**Escuchando eventos:**
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<!-- Output propio -->
|
|
198
|
+
<btn-primary (clicked)="guardar($event)">Guardar</btn-primary>
|
|
199
|
+
|
|
200
|
+
<!-- Eventos nativos -->
|
|
201
|
+
<btn-primary
|
|
202
|
+
(click)="guardar()"
|
|
203
|
+
(dblclick)="abrirModal()"
|
|
204
|
+
(focus)="onFocus()"
|
|
205
|
+
(blur)="onBlur()"
|
|
206
|
+
>
|
|
207
|
+
Guardar
|
|
208
|
+
</btn-primary>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Combinado:**
|
|
212
|
+
|
|
213
|
+
```html
|
|
214
|
+
<btn-primary
|
|
215
|
+
color="primary"
|
|
216
|
+
type="filled"
|
|
217
|
+
size="md"
|
|
218
|
+
iconLeft="download"
|
|
219
|
+
(clicked)="exportar($event)"
|
|
220
|
+
>
|
|
221
|
+
Exportar registros
|
|
222
|
+
</btn-primary>
|
|
223
|
+
|
|
224
|
+
<btn-primary
|
|
225
|
+
color="danger"
|
|
226
|
+
type="outlined"
|
|
227
|
+
size="sm"
|
|
228
|
+
iconLeft="trash-2"
|
|
229
|
+
[disabled]="cargando"
|
|
230
|
+
(clicked)="eliminar($event)"
|
|
231
|
+
>
|
|
232
|
+
Eliminar
|
|
233
|
+
</btn-primary>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Íconos disponibles en Lucide
|
|
239
|
+
|
|
240
|
+
Podés ver el catálogo completo en [lucide.dev](https://lucide.dev). Algunos íconos comunes:
|
|
241
|
+
|
|
242
|
+
| Nombre | Uso sugerido |
|
|
243
|
+
|------------------|----------------------|
|
|
244
|
+
| `download` | Exportar, descargar |
|
|
245
|
+
| `upload` | Importar, subir |
|
|
246
|
+
| `trash-2` | Eliminar |
|
|
247
|
+
| `pencil` | Editar |
|
|
248
|
+
| `check` | Confirmar, guardar |
|
|
249
|
+
| `x` | Cancelar, cerrar |
|
|
250
|
+
| `plus` | Agregar, nuevo |
|
|
251
|
+
| `search` | Buscar |
|
|
252
|
+
| `arrow-right` | Siguiente, continuar |
|
|
253
|
+
| `arrow-left` | Volver, anterior |
|
|
254
|
+
| `chevron-down` | Expandir |
|
|
255
|
+
| `settings` | Configuración |
|
|
256
|
+
| `user` | Perfil, usuario |
|
|
257
|
+
| `eye` | Ver, mostrar |
|
|
258
|
+
| `eye-off` | Ocultar |
|
|
259
|
+
| `alert-triangle` | Advertencia |
|
|
260
|
+
| `info` | Información |
|
|
261
|
+
| `filter` | Filtrar |
|
|
262
|
+
| `refresh-cw` | Recargar |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Desarrollo
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Buildear la librería en modo watch
|
|
270
|
+
ng build ten-minds-beta --watch
|
|
271
|
+
|
|
272
|
+
# Servir la app de prueba
|
|
273
|
+
ng serve consumer-app
|
|
274
|
+
```
|
|
275
|
+
## SnackbarService
|
|
276
|
+
|
|
277
|
+
Sistema de notificaciones globales para mostrar feedback visual al usuario.
|
|
278
|
+
Reemplaza los `console.log` con mensajes visibles en pantalla.
|
|
279
|
+
|
|
280
|
+
### Configuración (una sola vez)
|
|
281
|
+
|
|
282
|
+
**`app.html`:**
|
|
283
|
+
|
|
284
|
+
```html
|
|
285
|
+
<tm-snackbar-host />
|
|
286
|
+
<router-outlet />
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**`app.ts`:**
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { SnackbarHostComponent } from 'ten-minds-beta';
|
|
293
|
+
|
|
294
|
+
@Component({
|
|
295
|
+
imports: [SnackbarHostComponent],
|
|
296
|
+
})
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Uso
|
|
300
|
+
```typescript
|
|
301
|
+
import { SnackbarService } from 'ten-minds-beta';
|
|
302
|
+
|
|
303
|
+
export class MiComponente {
|
|
304
|
+
snackbar = inject(SnackbarService);
|
|
305
|
+
|
|
306
|
+
async onGuardar() {
|
|
307
|
+
try {
|
|
308
|
+
await this.service.guardar(data);
|
|
309
|
+
this.snackbar.success('Guardado', 'Los cambios fueron guardados correctamente');
|
|
310
|
+
} catch {
|
|
311
|
+
this.snackbar.error('Error', 'No pudimos guardar los cambios');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Métodos
|
|
318
|
+
|
|
319
|
+
| Método | Tipo | Descripción |
|
|
320
|
+
|--------|------|-------------|
|
|
321
|
+
| `success(title, description?)` | alert | Desaparece en 5s |
|
|
322
|
+
| `error(title, description?)` | alert | Desaparece en 5s |
|
|
323
|
+
| `warning(title, description?)` | alert | Desaparece en 5s |
|
|
324
|
+
| `info(title, description?)` | alert | Desaparece en 5s |
|
|
325
|
+
| `notify(color{success,error,warning,info}, title, description?)` | notification | El usuario la cierra manualmente |
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
## Chip
|
|
330
|
+
|
|
331
|
+
Componente para mostrar estados, etiquetas o valores visuales. Puede ser estático o clickeable.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Instalación
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
import { Chip } from 'ten-minds-beta';
|
|
339
|
+
|
|
340
|
+
@Component({
|
|
341
|
+
imports: [Chip],
|
|
342
|
+
})
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Status (colores)
|
|
348
|
+
|
|
349
|
+
| Status | Uso recomendado |
|
|
350
|
+
|-----------|----------------------------------------|
|
|
351
|
+
| `success` | Activo, completado, aprobado |
|
|
352
|
+
| `warning` | Pendiente, por vencer, precaución |
|
|
353
|
+
| `danger` | Inactivo, error, rechazado |
|
|
354
|
+
| `info` | Informativo, en proceso |
|
|
355
|
+
| `indigo` | Categorías, etiquetas neutras |
|
|
356
|
+
| `brand` | Destacado, principal |
|
|
357
|
+
|
|
358
|
+
```html
|
|
359
|
+
<chip status="success">Activo</chip>
|
|
360
|
+
<chip status="warning">Pendiente</chip>
|
|
361
|
+
<chip status="danger">Inactivo</chip>
|
|
362
|
+
<chip status="info">En proceso</chip>
|
|
363
|
+
<chip status="indigo">Categoría</chip>
|
|
364
|
+
<chip status="brand">Destacado</chip>
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Type (estilo visual)
|
|
370
|
+
|
|
371
|
+
| Type | Descripción |
|
|
372
|
+
|------------|------------------------------------------|
|
|
373
|
+
| `filled` | Fondo sólido con texto blanco |
|
|
374
|
+
| `subtle` | Fondo suave con texto del color |
|
|
375
|
+
| `outlined` | Sin fondo, solo borde y texto del color |
|
|
376
|
+
|
|
377
|
+
```html
|
|
378
|
+
<chip status="success" type="filled">Filled</chip>
|
|
379
|
+
<chip status="success" type="subtle">Subtle</chip>
|
|
380
|
+
<chip status="success" type="outlined">Outlined</chip>
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Rounded (forma)
|
|
386
|
+
|
|
387
|
+
| Rounded | Uso recomendado |
|
|
388
|
+
|-----------|-----------------------------------------------------|
|
|
389
|
+
| `default` | Valores estáticos, estados, badges informativos |
|
|
390
|
+
| `full` | Filtros, tags interactivos, estados de productos |
|
|
391
|
+
|
|
392
|
+
```html
|
|
393
|
+
<chip status="info" rounded="default">Estado</chip>
|
|
394
|
+
<chip status="info" rounded="full">Etiqueta</chip>
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Iconos
|
|
400
|
+
|
|
401
|
+
Acepta cualquier nombre de icono de [Lucide](https://lucide.dev/icons/) en `iconLeft` o `iconRight`.
|
|
402
|
+
|
|
403
|
+
```html
|
|
404
|
+
<!-- Solo icono izquierdo -->
|
|
405
|
+
<chip status="success" iconLeft="check">Activo</chip>
|
|
406
|
+
|
|
407
|
+
<!-- Solo icono derecho -->
|
|
408
|
+
<chip status="info" iconRight="x">Etiqueta</chip>
|
|
409
|
+
|
|
410
|
+
<!-- Ambos iconos -->
|
|
411
|
+
<chip status="warning" iconLeft="triangle-alert" iconRight="x">Advertencia</chip>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## Clickeable
|
|
417
|
+
|
|
418
|
+
Por defecto el chip es estático. Para hacerlo interactivo usa `[clickable]="true"` y escucha el evento `(clicked)`.
|
|
419
|
+
|
|
420
|
+
```html
|
|
421
|
+
<chip
|
|
422
|
+
status="danger"
|
|
423
|
+
type="filled"
|
|
424
|
+
rounded="full"
|
|
425
|
+
iconLeft="circle-x"
|
|
426
|
+
[clickable]="true"
|
|
427
|
+
(clicked)="onDesactivar()"
|
|
428
|
+
>
|
|
429
|
+
Desactivar
|
|
430
|
+
</chip>
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
onDesactivar() {
|
|
435
|
+
console.log('chip clickeado');
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
> Si `clickable` es `false` (default), el chip no emite eventos ni muestra cursor pointer.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Referencia de inputs y outputs
|
|
444
|
+
|
|
445
|
+
| Input | Tipo | Default | Descripción |
|
|
446
|
+
|-------------|---------------|-------------|-------------------------------------------------------|
|
|
447
|
+
| `status` | `ChipStatus` | `'brand'` | Color del chip |
|
|
448
|
+
| `type` | `ChipType` | `'filled'` | Estilo visual del chip |
|
|
449
|
+
| `rounded` | `ChipRounded` | `'default'` | Forma del borde |
|
|
450
|
+
| `iconLeft` | `string` | — | Nombre del icono Lucide a la izquierda (opcional) |
|
|
451
|
+
| `iconRight` | `string` | — | Nombre del icono Lucide a la derecha (opcional) |
|
|
452
|
+
| `clickable` | `boolean` | `false` | Habilita cursor pointer y emite evento al hacer click |
|
|
453
|
+
|
|
454
|
+
| Output | Tipo | Descripción |
|
|
455
|
+
|-----------|--------|-----------------------------------------------|
|
|
456
|
+
| `clicked` | `void` | Se emite al hacer click si `clickable="true"` |
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## Casos de uso reales
|
|
461
|
+
|
|
462
|
+
```html
|
|
463
|
+
<!-- Estado de un producto -->
|
|
464
|
+
<chip status="success" type="subtle" rounded="full" iconLeft="check">
|
|
465
|
+
Activo
|
|
466
|
+
</chip>
|
|
467
|
+
|
|
468
|
+
<!-- Licencia por vencer -->
|
|
469
|
+
<chip status="warning" type="filled" rounded="default" iconLeft="triangle-alert">
|
|
470
|
+
Por vencer
|
|
471
|
+
</chip>
|
|
472
|
+
|
|
473
|
+
<!-- Filtro clickeable -->
|
|
474
|
+
<chip
|
|
475
|
+
status="indigo"
|
|
476
|
+
type="outlined"
|
|
477
|
+
rounded="full"
|
|
478
|
+
[clickable]="true"
|
|
479
|
+
(clicked)="filtrar()"
|
|
480
|
+
>
|
|
481
|
+
Electrónica
|
|
482
|
+
</chip>
|
|
483
|
+
|
|
484
|
+
<!-- Notificación de error -->
|
|
485
|
+
<chip status="danger" type="subtle" rounded="default" iconLeft="circle-x">
|
|
486
|
+
Pago rechazado
|
|
487
|
+
</chip>
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Componente Toggle
|
|
491
|
+
|
|
492
|
+
Componente de interruptor para activar o desactivar estados. Emite el nuevo valor al padre para que maneje la lógica correspondiente.
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Instalación
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
import { Toggle } from 'ten-minds-beta';
|
|
500
|
+
|
|
501
|
+
@Component({
|
|
502
|
+
imports: [Toggle],
|
|
503
|
+
})
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## Uso básico
|
|
509
|
+
|
|
510
|
+
```html
|
|
511
|
+
<toggle [value]="isActive" (changed)="isActive = $event" />
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Inputs y Outputs
|
|
517
|
+
|
|
518
|
+
| Input | Tipo | Default | Descripción |
|
|
519
|
+
|------------|-----------|---------|------------------------------------------|
|
|
520
|
+
| `value` | `boolean` | `false` | Estado actual del toggle |
|
|
521
|
+
| `disabled` | `boolean` | `false` | Desactiva la interacción |
|
|
522
|
+
|
|
523
|
+
| Output | Tipo | Descripción |
|
|
524
|
+
|-----------|-----------|----------------------------------------|
|
|
525
|
+
| `changed` | `boolean` | Emite el nuevo estado al hacer click |
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Estados
|
|
530
|
+
|
|
531
|
+
### Default (apagado)
|
|
532
|
+
```html
|
|
533
|
+
<toggle [value]="false" (changed)="onChanged($event)" />
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Active (encendido)
|
|
537
|
+
```html
|
|
538
|
+
<toggle [value]="true" (changed)="onChanged($event)" />
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Disabled
|
|
542
|
+
```html
|
|
543
|
+
<toggle [value]="false" [disabled]="true" />
|
|
544
|
+
<toggle [value]="true" [disabled]="true" />
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## Manejo del estado
|
|
550
|
+
|
|
551
|
+
El toggle no guarda estado internamente. El padre es responsable de actualizar el valor:
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
isActive = false;
|
|
555
|
+
|
|
556
|
+
onChanged(value: boolean) {
|
|
557
|
+
this.isActive = value;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
```html
|
|
562
|
+
<toggle [value]="isActive" (changed)="onChanged($event)" />
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
O de forma inline:
|
|
566
|
+
|
|
567
|
+
```html
|
|
568
|
+
<toggle [value]="isActive" (changed)="isActive = $event" />
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Casos de uso reales
|
|
574
|
+
|
|
575
|
+
### Activar notificaciones
|
|
576
|
+
```html
|
|
577
|
+
<div class="flex items-center gap-3">
|
|
578
|
+
<toggle [value]="notificaciones" (changed)="notificaciones = $event" />
|
|
579
|
+
<span>Notificaciones</span>
|
|
580
|
+
</div>
|
|
581
|
+
|
|
582
|
+
@if(notificaciones) {
|
|
583
|
+
<p>Recibirás notificaciones de nuevos eventos.</p>
|
|
584
|
+
} @else {
|
|
585
|
+
<p>Las notificaciones están desactivadas.</p>
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Activar/desactivar un producto
|
|
590
|
+
```html
|
|
591
|
+
<div class="flex items-center gap-3">
|
|
592
|
+
<toggle [value]="producto.activo" (changed)="toggleProducto($event)" />
|
|
593
|
+
<span>{{ producto.activo ? 'Activo' : 'Inactivo' }}</span>
|
|
594
|
+
</div>
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
toggleProducto(value: boolean) {
|
|
599
|
+
this.producto.activo = value;
|
|
600
|
+
this.productoService.actualizarEstado(this.producto.id, value);
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Con disabled según permisos
|
|
605
|
+
```html
|
|
606
|
+
<toggle
|
|
607
|
+
[value]="configuracion.habilitado"
|
|
608
|
+
[disabled]="!tienePermisos"
|
|
609
|
+
(changed)="configuracion.habilitado = $event"
|
|
610
|
+
/>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
# Checkbox
|
|
615
|
+
|
|
616
|
+
Componente de selección para formularios. Permite marcar o desmarcar una opción individual. Semánticamente correcto y accesible.
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
## Instalación
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
import { CheckboxButton } from 'ten-minds-beta';
|
|
624
|
+
|
|
625
|
+
@Component({
|
|
626
|
+
imports: [CheckboxButton],
|
|
627
|
+
})
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Uso básico
|
|
633
|
+
|
|
634
|
+
```html
|
|
635
|
+
<checkbox-button [checked]="isChecked" (changed)="isChecked = $event" />
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## Inputs y Outputs
|
|
641
|
+
|
|
642
|
+
| Input | Tipo | Default | Descripción |
|
|
643
|
+
|------------|-----------|---------------|----------------------------------------------------|
|
|
644
|
+
| `checked` | `boolean` | `false` | Estado actual del checkbox |
|
|
645
|
+
| `disabled` | `boolean` | `false` | Desactiva la interacción |
|
|
646
|
+
| `label` | `string` | — | Texto descriptivo al lado del checkbox (opcional) |
|
|
647
|
+
| `id` | `string` | auto-generado | ID del input, útil para asociar labels externos |
|
|
648
|
+
|
|
649
|
+
| Output | Tipo | Descripción |
|
|
650
|
+
|-----------|-----------|--------------------------------------|
|
|
651
|
+
| `changed` | `boolean` | Emite el nuevo estado al hacer click |
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## Estados
|
|
656
|
+
|
|
657
|
+
### Default (desmarcado)
|
|
658
|
+
```html
|
|
659
|
+
<checkbox-button [checked]="false" (changed)="isChecked = $event" />
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Checked (marcado)
|
|
663
|
+
```html
|
|
664
|
+
<checkbox-button [checked]="true" (changed)="isChecked = $event" />
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### Disabled desmarcado
|
|
668
|
+
```html
|
|
669
|
+
<checkbox-button [checked]="false" [disabled]="true" />
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
### Disabled marcado
|
|
673
|
+
```html
|
|
674
|
+
<checkbox-button [checked]="true" [disabled]="true" />
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
## Con label
|
|
680
|
+
|
|
681
|
+
```html
|
|
682
|
+
<checkbox-button
|
|
683
|
+
[checked]="isChecked"
|
|
684
|
+
label="Aceptar términos y condiciones"
|
|
685
|
+
(changed)="isChecked = $event"
|
|
686
|
+
/>
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Manejo del estado
|
|
692
|
+
|
|
693
|
+
El checkbox no guarda estado internamente. El padre es responsable de actualizar el valor:
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
isChecked = false;
|
|
697
|
+
|
|
698
|
+
onChanged(value: boolean) {
|
|
699
|
+
this.isChecked = value;
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
```html
|
|
704
|
+
<checkbox-button [checked]="isChecked" (changed)="onChanged($event)" />
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
O de forma inline:
|
|
708
|
+
|
|
709
|
+
```html
|
|
710
|
+
<checkbox-button [checked]="isChecked" (changed)="isChecked = $event" />
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
---
|
|
714
|
+
|
|
715
|
+
## Casos de uso reales
|
|
716
|
+
|
|
717
|
+
### Aceptar términos
|
|
718
|
+
```html
|
|
719
|
+
<checkbox-button
|
|
720
|
+
[checked]="aceptaTerminos"
|
|
721
|
+
label="Acepto los términos y condiciones"
|
|
722
|
+
(changed)="aceptaTerminos = $event"
|
|
723
|
+
/>
|
|
724
|
+
|
|
725
|
+
<btn-primary
|
|
726
|
+
[disabled]="!aceptaTerminos"
|
|
727
|
+
type="filled"
|
|
728
|
+
(clicked)="continuar()"
|
|
729
|
+
>
|
|
730
|
+
Continuar
|
|
731
|
+
</btn-primary>
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Lista de permisos
|
|
735
|
+
```html
|
|
736
|
+
@for(permiso of permisos; track permiso.id) {
|
|
737
|
+
<checkbox-button
|
|
738
|
+
[checked]="permiso.activo"
|
|
739
|
+
[label]="permiso.nombre"
|
|
740
|
+
(changed)="togglePermiso(permiso.id, $event)"
|
|
741
|
+
/>
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
togglePermiso(id: string, value: boolean) {
|
|
747
|
+
const permiso = this.permisos.find(p => p.id === id);
|
|
748
|
+
if (permiso) permiso.activo = value;
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### Con disabled según permisos
|
|
753
|
+
```html
|
|
754
|
+
<checkbox-button
|
|
755
|
+
[checked]="opcion.activa"
|
|
756
|
+
[disabled]="!tienePermisos"
|
|
757
|
+
[label]="opcion.nombre"
|
|
758
|
+
(changed)="opcion.activa = $event"
|
|
759
|
+
/>
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
# Radio Button
|
|
764
|
+
|
|
765
|
+
Componente de selección única para formularios. Se usa en grupos donde solo una opción puede estar seleccionada a la vez.
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Instalación
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
import { RadioButton } from 'ten-minds-beta';
|
|
773
|
+
|
|
774
|
+
@Component({
|
|
775
|
+
imports: [RadioButton],
|
|
776
|
+
})
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
## Uso básico
|
|
782
|
+
|
|
783
|
+
```html
|
|
784
|
+
<radio-button
|
|
785
|
+
value="opcion1"
|
|
786
|
+
name="mi-grupo"
|
|
787
|
+
[checked]="selected === 'opcion1'"
|
|
788
|
+
(changed)="selected = $event"
|
|
789
|
+
/>
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
---
|
|
793
|
+
|
|
794
|
+
## Inputs y Outputs
|
|
795
|
+
|
|
796
|
+
| Input | Tipo | Default | Descripción |
|
|
797
|
+
|------------|-----------|-----------------|----------------------------------------------------------|
|
|
798
|
+
| `value` | `string` | requerido | Valor que emite cuando se selecciona |
|
|
799
|
+
| `name` | `string` | `'radio-group'` | Nombre del grupo, debe ser igual en todos los del grupo |
|
|
800
|
+
| `checked` | `boolean` | `false` | Estado actual del radio |
|
|
801
|
+
| `disabled` | `boolean` | `false` | Desactiva la interacción |
|
|
802
|
+
| `label` | `string` | — | Texto descriptivo al lado del radio (opcional) |
|
|
803
|
+
| `id` | `string` | auto-generado | ID del input, útil para asociar labels externos |
|
|
804
|
+
|
|
805
|
+
| Output | Tipo | Descripción |
|
|
806
|
+
|-----------|----------|------------------------------------------|
|
|
807
|
+
| `changed` | `string` | Emite el `value` del radio seleccionado |
|
|
808
|
+
|
|
809
|
+
---
|
|
810
|
+
|
|
811
|
+
## Estados
|
|
812
|
+
|
|
813
|
+
### Default (sin seleccionar)
|
|
814
|
+
```html
|
|
815
|
+
<radio-button value="opcion1" name="grupo" [checked]="false" (changed)="onChanged($event)" />
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### Checked (seleccionado)
|
|
819
|
+
```html
|
|
820
|
+
<radio-button value="opcion1" name="grupo" [checked]="true" (changed)="onChanged($event)" />
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### Disabled desmarcado
|
|
824
|
+
```html
|
|
825
|
+
<radio-button value="opcion1" name="grupo" [checked]="false" [disabled]="true" />
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
### Disabled marcado
|
|
829
|
+
```html
|
|
830
|
+
<radio-button value="opcion1" name="grupo" [checked]="true" [disabled]="true" />
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
## Uso en grupo
|
|
836
|
+
|
|
837
|
+
El `name` debe ser el mismo en todos los radio del grupo. El padre controla cuál está seleccionado comparando `value` con el valor actual:
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
selected = 'mensual';
|
|
841
|
+
|
|
842
|
+
onChanged(value: string) {
|
|
843
|
+
this.selected = value;
|
|
844
|
+
}
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
```html
|
|
848
|
+
<div class="flex flex-col gap-3">
|
|
849
|
+
<radio-button
|
|
850
|
+
value="mensual"
|
|
851
|
+
name="plan"
|
|
852
|
+
label="Mensual"
|
|
853
|
+
[checked]="selected === 'mensual'"
|
|
854
|
+
(changed)="onChanged($event)"
|
|
855
|
+
/>
|
|
856
|
+
<radio-button
|
|
857
|
+
value="anual"
|
|
858
|
+
name="plan"
|
|
859
|
+
label="Anual"
|
|
860
|
+
[checked]="selected === 'anual'"
|
|
861
|
+
(changed)="onChanged($event)"
|
|
862
|
+
/>
|
|
863
|
+
<radio-button
|
|
864
|
+
value="lifetime"
|
|
865
|
+
name="plan"
|
|
866
|
+
label="De por vida"
|
|
867
|
+
[checked]="selected === 'lifetime'"
|
|
868
|
+
(changed)="onChanged($event)"
|
|
869
|
+
/>
|
|
870
|
+
</div>
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
---
|
|
874
|
+
|
|
875
|
+
## Casos de uso reales
|
|
876
|
+
|
|
877
|
+
### Selección de plan
|
|
878
|
+
```html
|
|
879
|
+
<div class="flex flex-col gap-3">
|
|
880
|
+
@for(plan of planes; track plan.id) {
|
|
881
|
+
<radio-button
|
|
882
|
+
[value]="plan.id"
|
|
883
|
+
name="planes"
|
|
884
|
+
[label]="plan.nombre"
|
|
885
|
+
[checked]="selectedPlan === plan.id"
|
|
886
|
+
(changed)="selectedPlan = $event"
|
|
887
|
+
/>
|
|
888
|
+
}
|
|
889
|
+
</div>
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### Con opción desactivada
|
|
893
|
+
```html
|
|
894
|
+
<radio-button
|
|
895
|
+
value="premium"
|
|
896
|
+
name="plan"
|
|
897
|
+
label="Premium (próximamente)"
|
|
898
|
+
[checked]="false"
|
|
899
|
+
[disabled]="true"
|
|
900
|
+
/>
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### Selección de rol en formulario de usuario
|
|
904
|
+
```html
|
|
905
|
+
<div class="flex flex-col gap-3">
|
|
906
|
+
<radio-button value="admin" name="rol" label="Administrador" [checked]="rol === 'admin'" (changed)="rol = $event" />
|
|
907
|
+
<radio-button value="editor" name="rol" label="Editor" [checked]="rol === 'editor'" (changed)="rol = $event" />
|
|
908
|
+
<radio-button value="viewer" name="rol" label="Solo lectura" [checked]="rol === 'viewer'" (changed)="rol = $event" />
|
|
909
|
+
</div>
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
```typescript
|
|
913
|
+
rol = 'viewer';
|
|
914
|
+
```
|