@htlkg/components 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.
Files changed (79) hide show
  1. package/dist/composables/index.js +388 -0
  2. package/dist/composables/index.js.map +1 -0
  3. package/package.json +41 -0
  4. package/src/composables/index.ts +6 -0
  5. package/src/composables/useForm.test.ts +229 -0
  6. package/src/composables/useForm.ts +130 -0
  7. package/src/composables/useFormValidation.test.ts +189 -0
  8. package/src/composables/useFormValidation.ts +83 -0
  9. package/src/composables/useModal.property.test.ts +164 -0
  10. package/src/composables/useModal.ts +43 -0
  11. package/src/composables/useNotifications.test.ts +166 -0
  12. package/src/composables/useNotifications.ts +81 -0
  13. package/src/composables/useTable.property.test.ts +198 -0
  14. package/src/composables/useTable.ts +134 -0
  15. package/src/composables/useTabs.property.test.ts +247 -0
  16. package/src/composables/useTabs.ts +101 -0
  17. package/src/data/Chart.demo.vue +340 -0
  18. package/src/data/Chart.md +525 -0
  19. package/src/data/Chart.vue +133 -0
  20. package/src/data/DataList.md +80 -0
  21. package/src/data/DataList.test.ts +69 -0
  22. package/src/data/DataList.vue +46 -0
  23. package/src/data/SearchableSelect.md +107 -0
  24. package/src/data/SearchableSelect.vue +124 -0
  25. package/src/data/Table.demo.vue +296 -0
  26. package/src/data/Table.md +588 -0
  27. package/src/data/Table.property.test.ts +548 -0
  28. package/src/data/Table.test.ts +562 -0
  29. package/src/data/Table.unit.test.ts +544 -0
  30. package/src/data/Table.vue +321 -0
  31. package/src/data/index.ts +5 -0
  32. package/src/domain/BrandCard.md +81 -0
  33. package/src/domain/BrandCard.vue +63 -0
  34. package/src/domain/BrandSelector.md +84 -0
  35. package/src/domain/BrandSelector.vue +65 -0
  36. package/src/domain/ProductBadge.md +60 -0
  37. package/src/domain/ProductBadge.vue +47 -0
  38. package/src/domain/UserAvatar.md +84 -0
  39. package/src/domain/UserAvatar.vue +60 -0
  40. package/src/domain/domain-components.property.test.ts +449 -0
  41. package/src/domain/index.ts +4 -0
  42. package/src/forms/DateRange.demo.vue +273 -0
  43. package/src/forms/DateRange.md +337 -0
  44. package/src/forms/DateRange.vue +110 -0
  45. package/src/forms/JsonSchemaForm.demo.vue +549 -0
  46. package/src/forms/JsonSchemaForm.md +112 -0
  47. package/src/forms/JsonSchemaForm.property.test.ts +817 -0
  48. package/src/forms/JsonSchemaForm.test.ts +601 -0
  49. package/src/forms/JsonSchemaForm.unit.test.ts +801 -0
  50. package/src/forms/JsonSchemaForm.vue +615 -0
  51. package/src/forms/index.ts +3 -0
  52. package/src/index.ts +17 -0
  53. package/src/navigation/Breadcrumbs.demo.vue +142 -0
  54. package/src/navigation/Breadcrumbs.md +102 -0
  55. package/src/navigation/Breadcrumbs.test.ts +69 -0
  56. package/src/navigation/Breadcrumbs.vue +58 -0
  57. package/src/navigation/Stepper.demo.vue +337 -0
  58. package/src/navigation/Stepper.md +174 -0
  59. package/src/navigation/Stepper.vue +146 -0
  60. package/src/navigation/Tabs.demo.vue +293 -0
  61. package/src/navigation/Tabs.md +163 -0
  62. package/src/navigation/Tabs.test.ts +176 -0
  63. package/src/navigation/Tabs.vue +104 -0
  64. package/src/navigation/index.ts +5 -0
  65. package/src/overlays/Alert.demo.vue +377 -0
  66. package/src/overlays/Alert.md +248 -0
  67. package/src/overlays/Alert.test.ts +166 -0
  68. package/src/overlays/Alert.vue +70 -0
  69. package/src/overlays/Drawer.md +140 -0
  70. package/src/overlays/Drawer.test.ts +92 -0
  71. package/src/overlays/Drawer.vue +76 -0
  72. package/src/overlays/Modal.demo.vue +149 -0
  73. package/src/overlays/Modal.md +385 -0
  74. package/src/overlays/Modal.test.ts +128 -0
  75. package/src/overlays/Modal.vue +86 -0
  76. package/src/overlays/Notification.md +150 -0
  77. package/src/overlays/Notification.test.ts +96 -0
  78. package/src/overlays/Notification.vue +58 -0
  79. package/src/overlays/index.ts +4 -0
