@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,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
|
+
```
|