@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.
- package/dist/composables/index.js +388 -0
- package/dist/composables/index.js.map +1 -0
- package/package.json +41 -0
- package/src/composables/index.ts +6 -0
- package/src/composables/useForm.test.ts +229 -0
- package/src/composables/useForm.ts +130 -0
- package/src/composables/useFormValidation.test.ts +189 -0
- package/src/composables/useFormValidation.ts +83 -0
- package/src/composables/useModal.property.test.ts +164 -0
- package/src/composables/useModal.ts +43 -0
- package/src/composables/useNotifications.test.ts +166 -0
- package/src/composables/useNotifications.ts +81 -0
- package/src/composables/useTable.property.test.ts +198 -0
- package/src/composables/useTable.ts +134 -0
- package/src/composables/useTabs.property.test.ts +247 -0
- package/src/composables/useTabs.ts +101 -0
- package/src/data/Chart.demo.vue +340 -0
- package/src/data/Chart.md +525 -0
- package/src/data/Chart.vue +133 -0
- package/src/data/DataList.md +80 -0
- package/src/data/DataList.test.ts +69 -0
- package/src/data/DataList.vue +46 -0
- package/src/data/SearchableSelect.md +107 -0
- package/src/data/SearchableSelect.vue +124 -0
- package/src/data/Table.demo.vue +296 -0
- package/src/data/Table.md +588 -0
- package/src/data/Table.property.test.ts +548 -0
- package/src/data/Table.test.ts +562 -0
- package/src/data/Table.unit.test.ts +544 -0
- package/src/data/Table.vue +321 -0
- package/src/data/index.ts +5 -0
- package/src/domain/BrandCard.md +81 -0
- package/src/domain/BrandCard.vue +63 -0
- package/src/domain/BrandSelector.md +84 -0
- package/src/domain/BrandSelector.vue +65 -0
- package/src/domain/ProductBadge.md +60 -0
- package/src/domain/ProductBadge.vue +47 -0
- package/src/domain/UserAvatar.md +84 -0
- package/src/domain/UserAvatar.vue +60 -0
- package/src/domain/domain-components.property.test.ts +449 -0
- package/src/domain/index.ts +4 -0
- package/src/forms/DateRange.demo.vue +273 -0
- package/src/forms/DateRange.md +337 -0
- package/src/forms/DateRange.vue +110 -0
- package/src/forms/JsonSchemaForm.demo.vue +549 -0
- package/src/forms/JsonSchemaForm.md +112 -0
- package/src/forms/JsonSchemaForm.property.test.ts +817 -0
- package/src/forms/JsonSchemaForm.test.ts +601 -0
- package/src/forms/JsonSchemaForm.unit.test.ts +801 -0
- package/src/forms/JsonSchemaForm.vue +615 -0
- package/src/forms/index.ts +3 -0
- package/src/index.ts +17 -0
- package/src/navigation/Breadcrumbs.demo.vue +142 -0
- package/src/navigation/Breadcrumbs.md +102 -0
- package/src/navigation/Breadcrumbs.test.ts +69 -0
- package/src/navigation/Breadcrumbs.vue +58 -0
- package/src/navigation/Stepper.demo.vue +337 -0
- package/src/navigation/Stepper.md +174 -0
- package/src/navigation/Stepper.vue +146 -0
- package/src/navigation/Tabs.demo.vue +293 -0
- package/src/navigation/Tabs.md +163 -0
- package/src/navigation/Tabs.test.ts +176 -0
- package/src/navigation/Tabs.vue +104 -0
- package/src/navigation/index.ts +5 -0
- package/src/overlays/Alert.demo.vue +377 -0
- package/src/overlays/Alert.md +248 -0
- package/src/overlays/Alert.test.ts +166 -0
- package/src/overlays/Alert.vue +70 -0
- package/src/overlays/Drawer.md +140 -0
- package/src/overlays/Drawer.test.ts +92 -0
- package/src/overlays/Drawer.vue +76 -0
- package/src/overlays/Modal.demo.vue +149 -0
- package/src/overlays/Modal.md +385 -0
- package/src/overlays/Modal.test.ts +128 -0
- package/src/overlays/Modal.vue +86 -0
- package/src/overlays/Notification.md +150 -0
- package/src/overlays/Notification.test.ts +96 -0
- package/src/overlays/Notification.vue +58 -0
- 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>
|