shirkasoft-ui-components 1.0.23 → 1.0.26

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 CHANGED
@@ -1,40 +1,48 @@
1
1
  # Shirkasoft UI Components
2
2
 
3
3
  <p align="center">
4
- Creado por <a href="https://shirkasoft.com" target="_blank"><strong>Shirkasoft</strong></a>
4
+ <a href="https://github.com/Ansem13/shirkasoft-ui-components/releases"><img src="https://img.shields.io/npm/v/shirkasoft-ui-components?style=flat&logo=npm&label=version" alt="npm version" /></a>
5
+ <a href="https://github.com/Ansem13/shirkasoft-ui-components/issues"><img src="https://img.shields.io/github/issues/Ansem13/shirkasoft-ui-components?style=flat&logo=github" alt="GitHub issues" /></a>
6
+ <a href="https://github.com/Ansem13/shirkasoft-ui-components"><img src="https://img.shields.io/badge/source-github-181717?style=flat&logo=github" alt="GitHub source" /></a>
7
+ <a href="https://ansem13.github.io/shirkasoft-ui-components/"><img src="https://img.shields.io/badge/showcase-online-10b981?style=flat&logo=githubpages" alt="Showcase" /></a>
5
8
  </p>
6
9
 
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.
10
+ <p align="center">
11
+ Created by <a href="https://shirkasoft.com" target="_blank"><strong>Shirkasoft</strong></a>
12
+ </p>
13
+
14
+ Angular 21+ UI components library built with **Tailwind CSS**, **standalone components**, **Angular signals**, and **light/dark theme** support via CSS custom properties.
8
15
 
9
- ## Instalación
16
+ ## Installation
10
17
 
11
18
  ```bash
12
19
  pnpm add shirkasoft-ui-components
13
- # o
20
+ # or
14
21
  npm install shirkasoft-ui-components
15
22
  ```
16
23
 
17
- ### Dependencias pares
24
+ ### Peer Dependencies
18
25
 
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 |
26
+ | Package | Minimum version |
27
+ | ------------------ | --------------- |
28
+ | @angular/common | ^21.2.0 |
29
+ | @angular/core | ^21.2.0 |
30
+ | @angular/forms | ^21.2.0 |
31
+ | @angular/router | ^21.2.0 |
32
+ | rxjs | ^7.8.0 |
33
+ | @jsverse/transloco | >= 8.0.0 |
34
+ | @lucide/angular | ^1.17.0 |
35
+ | chart.js | ^4.4.0 |
28
36
 
29
- ## Configuración del tema
37
+ ## Theme Setup
30
38
 
31
- Importar el tema en `styles.css` global:
39
+ Import the theme in your global `styles.css`:
32
40
 
33
41
  ```css
34
42
  @import '@shirkasoft/ui-components/theme.css';
35
43
  ```
36
44
 
37
- El tema se basa en variables CSS `--shk-*`. Para personalizar colores, sobrescribí las variables en `:root` (modo claro) y `.dark` (modo oscuro):
45
+ The theme is based on `--shk-*` CSS variables. To customize colors, override the variables in `:root` (light mode) and `.dark` (dark mode):
38
46
 
39
47
  ```css
40
48
  :root {
@@ -46,7 +54,7 @@ El tema se basa en variables CSS `--shk-*`. Para personalizar colores, sobrescri
46
54
 
47
55
  ### Dark mode
48
56
 
49
- Agregá la clase `dark` al elemento `<html>` para activar el modo oscuro.
57
+ Add the `dark` class to the `<html>` element to enable dark mode.
50
58
 
51
59
  ```typescript
52
60
  document.documentElement.classList.toggle('dark');
@@ -54,110 +62,112 @@ document.documentElement.classList.toggle('dark');
54
62
 
55
63
  ---
56
64
 
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` | — | — |
65
+ ## Components
66
+
67
+ | # | Component | Selector | ControlValueAccessor | Associated service |
68
+ | --- | ------------- | -------------------- | -------------------- | ---------------------- |
69
+ | 1 | TextField | `shk-text-field` | ✅ | — |
70
+ | 2 | Toggle | `shk-toggle` | ✅ | — |
71
+ | 3 | Select | `shk-select` | ✅ | — |
72
+ | 4 | DatePicker | `shk-date-picker` | ✅ | — |
73
+ | 5 | PriceInput | `shk-price-input` | — | — |
74
+ | 6 | FileUpload | `shk-file-upload` | — | — |
75
+ | 7 | Table | `shk-table` | — | — |
76
+ | 8 | Modal | `shk-modal` | — | `ModalService` |
77
+ | 9 | Notification | `shk-notification` | — | `NotificationService` |
78
+ | 10 | ConfirmDialog | `shk-confirm-dialog` | — | `ConfirmDialogService` |
79
+ | 11 | Chart | `shk-chart` | — | — |
80
+ | 12 | Tooltip | `shk-tooltip` | — | — |
81
+ | 13 | Sidebar | `shk-sidebar` | — | — |
82
+ | 14 | Rail Sidebar | `shk-rail-sidebar` | — | — |
73
83
 
74
84
  ---
75
85
 
76
86
  ### TextField (`shk-text-field`)
77
87
 
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`.
88
+ Text input with support for input, textarea, password, search, credit card formatting, and error validation. Implements `ControlValueAccessor`.
79
89
 