@@ -0,0 +1,588 @@
1
+ # Table Component
2
+
3
+ A comprehensive data table component with pagination, sorting, filtering, selection, and column management. Wraps `@hotelinking/ui`'s `uiTable` component with advanced state management.
4
+
5
+ ## Features
6
+
7
+ - **Pagination**: Configurable page sizes with navigation
8
+ - **Sorting**: Column-based sorting with ascending/descending order
9
+ - **Selection**: Multi-select with bulk actions
10
+ - **Smart Filters**: Advanced filtering with multiple criteria
11
+ - **Column Management**: Show/hide columns dynamically
12
+ - **Empty States**: Customizable no-data and no-results states
13
+ - **Loading States**: Skeleton loading indicators
14
+ - **Actions**: Dropdown actions and custom action buttons
15
+ - **Refresh**: Optional data refresh functionality
16
+ - **Responsive**: Mobile-friendly design
17
+
18
+ ## Import
19
+
20
+ ```typescript
21
+ import { Table } from '@htlkg/components';
22
+ // or
23
+ import { Table } from '@htlkg/components/data';
24
+ ```
25
+
26
+ ## Props
27
+
28
+ | Prop | Type | Default | Description |
29
+ |------|------|---------|-------------|
30
+ | `items` | `T[]` | required | Array of data items to display |
31
+ | `columns` | `Column[]` | required | Column definitions |
32
+ | `loading` | `boolean` | `false` | Show loading state |
33
+ | `currentPage` | `number` | `1` | Current page number (v-model) |
34
+ | `totalPages` | `number` | `1` | Total number of pages |
35
+ | `totalItems` | `number` | `0` | Total number of items |
36
+ | `itemsPerPage` | `number` | `10` | Items per page (v-model) |
37
+ | `orderedBy` | `string` | `''` | Current sort column (v-model) |
38
+ | `orderDirection` | `'asc' \| 'desc'` | `'asc'` | Sort direction (v-model) |
39
+ | `actions` | `Array<{name: string, id: string}>` | `[]` | Bulk action options |
40
+ | `selectAllItemsModal` | `UiModalInterface` | - | Modal for select all confirmation |
41
+ | `availableCategories` | `FilterCategory[]` | `[]` | Smart filter categories |
42
+ | `filterLiterals` | `FilterLiterals` | - | Filter UI text labels |
43
+ | `tableActionsDropdown` | `{items: UiDropdownItemType[], loading?: boolean}` | - | Custom actions dropdown |
44
+ | `tableActionButtons` | `any[]` | `[]` | Custom action buttons |
45
+ | `noResults` | `NoResultsConfig` | - | Custom no results configuration |
46
+ | `showRefresh` | `boolean` | `false` | Show refresh action |
47
+ | `showFilters` | `boolean` | `true` | Show filter section |
48
+ | `showPagination` | `boolean` | `true` | Show pagination controls |
49
+
50
+ ### Column Interface
51
+
52
+ ```typescript
53
+ interface Column {
54
+ name: string; // Display name
55
+ value: string; // Property key in data
56
+ tooltip?: string; // Optional tooltip
57
+ }
58
+ ```
59
+
60
+ ### FilterCategory Interface
61
+
62
+ ```typescript
63
+ interface FilterCategory {
64
+ name: string;
65
+ label: string;
66
+ componentType: 'uiInput' | 'uiSelect';
67
+ defaultProps: any;
68
+ }
69
+ ```
70
+
71
+ ## Events
72
+
73
+ | Event | Payload | Description |
74
+ |-------|---------|-------------|
75
+ | `update:currentPage` | `number` | Page changed |
76
+ | `update:itemsPerPage` | `number` | Page size changed |
77
+ | `update:selected` | `T[]` | Selected items changed |
78
+ | `update:orderedBy` | `string` | Sort column changed |
79
+ | `update:orderDirection` | `'asc' \| 'desc'` | Sort direction changed |
80
+ | `refresh:data` | - | Refresh requested |
81
+ | `table-action` | `{action: string, items: Array<string \| number>}` | Bulk action triggered |
82
+ | `table-action-selected` | `any` | Single item action |
83
+ | `table-action-button-clicked` | `{id: string, text: string}` | Action button clicked |
84
+ | `smart-filters-sent` | `any` | Filters applied |
85
+ | `smart-filters-cleared` | - | Filters cleared |
86
+ | `smart-filter-deleted` | `number` | Single filter removed |
87
+ | `custom-emit` | `any` | Custom event from table |
88
+ | `modal-action` | `{modal: string, action: string}` | Modal action |
89
+ | `select-all-items` | - | All items selected |
90
+ | `deselect-all-items` | - | All items deselected |
91
+ | `no-results-action` | `string` | No results action clicked |
92
+ | `no-results-option-selected` | `any` | No results option selected |
93
+ | `order-changed` | `string, 'asc' \| 'desc'` | Sort changed |
94
+ | `page-changed` | `number` | Page changed |
95
+ | `items-per-page-changed` | `number` | Page size changed |
96
+ | `multiple-filters-applied` | `any` | Multiple filters applied |
97
+
98
+ ## Slots
99
+
100
+ | Slot | Description |
101
+ |------|-------------|
102
+ | `actions` | Custom action buttons in filter section |
103
+
104
+ ## Exposed Methods
105
+
106
+ | Method | Description |
107
+ |--------|-------------|
108
+ | `clearSelection()` | Clear all selected items |
109
+ | `getHiddenColumns()` | Get array of hidden column indices |
110
+ | `getSelectedItems()` | Get array of selected item IDs |
111
+
112
+ ## Usage Examples
113
+
114
+ ### Basic Table
115
+
116
+ ```vue
117
+ <script setup>
118
+ import { ref } from 'vue';
119
+ import { Table } from '@htlkg/components';
120
+
121
+ const columns = [
122
+ { name: 'ID', value: 'id' },
123
+ { name: 'Name', value: 'name' },
124
+ { name: 'Email', value: 'email' },
125
+ { name: 'Status', value: 'status' }
126
+ ];
127
+
128
+ const items = [
129
+ { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
130
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
131
+ { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' }
132
+ ];
133
+ </script>
134
+
135
+ <template>
136
+ <Table
137
+ :items="items"
138
+ :columns="columns"
139
+ />
140
+ </template>
141
+ ```
142
+
143
+ ### Table with Pagination
144
+
145
+ ```vue
146
+ <script setup>
147
+ import { ref } from 'vue';
148
+ import { Table } from '@htlkg/components';
149
+
150
+ const currentPage = ref(1);
151
+ const itemsPerPage = ref(10);
152
+ const totalItems = ref(100);
153
+ const totalPages = ref(10);
154
+
155
+ const columns = [
156
+ { name: 'ID', value: 'id' },
157
+ { name: 'Name', value: 'name' }
158
+ ];
159
+
160
+ const items = ref([]);
161
+
162
+ const loadPage = async (page: number) => {
163
+ // Fetch data for page
164
+ const response = await fetchUsers(page, itemsPerPage.value);
165
+ items.value = response.data;
166
+ };
167
+
168
+ const handlePageChange = (page: number) => {
169
+ currentPage.value = page;
170
+ loadPage(page);
171
+ };
172
+
173
+ const handlePageSizeChange = (size: number) => {
174
+ itemsPerPage.value = size;
175
+ currentPage.value = 1;
176
+ loadPage(1);
177
+ };
178
+ </script>
179
+
180
+ <template>
181
+ <Table
182
+ :items="items"
183
+ :columns="columns"
184
+ v-model:currentPage="currentPage"
185
+ v-model:itemsPerPage="itemsPerPage"
186
+ :totalItems="totalItems"
187
+ :totalPages="totalPages"
188
+ @page-changed="handlePageChange"
189
+ @items-per-page-changed="handlePageSizeChange"
190
+ />
191
+ </template>
192
+ ```
193
+
194
+ ### Table with Sorting
195
+
196
+ ```vue
197
+ <script setup>
198
+ import { ref } from 'vue';
199
+ import { Table } from '@htlkg/components';
200
+
201
+ const orderedBy = ref('name');
202
+ const orderDirection = ref<'asc' | 'desc'>('asc');
203
+
204
+ const columns = [
205
+ { name: 'Name', value: 'name' },
206
+ { name: 'Email', value: 'email' },
207
+ { name: 'Created', value: 'createdAt' }
208
+ ];
209
+
210
+ const items = ref([]);
211
+
212
+ const handleSort = (field: string, direction: 'asc' | 'desc') => {
213
+ orderedBy.value = field;
214
+ orderDirection.value = direction;
215
+
216
+ // Sort items or fetch sorted data
217
+ items.value = sortItems(items.value, field, direction);
218
+ };
219
+ </script>
220
+
221
+ <template>
222
+ <Table
223
+ :items="items"
224
+ :columns="columns"
225
+ v-model:orderedBy="orderedBy"
226
+ v-model:orderDirection="orderDirection"
227
+ @order-changed="handleSort"
228
+ />
229
+ </template>
230
+ ```
231
+
232
+ ### Table with Selection and Bulk Actions
233
+
234
+ ```vue
235
+ <script setup>
236
+ import { ref } from 'vue';
237
+ import { Table } from '@htlkg/components';
238
+
239
+ const selectedItems = ref([]);
240
+
241
+ const columns = [
242
+ { name: 'Name', value: 'name' },
243
+ { name: 'Email', value: 'email' }
244
+ ];
245
+
246
+ const items = ref([
247
+ { id: 1, name: 'John Doe', email: 'john@example.com' },
248
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
249
+ ]);
250
+
251
+ const actions = [
252
+ { name: 'Delete', id: 'delete' },
253
+ { name: 'Export', id: 'export' },
254
+ { name: 'Archive', id: 'archive' }
255
+ ];
256
+
257
+ const handleBulkAction = ({ action, items: itemIds }) => {
258
+ if (action === 'delete') {
259
+ deleteItems(itemIds);
260
+ } else if (action === 'export') {
261
+ exportItems(itemIds);
262
+ } else if (action === 'archive') {
263
+ archiveItems(itemIds);
264
+ }
265
+ };
266
+ </script>
267
+
268
+ <template>
269
+ <Table
270
+ :items="items"
271
+ :columns="columns"
272
+ :actions="actions"
273
+ v-model:selected="selectedItems"
274
+ @table-action="handleBulkAction"
275
+ />
276
+ </template>
277
+ ```
278
+
279
+ ### Table with Smart Filters
280
+
281
+ ```vue
282
+ <script setup>
283
+ import { ref } from 'vue';
284
+ import { Table } from '@htlkg/components';
285
+
286
+ const columns = [
287
+ { name: 'Name', value: 'name' },
288
+ { name: 'Status', value: 'status' },
289
+ { name: 'Role', value: 'role' }
290
+ ];
291
+
292
+ const items = ref([]);
293
+
294
+ const availableCategories = [
295
+ {
296
+ name: 'name',
297
+ label: 'Name',
298
+ componentType: 'uiInput',
299
+ defaultProps: { placeholder: 'Search by name' }
300
+ },
301
+ {
302
+ name: 'status',
303
+ label: 'Status',
304
+ componentType: 'uiSelect',
305
+ defaultProps: {
306
+ items: [
307
+ { id: 'active', name: 'Active' },
308
+ { id: 'inactive', name: 'Inactive' }
309
+ ]
310
+ }
311
+ }
312
+ ];
313
+
314
+ const filterLiterals = {
315
+ filters: 'Smart Filters',
316
+ contains: 'contains',
317
+ is: 'is',
318
+ and: 'and',
319
+ or: 'or',
320
+ deleteAll: 'Delete All',
321
+ filter: 'Filter'
322
+ };
323
+
324
+ const handleFiltersApplied = (filters) => {
325
+ // Apply filters to data
326
+ items.value = applyFilters(items.value, filters);
327
+ };
328
+
329
+ const handleFiltersClear = () => {
330
+ // Reset to original data
331
+ items.value = originalItems;
332
+ };
333
+ </script>
334
+
335
+ <template>
336
+ <Table
337
+ :items="items"
338
+ :columns="columns"
339
+ :availableCategories="availableCategories"
340
+ :filterLiterals="filterLiterals"
341
+ @smart-filters-sent="handleFiltersApplied"
342
+ @smart-filters-cleared="handleFiltersClear"
343
+ />
344
+ </template>
345
+ ```
346
+
347
+ ### Table with Loading State
348
+
349
+ ```vue
350
+ <script setup>
351
+ import { ref, onMounted } from 'vue';
352
+ import { Table } from '@htlkg/components';
353
+
354
+ const loading = ref(true);
355
+ const items = ref([]);
356
+
357
+ const columns = [
358
+ { name: 'Name', value: 'name' },
359
+ { name: 'Email', value: 'email' }
360
+ ];
361
+
362
+ onMounted(async () => {
363
+ loading.value = true;
364
+ items.value = await fetchUsers();
365
+ loading.value = false;
366
+ });
367
+ </script>
368
+
369
+ <template>
370
+ <Table
371
+ :items="items"
372
+ :columns="columns"
373
+ :loading="loading"
374
+ />
375
+ </template>
376
+ ```
377
+
378
+ ### Table with Custom Empty State
379
+
380
+ ```vue
381
+ <script setup>
382
+ import { ref } from 'vue';
383
+ import { Table } from '@htlkg/components';
384
+
385
+ const columns = [
386
+ { name: 'Name', value: 'name' }
387
+ ];
388
+
389
+ const items = ref([]);
390
+
391
+ const noResults = {
392
+ title: 'No users found',
393
+ message: 'Get started by creating your first user',
394
+ actions: [
395
+ { action: 'create', text: 'Create User' }
396
+ ]
397
+ };
398
+
399
+ const handleNoResultsAction = (action) => {
400
+ if (action === 'create') {
401
+ // Navigate to create user page
402
+ router.push('/users/create');
403
+ }
404
+ };
405
+ </script>
406
+
407
+ <template>
408
+ <Table
409
+ :items="items"
410
+ :columns="columns"
411
+ :noResults="noResults"
412
+ @no-results-action="handleNoResultsAction"
413
+ />
414
+ </template>
415
+ ```
416
+
417
+ ### Table with Refresh
418
+
419
+ ```vue
420
+ <script setup>
421
+ import { ref } from 'vue';
422
+ import { Table } from '@htlkg/components';
423
+
424
+ const columns = [
425
+ { name: 'Name', value: 'name' }
426
+ ];
427
+
428
+ const items = ref([]);
429
+
430
+ const refreshData = async () => {
431
+ items.value = await fetchUsers();
432
+ };
433
+ </script>
434
+
435
+ <template>
436
+ <Table
437
+ :items="items"
438
+ :columns="columns"
439
+ :showRefresh="true"
440
+ @refresh:data="refreshData"
441
+ />
442
+ </template>
443
+ ```
444
+
445
+ ### Table with Custom Actions Slot
446
+
447
+ ```vue
448
+ <script setup>
449
+ import { ref } from 'vue';
450
+ import { Table } from '@htlkg/components';
451
+
452
+ const columns = [
453
+ { name: 'Name', value: 'name' }
454
+ ];
455
+
456
+ const items = ref([]);
457
+
458
+ const exportData = () => {
459
+ // Export logic
460
+ };
461
+
462
+ const importData = () => {
463
+ // Import logic
464
+ };
465
+ </script>
466
+
467
+ <template>
468
+ <Table
469
+ :items="items"
470
+ :columns="columns"
471
+ >
472
+ <template #actions>
473
+ <button @click="exportData" class="btn btn-primary">
474
+ Export
475
+ </button>
476
+ <button @click="importData" class="btn btn-secondary">
477
+ Import
478
+ </button>
479
+ </template>
480
+ </Table>
481
+ </template>
482
+ ```
483
+
484
+ ### Programmatic Control
485
+
486
+ ```vue
487
+ <script setup>
488
+ import { ref } from 'vue';
489
+ import { Table } from '@htlkg/components';
490
+
491
+ const tableRef = ref();
492
+
493
+ const clearSelection = () => {
494
+ tableRef.value?.clearSelection();
495
+ };
496
+
497
+ const getSelected = () => {
498
+ const selected = tableRef.value?.getSelectedItems();
499
+ console.log('Selected items:', selected);
500
+ };
501
+
502
+ const getHidden = () => {
503
+ const hidden = tableRef.value?.getHiddenColumns();
504
+ console.log('Hidden columns:', hidden);
505
+ };
506
+ </script>
507
+
508
+ <template>
509
+ <div>
510
+ <button @click="clearSelection">Clear Selection</button>
511
+ <button @click="getSelected">Get Selected</button>
512
+ <button @click="getHidden">Get Hidden Columns</button>
513
+
514
+ <Table
515
+ ref="tableRef"
516
+ :items="items"
517
+ :columns="columns"
518
+ />
519
+ </div>
520
+ </template>
521
+ ```
522
+
523
+ ## Best Practices
524
+
525
+ ### Performance
526
+
527
+ - Use pagination for large datasets (>100 items)
528
+ - Implement server-side sorting and filtering for very large datasets
529
+ - Debounce filter inputs to reduce API calls
530
+ - Use virtual scrolling for extremely large tables
531
+
532
+ ### Accessibility
533
+
534
+ - Provide meaningful column names
535
+ - Use tooltips for abbreviated headers
536
+ - Ensure keyboard navigation works
537
+ - Add ARIA labels for screen readers
538
+
539
+ ### UX Guidelines
540
+
541
+ - Show loading states during data fetches
542
+ - Provide clear empty states with actionable next steps
543
+ - Use appropriate page sizes (10, 25, 50, 100)
544
+ - Reset to page 1 when filters or page size changes
545
+ - Clear selection when sorting or paginating
546
+ - Provide feedback for bulk actions
547
+
548
+ ## Design System Integration
549
+
550
+ This component wraps `@hotelinking/ui`'s `uiTable`, `uiPagination`, `uiDropdown`, `uiSmartFilterMultipleV2`, and `uiNoResults` components, providing:
551
+
552
+ - Unified state management for pagination, sorting, and selection
553
+ - Smart filter integration with multiple criteria
554
+ - Column visibility management
555
+ - Empty state handling
556
+ - Event normalization and consolidation
557
+ - Consistent API with other data components
558
+
559
+ ## Related Components
560
+
561
+ - **DataList**: For simpler list displays
562
+ - **SearchableSelect**: For searchable dropdown selections
563
+ - **JsonSchemaForm**: For form-based data entry
564
+
565
+ ## Demo
566
+
567
+ See the [Table demo page](/components/table) for interactive examples.
568
+
569
+ ## TypeScript Support
570
+
571
+ ```typescript
572
+ import type { Column } from '@htlkg/components';
573
+
574
+ interface User {
575
+ id: number;
576
+ name: string;
577
+ email: string;
578
+ status: 'active' | 'inactive';
579
+ }
580
+
581
+ const columns: Column[] = [
582
+ { name: 'Name', value: 'name' },
583
+ { name: 'Email', value: 'email' },
584
+ { name: 'Status', value: 'status' }
585
+ ];
586
+
587
+ const items = ref<User[]>([]);
588
+ ```