@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,296 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed } from 'vue';
3
+ import { Table } from '@htlkg/components/data';
4
+
5
+ // Sample data
6
+ const allItems = ref([
7
+ { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'Active', department: 'Engineering' },
8
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', status: 'Active', department: 'Marketing' },
9
+ { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User', status: 'Inactive', department: 'Sales' },
10
+ { id: 4, name: 'Alice Williams', email: 'alice@example.com', role: 'Manager', status: 'Active', department: 'Engineering' },
11
+ { id: 5, name: 'Charlie Brown', email: 'charlie@example.com', role: 'User', status: 'Active', department: 'Support' },
12
+ { id: 6, name: 'Diana Prince', email: 'diana@example.com', role: 'Admin', status: 'Active', department: 'Engineering' },
13
+ { id: 7, name: 'Eve Davis', email: 'eve@example.com', role: 'User', status: 'Inactive', department: 'Marketing' },
14
+ { id: 8, name: 'Frank Miller', email: 'frank@example.com', role: 'Manager', status: 'Active', department: 'Sales' },
15
+ { id: 9, name: 'Grace Lee', email: 'grace@example.com', role: 'User', status: 'Active', department: 'Engineering' },
16
+ { id: 10, name: 'Henry Wilson', email: 'henry@example.com', role: 'Manager', status: 'Active', department: 'Support' },
17
+ { id: 11, name: 'Iris Chen', email: 'iris@example.com', role: 'User', status: 'Inactive', department: 'Marketing' },
18
+ { id: 12, name: 'Jack Taylor', email: 'jack@example.com', role: 'Admin', status: 'Active', department: 'Engineering' },
19
+ { id: 13, name: 'Karen White', email: 'karen@example.com', role: 'User', status: 'Active', department: 'Sales' },
20
+ { id: 14, name: 'Leo Martinez', email: 'leo@example.com', role: 'Manager', status: 'Active', department: 'Support' },
21
+ { id: 15, name: 'Maria Garcia', email: 'maria@example.com', role: 'User', status: 'Inactive', department: 'Marketing' },
22
+ ]);
23
+
24
+ // Table columns
25
+ const columns = [
26
+ { name: 'Name', value: 'name' },
27
+ { name: 'Email', value: 'email' },
28
+ { name: 'Role', value: 'role' },
29
+ { name: 'Status', value: 'status' },
30
+ { name: 'Department', value: 'department' }
31
+ ];
32
+
33
+ // State
34
+ const loading = ref(false);
35
+ const currentPage = ref(1);
36
+ const itemsPerPage = ref(10);
37
+ const orderedBy = ref('name');
38
+ const orderDirection = ref<'asc' | 'desc'>('asc');
39
+ const selected = ref([]);
40
+ const appliedFilters = ref<any>(null);
41
+
42
+ // Actions for selection
43
+ const actions = [
44
+ { name: 'Delete Selected', id: 'delete' },
45
+ { name: 'Export Selected', id: 'export' },
46
+ { name: 'Change Status', id: 'changeStatus' }
47
+ ];
48
+
49
+ // Modal for select all confirmation
50
+ const selectAllItemsModal = {
51
+ title: 'Select All Items?',
52
+ content: 'Do you want to select all items (15 total), or just the items on this page?',
53
+ modalName: 'selectAllItemsModal',
54
+ open: false,
55
+ actions: [
56
+ { name: 'This page only', value: 'close' },
57
+ { name: 'All items', value: 'selectAll' }
58
+ ]
59
+ };
60
+
61
+ // Smart filter categories
62
+ const availableCategories = [
63
+ {
64
+ name: 'name',
65
+ label: 'Name',
66
+ componentType: 'uiInput' as const,
67
+ defaultProps: {
68
+ name: 'name',
69
+ label: 'Name',
70
+ placeholder: 'Search by name...',
71
+ value: ''
72
+ }
73
+ },
74
+ {
75
+ name: 'role',
76
+ label: 'Role',
77
+ componentType: 'uiSelect' as const,
78
+ defaultProps: {
79
+ name: 'role',
80
+ label: 'Role',
81
+ items: [
82
+ { id: '0', name: 'Select a role...', label: 'Select a role...' },
83
+ { id: 'admin', name: 'Admin', label: 'Admin' },
84
+ { id: 'manager', name: 'Manager', label: 'Manager' },
85
+ { id: 'user', name: 'User', label: 'User' }
86
+ ],
87
+ select: { id: '0', name: 'Select a role...', label: 'Select a role...' }
88
+ }
89
+ },
90
+ {
91
+ name: 'department',
92
+ label: 'Department',
93
+ componentType: 'uiSelect' as const,
94
+ defaultProps: {
95
+ name: 'department',
96
+ label: 'Department',
97
+ items: [
98
+ { id: '0', name: 'Select a department...', label: 'Select a department...' },
99
+ { id: 'engineering', name: 'Engineering', label: 'Engineering' },
100
+ { id: 'marketing', name: 'Marketing', label: 'Marketing' },
101
+ { id: 'sales', name: 'Sales', label: 'Sales' },
102
+ { id: 'support', name: 'Support', label: 'Support' }
103
+ ],
104
+ select: { id: '0', name: 'Select a department...', label: 'Select a department...' }
105
+ }
106
+ },
107
+ {
108
+ name: 'status',
109
+ label: 'Status',
110
+ componentType: 'uiSelect' as const,
111
+ defaultProps: {
112
+ name: 'status',
113
+ label: 'Status',
114
+ items: [
115
+ { id: '0', name: 'Select a status...', label: 'Select a status...' },
116
+ { id: 'active', name: 'Active', label: 'Active' },
117
+ { id: 'inactive', name: 'Inactive', label: 'Inactive' }
118
+ ],
119
+ select: { id: '0', name: 'Select a status...', label: 'Select a status...' }
120
+ }
121
+ }
122
+ ];
123
+
124
+ // Computed: Filtered items
125
+ const filteredItems = computed(() => {
126
+ let items = [...allItems.value];
127
+
128
+ // Apply filters
129
+ if (appliedFilters.value?.filters) {
130
+ items = items.filter(item => {
131
+ const filterResults = appliedFilters.value.filters.map((filter: any) => {
132
+ const value = String((item as any)[filter.name] || '').toLowerCase();
133
+ const filterValue = String(filter.value || '').toLowerCase();
134
+
135
+ if (!filterValue) return true;
136
+
137
+ if (filter.type === 'uiInput') {
138
+ return value.includes(filterValue);
139
+ } else if (filter.type === 'uiSelect') {
140
+ return value === filterValue;
141
+ }
142
+ return true;
143
+ });
144
+
145
+ // Apply logic operator
146
+ if (appliedFilters.value.logicOperator === 'and') {
147
+ return filterResults.every((r: boolean) => r);
148
+ } else {
149
+ return filterResults.some((r: boolean) => r);
150
+ }
151
+ });
152
+ }
153
+
154
+ // Apply sorting
155
+ if (orderedBy.value) {
156
+ items.sort((a, b) => {
157
+ const aVal = String((a as any)[orderedBy.value] || '');
158
+ const bVal = String((b as any)[orderedBy.value] || '');
159
+ const comparison = aVal.localeCompare(bVal);
160
+ return orderDirection.value === 'asc' ? comparison : -comparison;
161
+ });
162
+ }
163
+
164
+ return items;
165
+ });
166
+
167
+ // Computed: Paginated items
168
+ const paginatedItems = computed(() => {
169
+ const start = (currentPage.value - 1) * itemsPerPage.value;
170
+ const end = start + itemsPerPage.value;
171
+ return filteredItems.value.slice(start, end);
172
+ });
173
+
174
+ // Computed: Total pages
175
+ const totalPages = computed(() =>
176
+ Math.ceil(filteredItems.value.length / itemsPerPage.value)
177
+ );
178
+
179
+ // Event handlers
180
+ const handleTableAction = (data: { action: string; items: Array<string | number> }) => {
181
+ console.log('Table action:', data.action, 'Items:', data.items);
182
+
183
+ switch (data.action) {
184
+ case 'delete':
185
+ alert(`Delete ${data.items.length} items`);
186
+ break;
187
+ case 'export':
188
+ alert(`Export ${data.items.length} items`);
189
+ break;
190
+ case 'changeStatus':
191
+ alert(`Change status for ${data.items.length} items`);
192
+ break;
193
+ }
194
+ };
195
+
196
+ const handleRefresh = () => {
197
+ loading.value = true;
198
+ console.log('Refreshing data...');
199
+ setTimeout(() => {
200
+ loading.value = false;
201
+ console.log('Data refreshed!');
202
+ }, 1000);
203
+ };
204
+
205
+ const handleFiltersApplied = (filters: any) => {
206
+ console.log('Filters applied:', filters);
207
+ appliedFilters.value = filters;
208
+ currentPage.value = 1; // Reset to first page
209
+ };
210
+
211
+ const handleOrderChanged = (field: string, direction: 'asc' | 'desc') => {
212
+ console.log('Order changed:', field, direction);
213
+ orderedBy.value = field;
214
+ orderDirection.value = direction;
215
+ };
216
+
217
+ const handlePageChanged = (page: number) => {
218
+ console.log('Page changed:', page);
219
+ currentPage.value = page;
220
+ };
221
+
222
+ const handleItemsPerPageChanged = (size: number) => {
223
+ console.log('Items per page changed:', size);
224
+ itemsPerPage.value = size;
225
+ currentPage.value = 1;
226
+ };
227
+ </script>
228
+
229
+ <template>
230
+ <div>
231
+ <!-- Stats Display -->
232
+ <div class="mb-6 p-4 bg-blue-50 rounded border border-blue-200">
233
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
234
+ <div>
235
+ <span class="font-medium text-gray-700">Total Items:</span>
236
+ <span class="ml-2 text-blue-600 font-semibold">{{ allItems.length }}</span>
237
+ </div>
238
+ <div>
239
+ <span class="font-medium text-gray-700">Filtered:</span>
240
+ <span class="ml-2 text-blue-600 font-semibold">{{ filteredItems.length }}</span>
241
+ </div>
242
+ <div>
243
+ <span class="font-medium text-gray-700">Current Page:</span>
244
+ <span class="ml-2 text-blue-600 font-semibold">{{ currentPage }} / {{ totalPages }}</span>
245
+ </div>
246
+ <div>
247
+ <span class="font-medium text-gray-700">Selected:</span>
248
+ <span class="ml-2 text-blue-600 font-semibold">{{ selected.length }}</span>
249
+ </div>
250
+ </div>
251
+ <div v-if="selected.length > 0" class="mt-3 pt-3 border-t border-blue-200 text-sm text-gray-600">
252
+ <span class="font-medium">Selected Items:</span>
253
+ <span class="ml-2">{{ selected.map((s: any) => s.name).join(', ') }}</span>
254
+ </div>
255
+ <div v-if="appliedFilters" class="mt-3 pt-3 border-t border-blue-200 text-sm text-gray-600">
256
+ <span class="font-medium">Active Filters:</span>
257
+ <span class="ml-2">{{ appliedFilters.filters.length }} filter(s) applied</span>
258
+ </div>
259
+ </div>
260
+
261
+ <!-- Table Component -->
262
+ <Table
263
+ :items="paginatedItems"
264
+ :columns="columns"
265
+ :loading="loading"
266
+ :actions="actions"
267
+ :select-all-items-modal="selectAllItemsModal"
268
+ :available-categories="availableCategories"
269
+ :current-page="currentPage"
270
+ :total-pages="totalPages"
271
+ :total-items="filteredItems.length"
272
+ :items-per-page="itemsPerPage"
273
+ :ordered-by="orderedBy"
274
+ :order-direction="orderDirection"
275
+ :show-refresh="true"
276
+ :show-filters="true"
277
+ :show-pagination="true"
278
+ v-model:selected="selected"
279
+ @table-action="handleTableAction"
280
+ @refresh:data="handleRefresh"
281
+ @multiple-filters-applied="handleFiltersApplied"
282
+ @order-changed="handleOrderChanged"
283
+ @page-changed="handlePageChanged"
284
+ @items-per-page-changed="handleItemsPerPageChanged"
285
+ >
286
+ <template #actions>
287
+ <button
288
+ class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
289
+ @click="() => console.log('Custom action button clicked!')"
290
+ >
291
+ Custom Action
292
+ </button>
293
+ </template>
294
+ </Table>
295
+ </div>
296
+ </template>