80
90
  ```html
81
91
  <shk-text-field
82
- [label]="'Nombre'"
92
+ [label]="'Name'"
83
93
  [control]="myControl"
84
94
  [type]="'text'"
85
- [placeholder]="'Ingresá tu nombre'"
95
+ [placeholder]="'Enter your name'"
86
96
  [disabled]="false"
87
- [errorMessages]="{ required: 'Campo obligatorio' }"
97
+ [errorMessages]="{ required: 'This field is required' }"
88
98
  [isTextArea]="false"
89
99
  [searchMode]="false"
90
100
  (searchButtonClick)="onSearch()"
91
101
  />
92
102
  ```
93
103
 
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`.
104
+ | Input | Type | Default |
105
+ | ------------------- | --------------------------- | ---------------- |
106
+ | `id` | `string` | `''` |
107
+ | `label` | `string` | `''` |
108
+ | `type` | `string` | `'text'` |
109
+ | `placeholder` | `string` | `''` |
110
+ | `disabled` | `boolean` | `false` |
111
+ | `control` | `FormControl` | `undefined` |
112
+ | `formGroup` | `FormGroup` | `undefined` |
113
+ | `errorMessage` | `string` | `''` |
114
+ | `errorMessages` | `{ [key: string]: string }` | `{}` |
115
+ | `isTextArea` | `boolean` | `false` |
116
+ | `textAreaHeight` | `string` | `'h-28'` |
117
+ | `searchMode` | `boolean` | `false` |
118
+ | `searchButtonClick` | `output<void>` | — |
119
+ | `numbersOnly` | `boolean` | `false` |
120
+ | `allowDecimals` | `boolean` | `false` |
121
+ | `maxLength` | `number` | `undefined` |
122
+ | `formatCard` | `boolean` | `false` |
123
+ | `preventNegative` | `boolean` | `false` |
124
+ | `displayValue` | `string` | `''` |
125
+ | `autocomplete` | `string` | `'new-password'` |
126
+
127
+ > Also exposes `inputElement` and `textareaElement` as `viewChild`.
118
128
 
119
129
  ---
120
130
 
121
131
  ### Toggle (`shk-toggle`)
122
132
 
123
- Switch o checkbox. Implementa `ControlValueAccessor`.
133
+ Switch or checkbox. Implements `ControlValueAccessor`.
124
134
 
125
135
  ```html
126
136
  <shk-toggle
127
- [label]="'Activar notificaciones'"
137
+ [label]="'Enable notifications'"
128
138
  [mode]="'toggle'"
129
139
  [(checked)]="isChecked"
130
140
  (checkedChange)="onChange($event)"
131
141
  />
132
142
  ```
133
143
 
134
- | Input | Tipo | Default |
135
- |---|---|---|
136
- | `label` | `string` | `''` |
137
- | `mode` | `'toggle' \| 'checkbox'` | `'toggle'` |
138
- | `checked` | `boolean` | `undefined` |
144
+ | Input | Type | Default |
145
+ | --------- | ------------------------ | ----------- |
146
+ | `label` | `string` | `''` |
147
+ | `mode` | `'toggle' \| 'checkbox'` | `'toggle'` |
148
+ | `checked` | `boolean` | `undefined` |
139
149
 
140
- | Output | Tipo |
141
- |---|---|
150
+ | Output | Type |
151
+ | --------------- | --------- |
142
152
  | `checkedChange` | `boolean` |
143
153
 
144
154
  ---
145
155
 
146
156
  ### Select (`shk-select`)
147
157
 
148
- Dropdown seleccionable con búsqueda, paginación, selección múltiple, opciones personalizadas y validación. Implementa `ControlValueAccessor`.
158
+ Searchable dropdown with pagination, multiple selection, custom options, and validation. Implements `ControlValueAccessor`.
149
159
 
150
160
  ```html
151
161
  <shk-select
152
162
  [options]="options"
153
- [label]="'País'"
163
+ [label]="'Country'"
154
164
  [control]="countryControl"
155
165
  [multiple]="false"
