@htlkg/components 0.0.3 → 0.0.4

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 (47) hide show
  1. package/dist/AdminWrapper.vue_vue_type_script_setup_true_lang-B32IylcT.js +367 -0
  2. package/dist/AdminWrapper.vue_vue_type_script_setup_true_lang-B32IylcT.js.map +1 -0
  3. package/dist/Alert.vue_vue_type_script_setup_true_lang-DxPCS-Hx.js +263 -0
  4. package/dist/Alert.vue_vue_type_script_setup_true_lang-DxPCS-Hx.js.map +1 -0
  5. package/dist/DateRange.vue_vue_type_script_setup_true_lang-BLVg1Hah.js +580 -0
  6. package/dist/DateRange.vue_vue_type_script_setup_true_lang-BLVg1Hah.js.map +1 -0
  7. package/dist/ProductBadge.vue_vue_type_script_setup_true_lang-Cmr2f4Cy.js +187 -0
  8. package/dist/ProductBadge.vue_vue_type_script_setup_true_lang-Cmr2f4Cy.js.map +1 -0
  9. package/dist/_plugin-vue_export-helper-1tPrXgE0.js +11 -0
  10. package/dist/_plugin-vue_export-helper-1tPrXgE0.js.map +1 -0
  11. package/dist/components.css +15 -0
  12. package/dist/composables/index.js +32 -765
  13. package/dist/composables/index.js.map +1 -1
  14. package/dist/data/index.js +18 -0
  15. package/dist/data/index.js.map +1 -0
  16. package/dist/domain/index.js +8 -0
  17. package/dist/domain/index.js.map +1 -0
  18. package/dist/filterHelpers-DgRyoYSa.js +1386 -0
  19. package/dist/filterHelpers-DgRyoYSa.js.map +1 -0
  20. package/dist/forms/index.js +6 -0
  21. package/dist/forms/index.js.map +1 -0
  22. package/dist/index-DGO_pNgG.js +79 -0
  23. package/dist/index-DGO_pNgG.js.map +1 -0
  24. package/dist/index-QK97OdqQ.js +25 -0
  25. package/dist/index-QK97OdqQ.js.map +1 -0
  26. package/dist/index.js +67 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/navigation/index.js +8 -0
  29. package/dist/navigation/index.js.map +1 -0
  30. package/dist/overlays/index.js +8 -0
  31. package/dist/overlays/index.js.map +1 -0
  32. package/dist/stores/index.js +14 -0
  33. package/dist/stores/index.js.map +1 -0
  34. package/dist/useAdminPage-GhgXp0x8.js +1070 -0
  35. package/dist/useAdminPage-GhgXp0x8.js.map +1 -0
  36. package/dist/useTable-DutR1gkg.js +293 -0
  37. package/dist/useTable-DutR1gkg.js.map +1 -0
  38. package/package.json +37 -11
  39. package/src/composables/index.ts +52 -0
  40. package/src/composables/useAdminPage.ts +462 -0
  41. package/src/composables/useConfirmation.ts +358 -0
  42. package/src/composables/useStats.ts +361 -0
  43. package/src/composables/useWizard.ts +448 -0
  44. package/src/data/columnHelpers.ts +169 -0
  45. package/src/data/filterHelpers.ts +358 -0
  46. package/src/data/index.ts +11 -0
  47. package/src/forms/JsonSchemaForm.vue +4 -1
