shirkasoft-ui-components 1.0.21 → 1.0.23
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
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
# Shirkasoft UI Components
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
Creado por <a href="https://shirkasoft.com" target="_blank"><strong>Shirkasoft</strong></a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Librería de componentes UI para Angular 21+ con **Tailwind CSS**, **standalone components**, señales (Angular signals) y soporte de **tema claro/oscuro** mediante CSS custom properties.
|
|
8
|
+
|
|
9
|
+
## Instalación
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add shirkasoft-ui-components
|
|
13
|
+
# o
|
|
14
|
+
npm install shirkasoft-ui-components
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Dependencias pares
|
|
18
|
+
|
|
19
|
+
| Paquete | Versión mínima |
|
|
20
|
+
|---|---|
|
|
21
|
+
| @angular/common | ^21.2.0 |
|
|
22
|
+
| @angular/core | ^21.2.0 |
|
|
23
|
+
| @angular/forms | ^21.2.0 |
|
|
24
|
+
| rxjs | ^7.8.0 |
|
|
25
|
+
| @jsverse/transloco | >= 8.0.0 |
|
|
26
|
+
| @lucide/angular | ^1.17.0 |
|
|
27
|
+
| chart.js | ^4.4.0 |
|
|
28
|
+
|
|
29
|
+
## Configuración del tema
|
|
30
|
+
|
|
31
|
+
Importar el tema en `styles.css` global:
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@import '@shirkasoft/ui-components/theme.css';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
El tema se basa en variables CSS `--shk-*`. Para personalizar colores, sobrescribí las variables en `:root` (modo claro) y `.dark` (modo oscuro):
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
:root {
|
|
41
|
+
--shk-primary-500: #3b82f6;
|
|
42
|
+
--shk-primary-600: #2563eb;
|
|
43
|
+
/* ... */
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Dark mode
|
|
48
|
+
|
|
49
|
+
Agregá la clase `dark` al elemento `<html>` para activar el modo oscuro.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
document.documentElement.classList.toggle('dark');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Componentes
|
|
58
|
+
|
|
59
|
+
| # | Componente | Selector | ControlValueAccessor | Servicio asociado |
|
|
60
|
+
|---|---|---|---|---|
|
|
61
|
+
| 1 | TextField | `shk-text-field` | ✅ | — |
|
|
62
|
+
| 2 | Toggle | `shk-toggle` | ✅ | — |
|
|
63
|
+
| 3 | Select | `shk-select` | ✅ | — |
|
|
64
|
+
| 4 | DatePicker | `shk-date-picker` | ✅ | — |
|
|
65
|
+
| 5 | PriceInput | `shk-price-input` | — | — |
|
|
66
|
+
| 6 | FileUpload | `shk-file-upload` | — | — |
|
|
67
|
+
| 7 | Table | `shk-table` | — | — |
|
|
68
|
+
| 8 | Modal | `shk-modal` | — | `ModalService` |
|
|
69
|
+
| 9 | Notification | `shk-notification` | — | `NotificationService` |
|
|
70
|
+
| 10 | ConfirmDialog | `shk-confirm-dialog` | — | `ConfirmDialogService` |
|
|
71
|
+
| 11 | Chart | `shk-chart` | — | — |
|
|
72
|
+
| 12 | Tooltip | `shk-tooltip` | — | — |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### TextField (`shk-text-field`)
|
|
77
|
+
|
|
78
|
+
Campo de texto con soporte para input, textarea, password, búsqueda, formato de tarjeta de crédito, y validación de errores. Implementa `ControlValueAccessor`.
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<shk-text-field
|
|
82
|
+
[label]="'Nombre'"
|
|
83
|
+
[control]="myControl"
|
|
84
|
+
[type]="'text'"
|
|
85
|
+
[placeholder]="'Ingresá tu nombre'"
|
|
86
|
+
[disabled]="false"
|
|
87
|
+
[errorMessages]="{ required: 'Campo obligatorio' }"
|
|
88
|
+
[isTextArea]="false"
|
|
89
|
+
[searchMode]="false"
|
|
90
|
+
(searchButtonClick)="onSearch()"
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Input | Tipo | Default |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `id` | `string` | `''` |
|
|
97
|
+
| `label` | `string` | `''` |
|
|
98
|
+
| `type` | `string` | `'text'` |
|
|
99
|
+
| `placeholder` | `string` | `''` |
|
|
100
|
+
| `disabled` | `boolean` | `false` |
|
|
101
|
+
| `control` | `FormControl` | `undefined` |
|
|
102
|
+
| `formGroup` | `FormGroup` | `undefined` |
|
|
103
|
+
| `errorMessage` | `string` | `''` |
|
|
104
|
+
| `errorMessages` | `{ [key: string]: string }` | `{}` |
|
|
105
|
+
| `isTextArea` | `boolean` | `false` |
|
|
106
|
+
| `textAreaHeight` | `string` | `'h-28'` |
|
|
107
|
+
| `searchMode` | `boolean` | `false` |
|
|
108
|
+
| `searchButtonClick` | `output<void>` | — |
|
|
109
|
+
| `numbersOnly` | `boolean` | `false` |
|
|
110
|
+
| `allowDecimals` | `boolean` | `false` |
|
|
111
|
+
| `maxLength` | `number` | `undefined` |
|
|
112
|
+
| `formatCard` | `boolean` | `false` |
|
|
113
|
+
| `preventNegative` | `boolean` | `false` |
|
|
114
|
+
| `displayValue` | `string` | `''` |
|
|
115
|
+
| `autocomplete` | `string` | `'new-password'` |
|
|
116
|
+
|
|
117
|
+
> También expone `inputElement` y `textareaElement` como `viewChild`.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Toggle (`shk-toggle`)
|
|
122
|
+
|
|
123
|
+
Switch o checkbox. Implementa `ControlValueAccessor`.
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<shk-toggle
|
|
127
|
+
[label]="'Activar notificaciones'"
|
|
128
|
+
[mode]="'toggle'"
|
|
129
|
+
[(checked)]="isChecked"
|
|
130
|
+
(checkedChange)="onChange($event)"
|
|
131
|
+
/>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
| Input | Tipo | Default |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `label` | `string` | `''` |
|
|
137
|
+
| `mode` | `'toggle' \| 'checkbox'` | `'toggle'` |
|
|
138
|
+
| `checked` | `boolean` | `undefined` |
|
|
139
|
+
|
|
140
|
+
| Output | Tipo |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `checkedChange` | `boolean` |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### Select (`shk-select`)
|
|
147
|
+
|
|
148
|
+
Dropdown seleccionable con búsqueda, paginación, selección múltiple, opciones personalizadas y validación. Implementa `ControlValueAccessor`.
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<shk-select
|
|
152
|
+
[options]="options"
|
|
153
|
+
[label]="'País'"
|
|
154
|
+
[control]="countryControl"
|
|
155
|
+
[multiple]="false"
|
|
156
|
+
[isSearchable]="true"
|
|
157
|
+
[usePagination]="true"
|
|
158
|
+
[itemsPerPage]="10"
|
|
159
|
+
[allowCustomEntries]="false"
|
|
160
|
+
[placeholder]="'Seleccionar...'"
|
|
161
|
+
[isLoading]="false"
|
|
162
|
+
(selectionChange)="onSelect($event)"
|
|
163
|
+
(search)="onSearch($event)"
|
|
164
|
+
/>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
interface SelectOption {
|
|
169
|
+
label: string;
|
|
170
|
+
value: any;
|
|
171
|
+
custom?: boolean;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Input | Tipo | Default |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `options` | `SelectOption[]` | `[]` |
|
|
178
|
+
| `label` | `string` | `undefined` |
|
|
179
|
+
| `placeholder` | `string` | `'Seleccionar...'` |
|
|
180
|
+
| `disabled` | `boolean` | `false` |
|
|
181
|
+
| `control` | `FormControl` | `undefined` |
|
|
182
|
+
| `formGroup` | `FormGroup` | `undefined` |
|
|
183
|
+
| `multiple` | `boolean` | `false` |
|
|
184
|
+
| `isSearchable` | `boolean` | `false` |
|
|
185
|
+
| `usePagination` | `boolean` | `false` |
|
|
186
|
+
| `itemsPerPage` | `number` | `10` |
|
|
187
|
+
| `allowCustomEntries` | `boolean` | `false` |
|
|
188
|
+
| `isLoading` | `boolean` | `false` |
|
|
189
|
+
| `isAllDataLoaded` | `boolean` | `false` |
|
|
190
|
+
| `preserveSearchOnLoad` | `boolean` | `false` |
|
|
191
|
+
| `dropdownUpward` | `boolean` | `false` |
|
|
192
|
+
| `showEmptyOption` | `boolean` | `true` |
|
|
193
|
+
| `emptyMessageKey` | `string` | `'common.no_records'` |
|
|
194
|
+
| `validCombinations` | `string[][]` | `undefined` |
|
|
195
|
+
| `errorMessages` | `{ [key: string]: string }` | `{ required: 'Este campo es requerido' }` |
|
|
196
|
+
|
|
197
|
+
| Output | Tipo |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `selectionChange` | `any` |
|
|
200
|
+
| `search` | `string` |
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### DatePicker (`shk-date-picker`)
|
|
205
|
+
|
|
206
|
+
Selector de fecha, mes o año. Implementa `ControlValueAccessor`. Soporta formatos `'date'`, `'month'`, `'year'`.
|
|
207
|
+
|
|
208
|
+
```html
|
|
209
|
+
<shk-date-picker
|
|
210
|
+
[label]="'Fecha de inicio'"
|
|
211
|
+
[control]="dateControl"
|
|
212
|
+
[view]="'date'"
|
|
213
|
+
[locale]="'es'"
|
|
214
|
+
[minValue]="'2024-01-01'"
|
|
215
|
+
[maxValue]="'2026-12-31'"
|
|
216
|
+
/>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
| Input | Tipo | Default |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `id` | `string` | `''` |
|
|
222
|
+
| `label` | `string` | `''` |
|
|
223
|
+
| `placeholder` | `string` | `''` |
|
|
224
|
+
| `view` | `'date' \| 'month' \| 'year'` | `'date'` |
|
|
225
|
+
| `control` | `FormControl` | `undefined` |
|
|
226
|
+
| `formGroup` | `FormGroup` | `undefined` |
|
|
227
|
+
| `disabled` | `boolean` | `false` |
|
|
228
|
+
| `errorMessage` | `string` | `''` |
|
|
229
|
+
| `errorMessages` | `{ [key: string]: string }` | `{}` |
|
|
230
|
+
| `minValue` | `string` | `''` |
|
|
231
|
+
| `maxValue` | `string` | `''` |
|
|
232
|
+
| `locale` | `string` | `'es'` |
|
|
233
|
+
|
|
234
|
+
**Valor devuelto** según el `view`:
|
|
235
|
+
- `'date'` → `'YYYY-MM-DD'`
|
|
236
|
+
- `'month'` → `'YYYY-MM'`
|
|
237
|
+
- `'year'` → `'YYYY'`
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### PriceInput (`shk-price-input`
|
|
242
|
+
|
|
243
|
+
Input numérico con toggle entre modo monto (`$`) y porcentaje (`%`). Usa `model()` para doble vinculación.
|
|
244
|
+
|
|
245
|
+
```html
|
|
246
|
+
<shk-price-input
|
|
247
|
+
[(value)]="price"
|
|
248
|
+
[(isPercentage)]="isPercent"
|
|
249
|
+
[label]="'Precio'"
|
|
250
|
+
[min]="0"
|
|
251
|
+
[max]="10000"
|
|
252
|
+
[required]="true"
|
|
253
|
+
[showError]="hasError"
|
|
254
|
+
[errorMessage]="'Valor inválido'"
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
| Input | Tipo | Default |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| `value` | `model<number>` | **required** |
|
|
261
|
+
| `isPercentage` | `model<boolean>` | `false` |
|
|
262
|
+
| `label` | `string` | `''` |
|
|
263
|
+
| `inputId` | `string` | `''` |
|
|
264
|
+
| `required` | `boolean` | `false` |
|
|
265
|
+
| `disabled` | `boolean` | `false` |
|
|
266
|
+
| `min` | `number` | `0` |
|
|
267
|
+
| `max` | `number` | `Infinity` |
|
|
268
|
+
| `showError` | `boolean` | `false` |
|
|
269
|
+
| `errorMessage` | `string` | `''` |
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
### FileUpload (`shk-file-upload`)
|
|
274
|
+
|
|
275
|
+
Subida de archivos con arrastrar y soltar, vista previa de imágenes, validación de tipo y tamaño.
|
|
276
|
+
|
|
277
|
+
```html
|
|
278
|
+
<shk-file-upload
|
|
279
|
+
[label]="'Subí tu foto'"
|
|
280
|
+
[accept]="'image/*'"
|
|
281
|
+
[maxFileSize]="5 * 1024 * 1024"
|
|
282
|
+
[maxFiles]="3"
|
|
283
|
+
[multiple]="true"
|
|
284
|
+
(fileSelected)="onFilesSelected($event)"
|
|
285
|
+
(fileRemoved)="onFileRemoved()"
|
|
286
|
+
(fileError)="onFileError($event)"
|
|
287
|
+
/>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
interface FileUploadError {
|
|
292
|
+
type: 'size' | 'type';
|
|
293
|
+
message: string;
|
|
294
|
+
file: File;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
| Input | Tipo | Default |
|
|
299
|
+
|---|---|---|
|
|
300
|
+
| `label` | `string` | `'Cargar archivo'` |
|
|
301
|
+
| `accept` | `string` | `'image/*'` |
|
|
302
|
+
| `maxFileSize` | `number` | `2 * 1024 * 1024` (2MB) |
|
|
303
|
+
| `maxFiles` | `number` | `0` (sin límite) |
|
|
304
|
+
| `multiple` | `boolean` | `false` |
|
|
305
|
+
| `fileUploadText` | `string` | `'Seleccionar archivo'` |
|
|
306
|
+
| `changeFilesText` | `string` | `'Cambiar archivos'` |
|
|
307
|
+
| `fileRecommendation` | `string` | `''` |
|
|
308
|
+
|
|
309
|
+
| Output | Tipo |
|
|
310
|
+
|---|---|
|
|
311
|
+
| `fileSelected` | `File[]` |
|
|
312
|
+
| `fileRemoved` | `void` |
|
|
313
|
+
| `fileError` | `FileUploadError` |
|
|
314
|
+
| `fileWarning` | `FileUploadError` |
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### Table (`shk-table`)
|
|
319
|
+
|
|
320
|
+
Tabla de datos con ordenamiento, filtros por columna, búsqueda global, paginación, acciones por fila y acciones de cabecera. Soporta modo cliente y servidor.
|
|
321
|
+
|
|
322
|
+
```html
|
|
323
|
+
<shk-table
|
|
324
|
+
[data]="users"
|
|
325
|
+
[columns]="columns"
|
|
326
|
+
[loading]="isLoading"
|
|
327
|
+
[serverSide]="true"
|
|
328
|
+
[totalRecords]="totalUsers"
|
|
329
|
+
[rowActions]="rowActions"
|
|
330
|
+
[headerActions]="headerActions"
|
|
331
|
+
[rowsPerPage]="25"
|
|
332
|
+
[showSearch]="true"
|
|
333
|
+
(pageChange)="onPageChange($event)"
|
|
334
|
+
(searchChange)="onSearch($event)"
|
|
335
|
+
(refresh)="loadData()"
|
|
336
|
+
/>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
interface Column {
|
|
341
|
+
field: string;
|
|
342
|
+
header: string;
|
|
343
|
+
sortable?: boolean;
|
|
344
|
+
filter?: boolean;
|
|
345
|
+
filterPlaceholder?: string;
|
|
346
|
+
width?: string;
|
|
347
|
+
defaultSort?: true;
|
|
348
|
+
filterType?: 'text' | 'exact' | 'select';
|
|
349
|
+
filterOptions?: { label: string; value: any }[];
|
|
350
|
+
template?: 'text' | 'tag';
|
|
351
|
+
format?: (row: any) => string;
|
|
352
|
+
tagValue?: (row: any) => string;
|
|
353
|
+
tagSeverity?: (row: any) => 'success' | 'danger' | 'warn' | 'info' | undefined;
|
|
354
|
+
tagStyle?: (row: any) => { [key: string]: string } | undefined;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface TableAction {
|
|
358
|
+
label: string;
|
|
359
|
+
icon: string;
|
|
360
|
+
onClick: () => void;
|
|
361
|
+
class?: string;
|
|
362
|
+
isVisible?: () => boolean;
|
|
363
|
+
isDisabled?: () => boolean;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
interface RowAction {
|
|
367
|
+
label: string | ((data: any) => string);
|
|
368
|
+
icon: string | ((data: any) => string);
|
|
369
|
+
onClick: (rowData: any) => void;
|
|
370
|
+
class?: string | ((data: any) => string);
|
|
371
|
+
isVisible?: (rowData: any) => boolean;
|
|
372
|
+
isDisabled?: (rowData: any) => boolean;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
interface PageChangeEvent {
|
|
376
|
+
first: number;
|
|
377
|
+
rows: number;
|
|
378
|
+
page: number;
|
|
379
|
+
pageCount: number;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
interface FilterChangeEvent {
|
|
383
|
+
filters: { [key: string]: any };
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
| Input | Tipo | Default |
|
|
388
|
+
|---|---|---|
|
|
389
|
+
| `data` | `any[]` | `[]` |
|
|
390
|
+
| `columns` | `Column[]` | `[]` |
|
|
391
|
+
| `rowsPerPage` | `number` | `10` |
|
|
392
|
+
| `rowsPerPageOptions` | `number[]` | `[10, 25, 50]` |
|
|
393
|
+
| `loading` | `boolean` | `false` |
|
|
394
|
+
| `showActionRow` | `boolean` | `true` |
|
|
395
|
+
| `headerActions` | `TableAction[]` | `[]` |
|
|
396
|
+
| `rowActions` | `RowAction[]` | `[]` |
|
|
397
|
+
| `hasShadow` | `boolean` | `true` |
|
|
398
|
+
| `defaultSortField` | `string` | `''` |
|
|
399
|
+
| `defaultSortOrder` | `number` | `1` |
|
|
400
|
+
| `showSearch` | `boolean` | `true` |
|
|
401
|
+
| `searchPlaceholder` | `string` | `''` |
|
|
402
|
+
| `emptyMessage` | `string` | `''` |
|
|
403
|
+
| `serverSide` | `boolean` | `false` |
|
|
404
|
+
| `totalRecords` | `number` | `0` |
|
|
405
|
+
| `filters` | `{ label: string; value: string }[]` | `[]` |
|
|
406
|
+
| `activeFilter` | `string` | `''` |
|
|
407
|
+
| `customTemplates` | `{ [key: string]: any }` | `{}` |
|
|
408
|
+
|
|
409
|
+
| Output | Tipo |
|
|
410
|
+
|---|---|
|
|
411
|
+
| `pageChange` | `PageChangeEvent` |
|
|
412
|
+
| `filterChange` | `FilterChangeEvent` |
|
|
413
|
+
| `searchChange` | `string` |
|
|
414
|
+
| `filterClick` | `string` |
|
|
415
|
+
| `refresh` | `void` |
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Modal (`shk-modal`)
|
|
420
|
+
|
|
421
|
+
Modal dinámico que carga componentes a partir de un `ModalService`. Soporta formularios, expansión a pantalla completa y botones de aceptar/cancelar.
|
|
422
|
+
|
|
423
|
+
```html
|
|
424
|
+
<shk-modal />
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
interface ModalConfig {
|
|
429
|
+
title: string;
|
|
430
|
+
component: Type<any>;
|
|
431
|
+
data?: Record<string, any>;
|
|
432
|
+
width?: string;
|
|
433
|
+
showButtons?: boolean;
|
|
434
|
+
showExpandButton?: boolean;
|
|
435
|
+
acceptLabel?: string;
|
|
436
|
+
cancelLabel?: string;
|
|
437
|
+
onClose?: () => void;
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
El componente inyectado **debe** exponer:
|
|
442
|
+
- `form?: FormGroup` (opcional, para validación)
|
|
443
|
+
- `onSubmit()` → llama `submitSuccess` o `submitError`
|
|
444
|
+
- `submitSuccess?: EventEmitter<void>` (opcional)
|
|
445
|
+
- `submitError?: EventEmitter<void>` (opcional)
|
|
446
|
+
- `handleCancel?: () => void` (opcional)
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
constructor(private modalSrv: ModalService) {}
|
|
450
|
+
|
|
451
|
+
openModal() {
|
|
452
|
+
this.modalSrv.open({
|
|
453
|
+
title: 'Editar usuario',
|
|
454
|
+
component: EditUserComponent,
|
|
455
|
+
data: { userId: 123 },
|
|
456
|
+
width: '600px',
|
|
457
|
+
showButtons: true,
|
|
458
|
+
showExpandButton: true,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
closeModal() {
|
|
463
|
+
this.modalSrv.close();
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Métodos del servicio:**
|
|
468
|
+
|
|
469
|
+
| Método | Descripción |
|
|
470
|
+
|---|---|
|
|
471
|
+
| `open(config: ModalConfig)` | Abre un nuevo modal |
|
|
472
|
+
| `close()` | Cierra el modal actual |
|
|
473
|
+
| `accept()` | Cierra el modal (alias de close) |
|
|
474
|
+
| `clear()` | Cierra todos los modales |
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
### Notification (`shk-notification`)
|
|
479
|
+
|
|
480
|
+
Sistema de notificaciones toast con posiciones configurables y barra de progreso opcional.
|
|
481
|
+
|
|
482
|
+
```html
|
|
483
|
+
<shk-notification position="right-top" />
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
interface Notification {
|
|
488
|
+
id: string;
|
|
489
|
+
message: string;
|
|
490
|
+
type: 'success' | 'error' | 'warning' | 'info';
|
|
491
|
+
progress?: number;
|
|
492
|
+
showProgress?: boolean;
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
constructor(private notifSrv: NotificationService) {}
|
|
498
|
+
|
|
499
|
+
showNotif() {
|
|
500
|
+
const id = this.notifSrv.addNotification(
|
|
501
|
+
'Operación exitosa',
|
|
502
|
+
'success',
|
|
503
|
+
false, // showProgress
|
|
504
|
+
3000 // duration (ms)
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
updateProgress(id: string, progress: number) {
|
|
509
|
+
this.notifSrv.updateProgress(id, progress);
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
| Input | Tipo | Default |
|
|
514
|
+
|---|---|---|
|
|
515
|
+
| `position` | `'center-top' \| 'right-top' \| 'left-top'` | `'center-top'` |
|
|
516
|
+
|
|
517
|
+
**Métodos del servicio:**
|
|
518
|
+
|
|
519
|
+
| Método | Descripción |
|
|
520
|
+
|---|---|
|
|
521
|
+
| `addNotification(msg, type?, showProgress?, duration?)` | Agrega una notificación |
|
|
522
|
+
| `updateProgress(id, progress)` | Actualiza la barra de progreso |
|
|
523
|
+
| `removeNotification(notification)` | Elimina una notificación |
|
|
524
|
+
| `removeNotificationById(id)` | Elimina por ID |
|
|
525
|
+
| `clearAll()` | Elimina todas las notificaciones |
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
### ConfirmDialog (`shk-confirm-dialog`)
|
|
530
|
+
|
|
531
|
+
Diálogo de confirmación programático. Se usa a través del `ConfirmDialogService` que lo crea dinámicamente.
|
|
532
|
+
|
|
533
|
+
```html
|
|
534
|
+
<!-- No hace falta agregarlo al template -->
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
interface ConfirmConfig {
|
|
539
|
+
title?: string;
|
|
540
|
+
message: string;
|
|
541
|
+
confirmLabel?: string;
|
|
542
|
+
cancelLabel?: string;
|
|
543
|
+
loadingText?: string;
|
|
544
|
+
type?: 'danger' | 'info' | 'warning';
|
|
545
|
+
showCancel?: boolean;
|
|
546
|
+
loading?: boolean;
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
constructor(private confirmSrv: ConfirmDialogService) {}
|
|
552
|
+
|
|
553
|
+
async deleteItem() {
|
|
554
|
+
const confirmed = await this.confirmSrv.confirm({
|
|
555
|
+
title: 'Eliminar usuario',
|
|
556
|
+
message: '¿Estás seguro de eliminar este usuario?',
|
|
557
|
+
confirmLabel: 'Eliminar',
|
|
558
|
+
type: 'danger',
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
if (confirmed) {
|
|
562
|
+
// proceder con la eliminación
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
| Input | Tipo | Default |
|
|
568
|
+
|---|---|---|
|
|
569
|
+
| `title` | `string` | `'Confirmar acción'` |
|
|
570
|
+
| `message` | `string` | `'¿Está seguro de realizar esta acción?'` |
|
|
571
|
+
| `confirmLabel` | `string` | `'Confirmar'` |
|
|
572
|
+
| `cancelLabel` | `string` | `'Cancelar'` |
|
|
573
|
+
| `loadingText` | `string` | `'Procesando…'` |
|
|
574
|
+
| `type` | `'danger' \| 'info' \| 'warning'` | `'danger'` |
|
|
575
|
+
| `loading` | `boolean` | `false` |
|
|
576
|
+
| `showCancel` | `boolean` | `true` |
|
|
577
|
+
|
|
578
|
+
| Output | Tipo |
|
|
579
|
+
|---|---|
|
|
580
|
+
| `closed` | `void` |
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
### Chart (`shk-chart`)
|
|
585
|
+
|
|
586
|
+
Wrapper de Chart.js que soporta los tipos de gráfico principales.
|
|
587
|
+
|
|
588
|
+
```html
|
|
589
|
+
<shk-chart
|
|
590
|
+
[type]="'bar'"
|
|
591
|
+
[data]="chartData"
|
|
592
|
+
[options]="chartOptions"
|
|
593
|
+
/>
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
import { COLOR_PALETTE, readThemeColors } from 'shirkasoft-ui-components';
|
|
598
|
+
|
|
599
|
+
const colors = readThemeColors(); // colores del tema actual
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
| Input | Tipo | Default |
|
|
603
|
+
|---|---|---|
|
|
604
|
+
| `type` | `'line' \| 'bar' \| 'pie' \| 'doughnut' \| 'polarArea'` | `'bar'` |
|
|
605
|
+
| `data` | `any` | `{ datasets: [] }` |
|
|
606
|
+
| `options` | `any` | `{}` |
|
|
607
|
+
|
|
608
|
+
**Utils exportadas:**
|
|
609
|
+
|
|
610
|
+
| Export | Descripción |
|
|
611
|
+
|---|---|
|
|
612
|
+
| `COLOR_PALETTE` | Array de colores predefinidos (bg + border) |
|
|
613
|
+
| `readThemeColors()` | Lee colores del tema actual (`--shk-surface-*`) |
|
|
614
|
+
|
|
615
|
+
---
|
|
616
|
+
|
|
617
|
+
### Tooltip (`shk-tooltip`)
|
|
618
|
+
|
|
619
|
+
Tooltip con dos modos: `hover` (posicionamiento CSS) y `fixed` (posicionamiento calculado con JS).
|
|
620
|
+
|
|
621
|
+
```html
|
|
622
|
+
<shk-tooltip [text]="'Info adicional'" [position]="'bottom'" [mode]="'hover'">
|
|
623
|
+
<button>Pasar el mouse</button>
|
|
624
|
+
</shk-tooltip>
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
| Input | Tipo | Default |
|
|
628
|
+
|---|---|---|
|
|
629
|
+
| `text` | `string` | `''` |
|
|
630
|
+
| `position` | `'top' \| 'bottom' \| 'right'` | `'bottom'` |
|
|
631
|
+
| `mode` | `'hover' \| 'fixed'` | `'hover'` |
|
|
632
|
+
| `offset` | `number` | `8` |
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## Desarrollo
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
# Construir la librería
|
|
640
|
+
pnpm build
|
|
641
|
+
|
|
642
|
+
# Servir la showcase (app de demostración)
|
|
643
|
+
pnpm serve
|
|
644
|
+
|
|
645
|
+
# Construir la showcase
|
|
646
|
+
pnpm build:showcase
|
|
647
|
+
|
|
648
|
+
# Escuchar cambios en la librería
|
|
649
|
+
pnpm watch
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Versionado
|
|
653
|
+
|
|
654
|
+
```bash
|
|
655
|
+
pnpm version:patch # 1.0.22 → 1.0.23
|
|
656
|
+
pnpm version:minor # 1.0.22 → 1.1.0
|
|
657
|
+
pnpm version:major # 1.0.22 → 2.0.0
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## Publicación
|
|
663
|
+
|
|
664
|
+
CI/CD vía GitHub Actions:
|
|
665
|
+
- Al pushear un tag `v*` se publica a npm automáticamente.
|
|
666
|
+
- Al pushear a `main`/`master` se despliega la showcase a GitHub Pages.
|
|
667
|
+
|
|
668
|
+
Manual:
|
|
669
|
+
|
|
670
|
+
```bash
|
|
671
|
+
bash scripts/publish-lib.sh
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## Licencia
|
|
677
|
+
|
|
678
|
+
MIT © Shirkasoft
|