156
166
  [isSearchable]="true"
157
167
  [usePagination]="true"
158
168
  [itemsPerPage]="10"
159
169
  [allowCustomEntries]="false"
160
- [placeholder]="'Seleccionar...'"
170
+ [placeholder]="'Select...'"
161
171
  [isLoading]="false"
162
172
  (selectionChange)="onSelect($event)"
163
173
  (search)="onSearch($event)"
@@ -172,42 +182,42 @@ interface SelectOption {
172
182
  }
173
183
  ```
174
184
 
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` |
185
+ | Input | Type | Default |
186
+ | ---------------------- | --------------------------- | ---------------------------------------- |
187
+ | `options` | `SelectOption[]` | `[]` |
188
+ | `label` | `string` | `undefined` |
189
+ | `placeholder` | `string` | `'Select...'` |
190
+ | `disabled` | `boolean` | `false` |
191
+ | `control` | `FormControl` | `undefined` |
192
+ | `formGroup` | `FormGroup` | `undefined` |
193
+ | `multiple` | `boolean` | `false` |
194
+ | `isSearchable` | `boolean` | `false` |
195
+ | `usePagination` | `boolean` | `false` |
196
+ | `itemsPerPage` | `number` | `10` |
197
+ | `allowCustomEntries` | `boolean` | `false` |
198
+ | `isLoading` | `boolean` | `false` |
199
+ | `isAllDataLoaded` | `boolean` | `false` |
200
+ | `preserveSearchOnLoad` | `boolean` | `false` |
201
+ | `dropdownUpward` | `boolean` | `false` |
202
+ | `showEmptyOption` | `boolean` | `true` |
203
+ | `emptyMessageKey` | `string` | `'common.no_records'` |
204
+ | `validCombinations` | `string[][]` | `undefined` |
205
+ | `errorMessages` | `{ [key: string]: string }` | `{ required: 'This field is required' }` |
206
+
207
+ | Output | Type |
208
+ | ----------------- | -------- |
209
+ | `selectionChange` | `any` |
210
+ | `search` | `string` |
201
211
 
202
212
  ---
203
213
 
204
214
  ### DatePicker (`shk-date-picker`)
205
215
 
206
- Selector de fecha, mes o año. Implementa `ControlValueAccessor`. Soporta formatos `'date'`, `'month'`, `'year'`.
216
+ Date, month, or year picker. Implements `ControlValueAccessor`. Supports `'date'`, `'month'`, `'year'` views.
207
217
 
208
218
  ```html
209
219
  <shk-date-picker
210
- [label]="'Fecha de inicio'"
220
+ [label]="'Start date'"
211
221
  [control]="dateControl"
212
222
  [view]="'date'"
213
223
  [locale]="'es'"
@@ -216,67 +226,68 @@ Selector de fecha, mes o año. Implementa `ControlValueAccessor`. Soporta format
216
226
  />
217
227
  ```
218
228
 
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`:
229
+ | Input | Type | Default |
230
+ | --------------- | ----------------------------- | ----------- |
231
+ | `id` | `string` | `''` |
232
+ | `label` | `string` | `''` |
233
+ | `placeholder` | `string` | `''` |
234
+ | `view` | `'date' \| 'month' \| 'year'` | `'date'` |
235
+ | `control` | `FormControl` | `undefined` |
236
+ | `formGroup` | `FormGroup` | `undefined` |
237
+ | `disabled` | `boolean` | `false` |
238
+ | `errorMessage` | `string` | `''` |
239
+ | `errorMessages` | `{ [key: string]: string }` | `{}` |
240
+ | `minValue` | `string` | `''` |
241
+ | `maxValue` | `string` | `''` |
242
+ | `locale` | `string` | `'es'` |
243
+
244
+ **Return value** depends on `view`:
245
+
235
246
  - `'date'` → `'YYYY-MM-DD'`
236
247
  - `'month'` → `'YYYY-MM'`
237
248
  - `'year'` → `'YYYY'`
238
249
 
239
250
  ---
240
251
 
241
- ### PriceInput (`shk-price-input`
252
+ ### PriceInput (`shk-price-input`)
242
253
 
243
- Input numérico con toggle entre modo monto (`$`) y porcentaje (`%`). Usa `model()` para doble vinculación.
254
+ Numeric input with toggle between amount (`$`) and percentage (`%`). Uses Angular `model()` for two-way binding.
244
255
 
245
256
  ```html
246
257
  <shk-price-input
247
258
  [(value)]="price"
248
259
  [(isPercentage)]="isPercent"
249
- [label]="'Precio'"
260
+ [label]="'Price'"
250
261
  [min]="0"
251
262
  [max]="10000"
252
263
  [required]="true"