@@ -0,0 +1,358 @@
1
+ /**
2
+ * Filter Definition Helpers
3
+ *
4
+ * Pre-built filter definitions for common patterns, reducing boilerplate
5
+ * when defining DataTable filters.
6
+ */
7
+
8
+ import type { DataTableFilter } from "./DataTable.vue";
9
+
10
+ /**
11
+ * Filter option for select filters
12
+ */
13
+ export interface FilterOption {
14
+ label: string;
15
+ value: string | number | boolean;
16
+ }
17
+
18
+ /**
19
+ * Common status options
20
+ */
21
+ export const statusOptions: FilterOption[] = [
22
+ { label: "Active", value: "active" },
23
+ { label: "Inactive", value: "inactive" },
24
+ { label: "Pending", value: "pending" },
25
+ { label: "Archived", value: "archived" },
26
+ ];
27
+
28
+ /**
29
+ * Boolean options
30
+ */
31
+ export const booleanOptions: FilterOption[] = [
32
+ { label: "Yes", value: "true" },
33
+ { label: "No", value: "false" },
34
+ ];
35
+
36
+ /**
37
+ * Pre-built filter helpers
38
+ */
39
+ export const filters = {
40
+ /**
41
+ * Text search filter
42
+ *
43
+ * @example
44
+ * filters.text('name', 'Name')
45
+ * filters.text('email', 'Email', 'Search by email address...')
46
+ */
47
+ text: (key: string, label: string, placeholder?: string): DataTableFilter => ({
48
+ key,
49
+ label,
50
+ type: "text",
51
+ placeholder: placeholder ?? `Search by ${label.toLowerCase()}...`,
52
+ }),
53
+
54
+ /**
55
+ * Select dropdown filter
56
+ *
57
+ * @example
58
+ * filters.select('role', 'Role', [
59
+ * { label: 'Admin', value: 'admin' },
60
+ * { label: 'User', value: 'user' },
61
+ * ])
62
+ */
63
+ select: (key: string, label: string, options: FilterOption[]): DataTableFilter => ({
64
+ key,
65
+ label,
66
+ type: "select",
67
+ options,
68
+ }),
69
+
70
+ /**
71
+ * Status filter with common status options
72
+ *
73
+ * @example
74
+ * filters.status()
75
+ * filters.status('state', 'State')
76
+ * filters.status('status', 'Status', [
77
+ * { label: 'Active', value: 'active' },
78
+ * { label: 'Draft', value: 'draft' },
79
+ * ])
80
+ */
81
+ status: (key: string = "status", label: string = "Status", options?: FilterOption[]): DataTableFilter => ({
82
+ key,
83
+ label,
84
+ type: "select",
85
+ options: options ?? statusOptions,
86
+ }),
87
+
88
+ /**
89
+ * Boolean (Yes/No) filter
90
+ *
91
+ * @example
92
+ * filters.boolean('verified', 'Verified')
93
+ * filters.boolean('active', 'Active', 'Enabled', 'Disabled')
94
+ */
95
+ boolean: (key: string, label: string, trueLabel: string = "Yes", falseLabel: string = "No"): DataTableFilter => ({
96
+ key,
97
+ label,
98
+ type: "select",
99
+ options: [
100
+ { label: trueLabel, value: "true" },
101
+ { label: falseLabel, value: "false" },
102
+ ],
103
+ }),
104
+
105
+ /**
106
+ * Number filter
107
+ *
108
+ * @example
109
+ * filters.number('age', 'Age')
110
+ * filters.number('amount', 'Amount', 'Enter amount...')
111
+ */
112
+ number: (key: string, label: string, placeholder?: string): DataTableFilter => ({
113
+ key,
114
+ label,
115
+ type: "number",
116
+ placeholder: placeholder ?? `Enter ${label.toLowerCase()}...`,
117
+ }),
118
+
119
+ /**
120
+ * Date filter
121
+ *
122
+ * @example
123
+ * filters.date('createdAt', 'Created Date')
124
+ */
125
+ date: (key: string, label: string): DataTableFilter => ({
126
+ key,
127
+ label,
128
+ type: "date",
129
+ }),
130
+
131
+ /**
132
+ * Date range filter
133
+ *
134
+ * @example
135
+ * filters.dateRange('createdAt', 'Created')
136
+ */
137
+ dateRange: (key: string, label: string): DataTableFilter => ({
138
+ key,
139
+ label,
140
+ type: "dateRange",
141
+ }),
142
+
143
+ /**
144
+ * Role filter with common role options
145
+ *
146
+ * @example
147
+ * filters.role()
148
+ * filters.role('userRole', 'User Role')
149
+ */
150
+ role: (key: string = "role", label: string = "Role", options?: FilterOption[]): DataTableFilter => ({
151
+ key,
152
+ label,
153
+ type: "select",
154
+ options: options ?? [
155
+ { label: "Admin", value: "admin" },
156
+ { label: "Manager", value: "manager" },
157
+ { label: "User", value: "user" },
158
+ { label: "Guest", value: "guest" },
159
+ ],
160
+ }),
161
+
162
+ /**
163
+ * Type filter (generic entity type)
164
+ *
165
+ * @example
166
+ * filters.type('campaignType', 'Type', [
167
+ * { label: 'Email', value: 'email' },
168
+ * { label: 'SMS', value: 'sms' },
169
+ * ])
170
+ */
171
+ type: (key: string, label: string, options: FilterOption[]): DataTableFilter => ({
172
+ key,
173
+ label,
174
+ type: "select",
175
+ options,
176
+ }),
177
+
178
+ /**
179
+ * Priority filter
180
+ *
181
+ * @example
182
+ * filters.priority()
183
+ * filters.priority('urgency', 'Urgency')
184
+ */
185
+ priority: (key: string = "priority", label: string = "Priority"): DataTableFilter => ({
186
+ key,
187
+ label,
188
+ type: "select",
189
+ options: [
190
+ { label: "Low", value: "low" },
191
+ { label: "Medium", value: "medium" },
192
+ { label: "High", value: "high" },
193
+ { label: "Critical", value: "critical" },
194
+ ],
195
+ }),
196
+
197
+ /**
198
+ * Category filter from dynamic options
199
+ *
200
+ * @example
201
+ * // From array of objects
202
+ * filters.fromData('categoryId', 'Category', categories, 'name', 'id')
203
+ */
204
+ fromData: <T extends Record<string, any>>(
205
+ key: string,
206
+ label: string,
207
+ data: T[],
208
+ labelKey: keyof T,
209
+ valueKey: keyof T
210
+ ): DataTableFilter => ({
211
+ key,
212
+ label,
213
+ type: "select",
214
+ options: data.map((item) => ({
215
+ label: String(item[labelKey]),
216
+ value: item[valueKey] as string | number,
217
+ })),
218
+ }),
219
+
220
+ /**
221
+ * Enum filter from TypeScript enum
222
+ *
223
+ * @example
224
+ * enum Status { Active = 'active', Inactive = 'inactive' }
225
+ * filters.fromEnum('status', 'Status', Status)
226
+ */
227
+ fromEnum: (key: string, label: string, enumObj: Record<string, string | number>): DataTableFilter => ({
228
+ key,
229
+ label,
230
+ type: "select",
231
+ options: Object.entries(enumObj)
232
+ .filter(([k]) => Number.isNaN(Number(k))) // Filter out numeric keys from numeric enums
233
+ .map(([enumKey, enumValue]) => ({
234
+ label: enumKey.replace(/([A-Z])/g, " $1").trim(), // Convert camelCase to Title Case
235
+ value: enumValue,
236
+ })),
237
+ }),
238
+ };
239
+
240
+ /**
241
+ * Create a filter group with common filters
242
+ *
243
+ * @example
244
+ * const tableFilters = createFilterGroup({
245
+ * search: ['name', 'email'],
246
+ * status: true,
247
+ * dateRange: 'createdAt',
248
+ * custom: [
249
+ * filters.role('userRole', 'Role'),
250
+ * ],
251
+ * });
252
+ */
253
+ export interface FilterGroupConfig {
254
+ /** Fields to include as text search filters */
255
+ search?: string[];
256
+ /** Include status filter */
257
+ status?: boolean | { key?: string; label?: string; options?: FilterOption[] };
258
+ /** Field for date range filter */
259
+ dateRange?: string;
260
+ /** Additional custom filters */
261
+ custom?: DataTableFilter[];
262
+ }
263
+
264
+ export function createFilterGroup(config: FilterGroupConfig): DataTableFilter[] {
265
+ const result: DataTableFilter[] = [];
266
+
267
+ // Add search filters
268
+ if (config.search) {
269
+ config.search.forEach((field) => {
270
+ result.push(filters.text(field, field.charAt(0).toUpperCase() + field.slice(1)));
271
+ });
272
+ }
273
+
274
+ // Add status filter
275
+ if (config.status) {
276
+ if (typeof config.status === "boolean") {
277
+ result.push(filters.status());
278
+ } else {
279
+ result.push(filters.status(config.status.key, config.status.label, config.status.options));
280
+ }
281
+ }
282
+
283
+ // Add date range filter
284
+ if (config.dateRange) {
285
+ result.push(filters.dateRange(config.dateRange, "Date Range"));
286
+ }
287
+
288
+ // Add custom filters
289
+ if (config.custom) {
290
+ result.push(...config.custom);
291
+ }
292
+
293
+ return result;
294
+ }
295
+
296
+ /**
297
+ * Common filter presets for specific entity types
298
+ */
299
+ export const filterPresets = {
300
+ /**
301
+ * Filters for user/account tables
302
+ */
303
+ users: (): DataTableFilter[] => [
304
+ filters.text("name", "Name"),
305
+ filters.text("email", "Email"),
306
+ filters.role(),
307
+ filters.status(),
308
+ ],
309
+
310
+ /**
311
+ * Filters for campaign tables
312
+ */
313
+ campaigns: (): DataTableFilter[] => [
314
+ filters.text("name", "Campaign Name"),
315
+ filters.status("status", "Status", [
316
+ { label: "Active", value: "active" },
317
+ { label: "Draft", value: "draft" },
318
+ { label: "Completed", value: "completed" },
319
+ { label: "Archived", value: "archived" },
320
+ { label: "Failed", value: "failed" },
321
+ ]),
322
+ filters.dateRange("createdAt", "Created Date"),
323
+ ],
324
+
325
+ /**
326
+ * Filters for contact tables
327
+ */
328
+ contacts: (): DataTableFilter[] => [
329
+ filters.text("name", "Name"),
330
+ filters.text("email", "Email"),
331
+ filters.text("phone", "Phone"),
332
+ filters.status(),
333
+ ],
334
+
335
+ /**
336
+ * Filters for booking/reservation tables
337
+ */
338
+ bookings: (): DataTableFilter[] => [
339
+ filters.text("guestName", "Guest Name"),
340
+ filters.text("confirmationNumber", "Confirmation #"),
341
+ filters.status("status", "Status", [
342
+ { label: "Confirmed", value: "confirmed" },
343
+ { label: "Pending", value: "pending" },
344
+ { label: "Cancelled", value: "cancelled" },
345
+ { label: "Completed", value: "completed" },
346
+ ]),
347
+ filters.dateRange("checkIn", "Check-in Date"),
348
+ ],
349
+
350
+ /**
351
+ * Filters for audit/log tables
352
+ */
353
+ auditLogs: (): DataTableFilter[] => [
354
+ filters.text("action", "Action"),
355
+ filters.text("user", "User"),
356
+ filters.dateRange("timestamp", "Date"),
357
+ ],
358
+ };
package/src/data/index.ts CHANGED
@@ -23,3 +23,14 @@ export {
23
23
  type DateFormatOptions,
24
24
  type TagColorFn,
25
25
  } from './columnHelpers';
26
+
27
+ // Filter definition helpers
28
+ export {
29
+ filters,
30
+ filterPresets,
31
+ createFilterGroup,
32
+ statusOptions,
33
+ booleanOptions,
34
+ type FilterOption,
35
+ type FilterGroupConfig,
36
+ } from './filterHelpers';
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed } from 'vue';
3
- import Ajv from 'ajv';
3
+ import _Ajv from 'ajv';
4
4
  import addFormats from 'ajv-formats';
5
5
  import {
6
6
  uiInput,
@@ -11,6 +11,9 @@ import {
11
11
  uiButton
12
12
  } from '@hotelinking/ui';
13
13
 
14
+ // Handle ESM/CJS interop for ajv
15
+ const Ajv = (_Ajv as unknown as { default: typeof _Ajv }).default ?? _Ajv;
16
+
14
17
  // Initialize AJV for JSON Schema validation with format support
15
18
  const ajv = new Ajv({ allErrors: true });
16
19
  addFormats(ajv); // Add support for format keywords like "email", "uri", "date", etc.