253
264
  [showError]="hasError"
254
- [errorMessage]="'Valor inválido'"
265
+ [errorMessage]="'Invalid value'"
255
266
  />
256
267
  ```
257
268
 
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` | `''` |
269
+ | Input | Type | Default |
270
+ | -------------- | ---------------- | ------------ |
271
+ | `value` | `model<number>` | **required** |
272
+ | `isPercentage` | `model<boolean>` | `false` |
273
+ | `label` | `string` | `''` |
274
+ | `inputId` | `string` | `''` |
275
+ | `required` | `boolean` | `false` |
276
+ | `disabled` | `boolean` | `false` |
277
+ | `min` | `number` | `0` |
278
+ | `max` | `number` | `Infinity` |
279
+ | `showError` | `boolean` | `false` |
280
+ | `errorMessage` | `string` | `''` |
270
281
 
271
282
  ---
272
283
 
273
284
  ### FileUpload (`shk-file-upload`)
274
285
 
275
- Subida de archivos con arrastrar y soltar, vista previa de imágenes, validación de tipo y tamaño.
286
+ File upload with drag & drop, image preview, file type and size validation.
276
287
 
277
288
  ```html
278
289
  <shk-file-upload
279
- [label]="'Subí tu foto'"
290
+ [label]="'Upload your photo'"
280
291
  [accept]="'image/*'"
281
292
  [maxFileSize]="5 * 1024 * 1024"
282
293
  [maxFiles]="3"
@@ -295,29 +306,29 @@ interface FileUploadError {
295
306
  }
296
307
  ```
297
308
 
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` |
309
+ | Input | Type | Default |
310
+ | -------------------- | --------- | ----------------------- |
311
+ | `label` | `string` | `'Upload file'` |
312
+ | `accept` | `string` | `'image/*'` |
313
+ | `maxFileSize` | `number` | `2 * 1024 * 1024` (2MB) |
314
+ | `maxFiles` | `number` | `0` (unlimited) |
315
+ | `multiple` | `boolean` | `false` |
316
+ | `fileUploadText` | `string` | `'Select file'` |
317
+ | `changeFilesText` | `string` | `'Change files'` |
318
+ | `fileRecommendation` | `string` | `''` |
319
+
320
+ | Output | Type |
321
+ | -------------- | ----------------- |
322
+ | `fileSelected` | `File[]` |
323
+ | `fileRemoved` | `void` |
324
+ | `fileError` | `FileUploadError` |
325
+ | `fileWarning` | `FileUploadError` |
315
326
 
316
327
  ---
317
328
 
318
329
  ### Table (`shk-table`)
319
330
 
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.
331
+ Data table with sorting, column filters, global search, pagination, row actions, and header actions. Supports client and server-side mode.
321
332
 
322
333
  ```html
323
334
  <shk-table
@@ -384,41 +395,41 @@ interface FilterChangeEvent {
384
395
  }
385
396
  ```
386
397
 
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` |
398
+ | Input | Type | Default |
399
+ | -------------------- | ------------------------------------ | -------------- |
400
+ | `data` | `any[]` | `[]` |
401
+ | `columns` | `Column[]` | `[]` |
402
+ | `rowsPerPage` | `number` | `10` |
403
+ | `rowsPerPageOptions` | `number[]` | `[10, 25, 50]` |
404
+ | `loading` | `boolean` | `false` |
405
+ | `showActionRow` | `boolean` | `true` |
406
+ | `headerActions` | `TableAction[]` | `[]` |
407
+ | `rowActions` | `RowAction[]` | `[]` |
408
+ | `hasShadow` | `boolean` | `true` |
409
+ | `defaultSortField` | `string` | `''` |
410
+ | `defaultSortOrder` | `number` | `1` |
411
+ | `showSearch` | `boolean` | `true` |
412
+ | `searchPlaceholder` | `string` | `''` |
413
+ | `emptyMessage` | `string` | `''` |
414
+ | `serverSide` | `boolean` | `false` |
415
+ | `totalRecords` | `number` | `0` |
416
+ | `filters` | `{ label: string; value: string }[]` | `[]` |
417
+ | `activeFilter` | `string` | `''` |
418
+ | `customTemplates` | `{ [key: string]: any }` | `{}` |
419
+
420
+ | Output | Type |
421
+ | -------------- | ------------------- |
422
+ | `pageChange` | `PageChangeEvent` |
412
423
  | `filterChange` | `FilterChangeEvent` |
413
- | `searchChange` | `string` |
414
- | `filterClick` | `string` |
415
- | `refresh` | `void` |
424
+ | `searchChange` | `string` |
425
+ | `filterClick` | `string` |
426
+ | `refresh` | `void` |
416
427
 
417
428
  ---
418
429
 
419
430
  ### Modal (`shk-modal`)
420
431
 
421
- Modal dinámico que carga componentes a partir de un `ModalService`. Soporta formularios, expansión a pantalla completa y botones de aceptar/cancelar.
432
+ Dynamic modal that loads components via `ModalService`. Supports forms, fullscreen expansion, and accept/cancel buttons.
422
433
 
423
434
  ```html
424
435
  <shk-modal />
@@ -438,19 +449,20 @@ interface ModalConfig {
438
449
  }
439
450
  ```
440
451
 
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)
452
+ The injected component **must** expose:
453
+
454
+ - `form?: FormGroup` (optional, for validation)
455
+ - `onSubmit()` → calls `submitSuccess` or `submitError`
456
+ - `submitSuccess?: EventEmitter<void>` (optional)
457
+ - `submitError?: EventEmitter<void>` (optional)
458
+ - `handleCancel?: () => void` (optional)
447
459
 
448
460
  ```typescript
449
461
  constructor(private modalSrv: ModalService) {}
450
462
 
451
463
  openModal() {
452
464
  this.modalSrv.open({
453
- title: 'Editar usuario',
465
+ title: 'Edit user',
454
466
  component: EditUserComponent,
455
467
  data: { userId: 123 },
456
468
  width: '600px',
@@ -464,20 +476,20 @@ closeModal() {
464
476
  }
465
477
  ```
466
478
 
467
- **Métodos del servicio:**
479
+ **Service methods:**
468
480
 
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 |
481
+ | Method | Description |
482
+ | --------------------------- | ---------------------------------- |
483
+ | `open(config: ModalConfig)` | Opens a new modal |
484
+ | `close()` | Closes the current modal |
485
+ | `accept()` | Closes the modal (alias for close) |
486
+ | `clear()` | Closes all modals |
475
487
 
476
488
  ---
477
489
 
478
490
  ### Notification (`shk-notification`)
479
491
 
480
- Sistema de notificaciones toast con posiciones configurables y barra de progreso opcional.
492
+ Toast notification system with configurable positions and optional progress bar.
481
493
 
482
494
  ```html
483
495
  <shk-notification position="right-top" />
@@ -498,7 +510,7 @@ constructor(private notifSrv: NotificationService) {}
498
510
 
499
511
  showNotif() {
500
512
  const id = this.notifSrv.addNotification(
501
- 'Operación exitosa',
513
+ 'Operation successful',
502
514
  'success',
503
515
  false, // showProgress
504
516
  3000 // duration (ms)
@@ -510,28 +522,28 @@ updateProgress(id: string, progress: number) {
510
522
  }
511
523
  ```
512
524
 
513
- | Input | Tipo | Default |
514
- |---|---|---|
525
+ | Input | Type | Default |
526
+ | ---------- | ------------------------------------------- | -------------- |
515
527
  | `position` | `'center-top' \| 'right-top' \| 'left-top'` | `'center-top'` |
516
528
 
517
- **Métodos del servicio:**
529
+ **Service methods:**
518
530
 
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 |
531
+ | Method | Description |
532
+ | ------------------------------------------------------- | ------------------------- |
533
+ | `addNotification(msg, type?, showProgress?, duration?)` | Adds a notification |
534
+ | `updateProgress(id, progress)` | Updates the progress bar |
535
+ | `removeNotification(notification)` | Removes a notification |
536
+ | `removeNotificationById(id)` | Removes by ID |
537
+ | `clearAll()` | Removes all notifications |
526
538
 
527
539
  ---
528
540
 
529
541
  ### ConfirmDialog (`shk-confirm-dialog`)
530
542
 
531
- Diálogo de confirmación programático. Se usa a través del `ConfirmDialogService` que lo crea dinámicamente.
543
+ Programmatic confirmation dialog. Used via `ConfirmDialogService` which dynamically creates it.
532
544
 
533
545
  ```html
534
- <!-- No hace falta agregarlo al template -->
546
+ <!-- No need to add it to the template -->
535
547
  ```
536
548
 
537
549
  ```typescript
@@ -552,120 +564,279 @@ constructor(private confirmSrv: ConfirmDialogService) {}
552
564
 
553
565
  async deleteItem() {
554
566
  const confirmed = await this.confirmSrv.confirm({
555
- title: 'Eliminar usuario',
556
- message: '¿Estás seguro de eliminar este usuario?',
557
- confirmLabel: 'Eliminar',
567
+ title: 'Delete user',
568
+ message: 'Are you sure you want to delete this user?',
569
+ confirmLabel: 'Delete',
558
570
  type: 'danger',
559
571
  });
560
572
 
561
573
  if (confirmed) {
562
- // proceder con la eliminación
574
+ // proceed with deletion
563
575
  }
564
576
  }
565
577
  ```
566
578
 
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
- |---|---|
579
+ | Input | Type | Default |
580
+ | -------------- | --------------------------------- | ------------------------------------- |
581
+ | `title` | `string` | `'Confirm action'` |
582
+ | `message` | `string` | `'Are you sure you want to proceed?'` |
583
+ | `confirmLabel` | `string` | `'Confirm'` |
584
+ | `cancelLabel` | `string` | `'Cancel'` |
585
+ | `loadingText` | `string` | `'Processing…'` |
586
+ | `type` | `'danger' \| 'info' \| 'warning'` | `'danger'` |
587
+ | `loading` | `boolean` | `false` |
588
+ | `showCancel` | `boolean` | `true` |
589
+
590
+ | Output | Type |
591
+ | -------- | ------ |
580
592
  | `closed` | `void` |
581
593
 
582
594
  ---
583
595
 
584
596
  ### Chart (`shk-chart`)
585
597
 
586
- Wrapper de Chart.js que soporta los tipos de gráfico principales.
598
+ Chart.js wrapper supporting the main chart types.
587
599
 
588
600
  ```html
589
- <shk-chart
590
- [type]="'bar'"
591
- [data]="chartData"
592
- [options]="chartOptions"
593
- />
601
+ <shk-chart [type]="'bar'" [data]="chartData" [options]="chartOptions" />
594
602
  ```
595
603
 
596
604
  ```typescript
597
605
  import { COLOR_PALETTE, readThemeColors } from 'shirkasoft-ui-components';
598
606
 
599
- const colors = readThemeColors(); // colores del tema actual
607
+ const colors = readThemeColors(); // current theme colors
600
608
  ```
601
609
 
602
- | Input | Tipo | Default |
603
- |---|---|---|
604
- | `type` | `'line' \| 'bar' \| 'pie' \| 'doughnut' \| 'polarArea'` | `'bar'` |
605
- | `data` | `any` | `{ datasets: [] }` |
606
- | `options` | `any` | `{}` |
610
+ | Input | Type | Default |
611
+ | --------- | ------------------------------------------------------- | ------------------ |
612
+ | `type` | `'line' \| 'bar' \| 'pie' \| 'doughnut' \| 'polarArea'` | `'bar'` |
613
+ | `data` | `any` | `{ datasets: [] }` |
614
+ | `options` | `any` | `{}` |
607
615
 
608
- **Utils exportadas:**
616
+ **Exported utils:**
609
617
 
610
- | Export | Descripción |
611
- |---|---|
612
- | `COLOR_PALETTE` | Array de colores predefinidos (bg + border) |
613
- | `readThemeColors()` | Lee colores del tema actual (`--shk-surface-*`) |
618
+ | Export | Description |
619
+ | ------------------- | ---------------------------------------------- |
620
+ | `COLOR_PALETTE` | Predefined color array (bg + border) |
621
+ | `readThemeColors()` | Reads current theme colors (`--shk-surface-*`) |
614
622
 
615
623
  ---
616
624
 
617
625
  ### Tooltip (`shk-tooltip`)
618
626
 
619
- Tooltip con dos modos: `hover` (posicionamiento CSS) y `fixed` (posicionamiento calculado con JS).
627
+ Tooltip with two modes: `hover` (CSS positioning) and `fixed` (JS-calculated positioning).
620
628
 
621
629
  ```html
622
- <shk-tooltip [text]="'Info adicional'" [position]="'bottom'" [mode]="'hover'">
623
- <button>Pasar el mouse</button>
630
+ <shk-tooltip [text]="'Additional info'" [position]="'bottom'" [mode]="'hover'">
631
+ <button>Hover me</button>
624
632
  </shk-tooltip>
625
633
  ```
626
634
 
627
- | Input | Tipo | Default |
628
- |---|---|---|
629
- | `text` | `string` | `''` |
635
+ | Input | Type | Default |
636
+ | ---------- | ------------------------------ | ---------- |
637
+ | `text` | `string` | `''` |
630
638
  | `position` | `'top' \| 'bottom' \| 'right'` | `'bottom'` |
631
- | `mode` | `'hover' \| 'fixed'` | `'hover'` |
632
- | `offset` | `number` | `8` |
639
+ | `mode` | `'hover' \| 'fixed'` | `'hover'` |
640
+ | `offset` | `number` | `8` |
633
641
 
634
642
  ---
635
643
 
636
- ## Desarrollo
644
+ ### Sidebar (`shk-sidebar`)
645
+
646
+ Brand/logo header, round collapse toggle with tooltip, expandable groups with nested children, standalone items, Lucide icons, badges, separators, disabled items, active-item highlighting (`primary`-600 with white text), projected `header`/`content`/`footer` slots, tooltips on collapsed items, and a responsive off-canvas mode below 1024px. Uses the same theme tokens (`--shk-*`) as the rest of the library.
647
+
648
+ ```html
649
+ <shk-sidebar
650
+ [items]="items"
651
+ [(collapsed)]="collapsed"
652
+ [activeItemId]="activeId"
653
+ title="WS Admin"
654
+ subtitle="Panel de control"
655
+ logo="/logo.svg"
656
+ [defaultExpanded]="['products']"
657
+ (itemClick)="onItemClick($event)"
658
+ >
659
+ <div sidebarFooter>
660
+ <button (click)="logout()">Cerrar sesión</button>
661
+ </div>
662
+ </shk-sidebar>
663
+ ```
664
+
665
+ ```typescript
666
+ interface SidebarItem {
667
+ id: string;
668
+ label: string;
669
+ icon?: string; // Lucide icon name
670
+ badge?: string | number;
671
+ disabled?: boolean;
672
+ separator?: boolean; // renders a divider before the item
673
+ route?: string; // navigation target (optional)
674
+ roles?: string[]; // when `userRole` is set, items are filtered
675
+ children?: SidebarItem[]; // renders an expandable group with nested items
676
+ }
677
+
678
+ interface SidebarGroup {
679
+ id?: string;
680
+ label?: string;
681
+ items: SidebarItem[];
682
+ }
683
+ ```
684
+
685
+ | Input | Type | Default |
686
+ | ----------------- | --------------------------- | --------------------------------------------- |
687
+ | `items` | `SidebarItem[]` | `[]` |
688
+ | `groups` | `SidebarGroup[]` | `[]` (when set, overrides `items`) |
689
+ | `title` | `string` | `''` |
690
+ | `subtitle` | `string` | `''` |
691
+ | `logo` | `string` | `''` (image URL shown in the brand header) |
692
+ | `collapsed` | `model<boolean>` | `false` |
693
+ | `mobileOpen` | `model<boolean>` | `false` (off-canvas state on mobile) |
694
+ | `collapsible` | `boolean` | `true` |
695
+ | `showToggle` | `boolean` | `true` |
696
+ | `responsive` | `boolean` | `true` (off-canvas below 1024px) |
697
+ | `fixed` | `boolean` | `false` (uses `position: fixed` + `h-screen`) |
698
+ | `hasShadow` | `boolean` | `true` |
699
+ | `expandedWidth` | `string` | `'16rem'` |
700
+ | `collapsedWidth` | `string` | `'5rem'` |
701
+ | `activeItemId` | `string` | `''` |
702
+ | `userRole` | `string` | `''` (filters items by `roles`) |
703
+ | `defaultExpanded` | `string[]` | `[]` (groups expanded on init) |
704
+ | `labelPipe` | `(label: string) => string` | identity (e.g. pass a Transloco translate fn) |
705
+ | `expandTooltip` | `string` | `'Expandir'` |
706
+ | `collapseTooltip` | `string` | `'Colapsar'` |
707
+
708
+ | Output | Type |
709
+ | ----------- | ------------- |
710
+ | `itemClick` | `SidebarItem` |
711
+ | `toggle` | `boolean` |
712
+
713
+ **Projected slots:**
714
+
715
+ | Slot | Description |
716
+ | ---------------- | --------------------------------------------------- |
717
+ | `sidebarHeader` | Brand/logo area (rendered before the title) |
718
+ | `sidebarContent` | Custom content between the header and the nav |
719
+ | `sidebarFooter` | Footer area (e.g. logout button); hidden when empty |
720
+
721
+ > Icons are resolved by name via a Lucide map with a `Menu` fallback. Use `[fixed]="true"` for a full-screen sidebar (as in ws-admin) or leave it embedded in a container for previews.
722
+
723
+ ### Rail Sidebar (`shk-rail-sidebar`)
724
+
725
+ Sidebar estilo rail + nav, una columna vertical de iconos (una por sección) y un panel con el menú de la sección activa, con subgrupos expandibles, toggle de idioma, botón de logout y colapso.
726
+
727
+ ```html
728
+ <shk-rail-sidebar
729
+ [sections]="sections"
730
+ [activeUrl]="router.url"
731
+ [(activeSectionKey)]="activeSectionKey"
732
+ [(collapsed)]="collapsed"
733
+ [activeLang]="transloco.getActiveLang()"
734
+ appName="WAC Bookings"
735
+ logo="/logo.png"
736
+ (sectionSelected)="onSectionSelected($event)"
737
+ (itemClick)="onItemClick($event)"
738
+ (setLang)="onSetLanguage($event)"
739
+ (logoutRequested)="requestLogout()"
740
+ />
741
+ ```
742
+
743
+ ```ts
744
+ interface RailSidebarSection {
745
+ key: string;
746
+ label: string;
747
+ icon?: string; // nombre del icono Lucide
748
+ routerLink?: string; // ruta de la sección (selección automática por URL)
749
+ matchPrefixes?: string[]; // prefijos de URL que activan la sección
750
+ items?: RailSidebarItem[]; // menú del panel cuando la sección está activa
751
+ }
752
+
753
+ interface RailSidebarItem {
754
+ id: string;
755
+ label: string;
756
+ icon?: string;
757
+ routerLink?: string;
758
+ children?: RailSidebarItem[]; // subgrupo expandible
759
+ roles?: string[]; // filtro por rol (userRole)
760
+ badge?: string | number;
761
+ disabled?: boolean;
762
+ separator?: boolean;
763
+ }
764
+ ```
765
+
766
+ | Input | Type | Default |
767
+ | ------------------ | ---------------------- | --------------------------------------------------------- |
768
+ | `sections` | `RailSidebarSection[]` | `[]` |
769
+ | `activeUrl` | `string` | `''` — activa la sección por `matchPrefixes`/`routerLink` |
770
+ | `activeSectionKey` | `string` (model) | `''` |
771
+ | `collapsed` | `boolean` (model) | `false` |
772
+ | `activeLang` | `string` | `'es'` |
773
+ | `langs` | `string[]` | `['es', 'en']` — idiomas al togglear |
774
+ | `logo` | `string` | `''` — imagen del workspace |
775
+ | `appName` | `string` | `''` — título del panel |
776
+ | `userRole` | `string` | `''` — filtra `items.roles` |
777
+ | `labelPipe` | `(label) => string` | identidad (para transloco) |
778
+ | `railWidth` | `string` | `'4.5rem'` |
779
+ | `expandedWidth` | `string` | `'16.5rem'` |
780
+
781
+ | Output | Type |
782
+ | ----------------- | ---------------------- |
783
+ | `sectionSelected` | `{ key, routerLink? }` |
784
+ | `itemClick` | `RailSidebarItem` |
785
+ | `setLang` | `string` |
786
+ | `logoutRequested` | `void` |
787
+ | `toggleSidebar` | `void` |
788
+ | `workspaceClick` | `void` |
789
+
790
+ ---
791
+
792
+ ## Development
637
793
 
638
794
  ```bash
639
- # Construir la librería
795
+ # Build the library
640
796
  pnpm build
641
797
 
642
- # Servir la showcase (app de demostración)
798
+ # Serve the showcase (demo app)
643
799
  pnpm serve
644
800
 
645
- # Construir la showcase
801
+ # Build the showcase
646
802
  pnpm build:showcase
647
803
 
648
- # Escuchar cambios en la librería
804
+ # Watch for library changes
649
805
  pnpm watch
650
806
  ```
651
807
 
652
- ### Versionado
808
+ ### Versioning
809
+
810
+ ```bash
811
+ pnpm version:patch # 1.0.23 → 1.0.24 (creates commit + tag locally)
812
+ pnpm version:minor # 1.0.23 → 1.1.0
813
+ pnpm version:major # 1.0.23 → 2.0.0
814
+ ```
815
+
816
+ ### Push code (without publishing)
653
817
 
654
818
  ```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
819
+ git push origin main
820
+ ```
821
+
822
+ ### Push code + publish to npm
823
+
824
+ ```bash
825
+ git push origin main --tags
658
826
  ```
659
827
 
660
828
  ---
661
829
 
662
- ## Publicación
830
+ ## Publishing
831
+
832
+ ### CI/CD via GitHub Actions
663
833
 
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.
834
+ | Workflow | Trigger | Description |
835
+ | ------------------- | --------------------------------------------- | ------------------------------------------------------------------------- |
836
+ | **Publish to npm** | Manual (`workflow_dispatch`) or push `v*` tag | Builds library, publishes to npm, builds showcase, deploys to public repo |
837
+ | **Deploy Showcase** | Push to `main`/`master` or manual | Builds library + showcase, deploys to GitHub Pages public repo |
667
838
 
668
- Manual:
839
+ ### Manual publish (without GitHub Actions)
669
840
 
670
841
  ```bash
671
842
  bash scripts/publish-lib.sh
@@ -673,6 +844,6 @@ bash scripts/publish-lib.sh
673
844
 
674
845
  ---
675
846
 
676
- ## Licencia
847
+ ## License
677
848
 
678
849
  MIT © Shirkasoft