@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,142 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue';
3
+ import { Breadcrumbs } from '@htlkg/components/navigation';
4
+ import type { BreadcrumbItem } from '@htlkg/components/navigation';
5
+
6
+ // Breadcrumb configurations
7
+ const currentBreadcrumbs = ref<BreadcrumbItem[]>([
8
+ { label: 'Home', routeName: '/' },
9
+ { label: 'Products', routeName: '/products' },
10
+ { label: 'Electronics', routeName: '/products/electronics' },
11
+ { label: 'Laptops', routeName: '/products/electronics/laptops', current: true }
12
+ ]);
13
+
14
+ const loading = ref(false);
15
+
16
+ // Event tracking
17
+ const eventLog = ref<string[]>([]);
18
+
19
+ // Predefined breadcrumb examples
20
+ const breadcrumbExamples = [
21
+ {
22
+ name: 'Product Detail',
23
+ items: [
24
+ { label: 'Home', routeName: '/' },
25
+ { label: 'Products', routeName: '/products' },
26
+ { label: 'Electronics', routeName: '/products/electronics' },
27
+ { label: 'Laptops', routeName: '/products/electronics/laptops', current: true }
28
+ ]
29
+ },
30
+ {
31
+ name: 'User Profile',
32
+ items: [
33
+ { label: 'Home', routeName: '/' },
34
+ { label: 'Settings', routeName: '/settings' },
35
+ { label: 'Profile', routeName: '/settings/profile', current: true }
36
+ ]
37
+ },
38
+ {
39
+ name: 'Admin Dashboard',
40
+ items: [
41
+ { label: 'Home', routeName: '/' },
42
+ { label: 'Admin', routeName: '/admin' },
43
+ { label: 'Users', routeName: '/admin/users' },
44
+ { label: 'User Details', routeName: '/admin/users/123', current: true }
45
+ ]
46
+ },
47
+ {
48
+ name: 'Simple Path',
49
+ items: [
50
+ { label: 'Home', routeName: '/' },
51
+ { label: 'About', routeName: '/about', current: true }
52
+ ]
53
+ }
54
+ ];
55
+
56
+ // Handle breadcrumb click
57
+ const handleBreadcrumbClick = (routeName: string) => {
58
+ logEvent(`Breadcrumb clicked: ${routeName}`);
59
+ // In a real app, you would navigate to the route here
60
+ };
61
+
62
+ // Switch to different breadcrumb example
63
+ const switchExample = (example: typeof breadcrumbExamples[0]) => {
64
+ currentBreadcrumbs.value = example.items;
65
+ logEvent(`Switched to: ${example.name}`);
66
+ };
67
+
68
+ // Toggle loading state
69
+ const toggleLoading = () => {
70
+ loading.value = !loading.value;
71
+ logEvent(`Loading state: ${loading.value ? 'ON' : 'OFF'}`);
72
+ };
73
+
74
+ const logEvent = (message: string) => {
75
+ eventLog.value.unshift(`[${new Date().toLocaleTimeString()}] ${message}`);
76
+ if (eventLog.value.length > 5) {
77
+ eventLog.value = eventLog.value.slice(0, 5);
78
+ }
79
+ };
80
+ </script>
81
+
82
+ <template>
83
+ <div>
84
+ <!-- Breadcrumbs Component -->
85
+ <div class="mb-6 p-4 bg-white rounded-lg border">
86
+ <Breadcrumbs
87
+ :items="currentBreadcrumbs"
88
+ :loading="loading"
89
+ @breadcrumb-click="handleBreadcrumbClick"
90
+ />
91
+ </div>
92
+
93
+ <!-- Example Switcher -->
94
+ <div class="mb-6">
95
+ <h3 class="text-sm font-semibold text-gray-900 mb-3">Try Different Examples:</h3>
96
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-2">
97
+ <button
98
+ v-for="example in breadcrumbExamples"
99
+ :key="example.name"
100
+ @click="switchExample(example)"
101
+ class="px-3 py-2 text-sm border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
102
+ >
103
+ {{ example.name }}
104
+ </button>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- Controls -->
109
+ <div class="mb-6 p-4 bg-white rounded-lg border">
110
+ <h3 class="text-sm font-semibold text-gray-900 mb-3">Controls:</h3>
111
+ <button
112
+ @click="toggleLoading"
113
+ class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
114
+ >
115
+ {{ loading ? 'Stop Loading' : 'Start Loading' }}
116
+ </button>
117
+ </div>
118
+
119
+ <!-- Event Log -->
120
+ <div class="p-4 bg-gray-50 rounded border mb-6">
121
+ <h4 class="text-sm font-semibold text-gray-900 mb-2">Event Log:</h4>
122
+ <div class="space-y-1">
123
+ <p
124
+ v-for="(event, index) in eventLog"
125
+ :key="index"
126
+ class="text-xs text-gray-700"
127
+ >
128
+ {{ event }}
129
+ </p>
130
+ <p v-if="eventLog.length === 0" class="text-xs text-gray-500 italic">
131
+ No events yet. Click on breadcrumb items or try different examples.
132
+ </p>
133
+ </div>
134
+ </div>
135
+
136
+ <!-- Current State Display -->
137
+ <div class="p-4 bg-gray-50 rounded border">
138
+ <h4 class="text-sm font-semibold text-gray-900 mb-2">Current Breadcrumbs:</h4>
139
+ <pre class="text-xs text-gray-700 overflow-x-auto">{{ JSON.stringify(currentBreadcrumbs, null, 2) }}</pre>
140
+ </div>
141
+ </div>
142
+ </template>
@@ -0,0 +1,102 @@
1
+ # Breadcrumbs Component
2
+
3
+ A navigation component showing the current page's location in the site hierarchy. Wraps `@hotelinking/ui`'s `uiBreadcrumbs` component.
4
+
5
+ ## Features
6
+
7
+ - **Hierarchical navigation**: Shows page path
8
+ - **Click handling**: Navigate to any level
9
+ - **Loading state**: Skeleton loading indicator
10
+ - **Auto-current**: Automatically marks last item as current
11
+
12
+ ## Import
13
+
14
+ ```typescript
15
+ import { Breadcrumbs } from '@htlkg/components';
16
+ // or
17
+ import { Breadcrumbs } from '@htlkg/components/navigation';
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `items` | `BreadcrumbItem[]` | required | Breadcrumb items |
25
+ | `loading` | `boolean` | `false` | Show loading state |
26
+
27
+ ### BreadcrumbItem Interface
28
+
29
+ ```typescript
30
+ interface BreadcrumbItem {
31
+ label: string;
32
+ routeName: string;
33
+ current?: boolean;
34
+ }
35
+ ```
36
+
37
+ ## Events
38
+
39
+ | Event | Payload | Description |
40
+ |-------|---------|-------------|
41
+ | `breadcrumb-click` | `string` | Emitted when breadcrumb is clicked (routeName) |
42
+
43
+ ## Exposed Methods
44
+
45
+ | Method | Description |
46
+ |--------|-------------|
47
+ | `getItems()` | Get current breadcrumb items |
48
+
49
+ ## Usage Examples
50
+
51
+ ### Basic Breadcrumbs
52
+
53
+ ```vue
54
+ <script setup>
55
+ import { Breadcrumbs } from '@htlkg/components';
56
+
57
+ const items = [
58
+ { label: 'Home', routeName: '/' },
59
+ { label: 'Users', routeName: '/users' },
60
+ { label: 'John Doe', routeName: '/users/1' }
61
+ ];
62
+
63
+ const handleClick = (routeName) => {
64
+ router.push(routeName);
65
+ };
66
+ </script>
67
+
68
+ <template>
69
+ <Breadcrumbs
70
+ :items="items"
71
+ @breadcrumb-click="handleClick"
72
+ />
73
+ </template>
74
+ ```
75
+
76
+ ### With Loading State
77
+
78
+ ```vue
79
+ <script setup>
80
+ import { ref, onMounted } from 'vue';
81
+ import { Breadcrumbs } from '@htlkg/components';
82
+
83
+ const loading = ref(true);
84
+ const items = ref([]);
85
+
86
+ onMounted(async () => {
87
+ items.value = await fetchBreadcrumbs();
88
+ loading.value = false;
89
+ });
90
+ </script>
91
+
92
+ <template>
93
+ <Breadcrumbs
94
+ :items="items"
95
+ :loading="loading"
96
+ />
97
+ </template>
98
+ ```
99
+
100
+ ## Demo
101
+
102
+ See the [Breadcrumbs demo page](/components/breadcrumbs) for interactive examples.
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import Breadcrumbs from './Breadcrumbs.vue';
4
+
5
+ describe('Breadcrumbs Component', () => {
6
+ const mockBreadcrumbs = [
7
+ { label: 'Home', routeName: '/' },
8
+ { label: 'Products', routeName: '/products' },
9
+ { label: 'Details', routeName: '/products/123' }
10
+ ];
11
+
12
+ it('renders with basic props', () => {
13
+ const wrapper = mount(Breadcrumbs, {
14
+ props: {
15
+ items: mockBreadcrumbs
16
+ }
17
+ });
18
+
19
+ expect(wrapper.exists()).toBe(true);
20
+ });
21
+
22
+ it('renders all breadcrumb items', () => {
23
+ const wrapper = mount(Breadcrumbs, {
24
+ props: {
25
+ items: mockBreadcrumbs
26
+ }
27
+ });
28
+
29
+ // Breadcrumbs uses uiBreadcrumbs component which renders the items
30
+ // We can verify the component received the correct props
31
+ const component = wrapper.vm as any;
32
+ expect(component.pagesConfig.length).toBe(mockBreadcrumbs.length);
33
+ });
34
+
35
+ it('emits breadcrumb-click event when item is clicked', async () => {
36
+ const wrapper = mount(Breadcrumbs, {
37
+ props: {
38
+ items: mockBreadcrumbs
39
+ }
40
+ });
41
+
42
+ const component = wrapper.vm as any;
43
+ if (component.handleBreadcrumbClick) {
44
+ component.handleBreadcrumbClick(mockBreadcrumbs[0]);
45
+ expect(wrapper.emitted('breadcrumb-click')).toBeTruthy();
46
+ expect(wrapper.emitted('breadcrumb-click')?.[0]).toEqual([mockBreadcrumbs[0]]);
47
+ }
48
+ });
49
+
50
+ it('handles empty breadcrumbs array', () => {
51
+ const wrapper = mount(Breadcrumbs, {
52
+ props: {
53
+ items: []
54
+ }
55
+ });
56
+
57
+ expect(wrapper.exists()).toBe(true);
58
+ });
59
+
60
+ it('marks last item as current', () => {
61
+ const wrapper = mount(Breadcrumbs, {
62
+ props: {
63
+ items: mockBreadcrumbs
64
+ }
65
+ });
66
+
67
+ expect(wrapper.exists()).toBe(true);
68
+ });
69
+ });
@@ -0,0 +1,58 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue';
3
+ import { uiBreadcrumbs } from '@hotelinking/ui';
4
+
5
+ export interface BreadcrumbItem {
6
+ label: string;
7
+ routeName: string;
8
+ current?: boolean;
9
+ }
10
+
11
+ interface Props {
12
+ items: BreadcrumbItem[];
13
+ loading?: boolean;
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ loading: false
18
+ });
19
+
20
+ const emit = defineEmits<{
21
+ 'breadcrumb-click': [routeName: string];
22
+ }>();
23
+
24
+ // Convert items to uiBreadcrumbs format
25
+ const pagesConfig = computed(() =>
26
+ props.items.map((item, index) => ({
27
+ name: item.label,
28
+ routeName: item.routeName,
29
+ current: item.current ?? (index === props.items.length - 1)
30
+ }))
31
+ );
32
+
33
+ // Handle breadcrumb click
34
+ function handleBreadcrumbClick(routeName: string) {
35
+ emit('breadcrumb-click', routeName);
36
+ }
37
+
38
+ // Expose methods for parent components
39
+ defineExpose({
40
+ getItems: () => props.items
41
+ });
42
+ </script>
43
+
44
+ <template>
45
+ <div class="breadcrumbs-wrapper">
46
+ <uiBreadcrumbs
47
+ :pages="pagesConfig"
48
+ :loading="loading"
49
+ @bread-crumb-clicked="handleBreadcrumbClick"
50
+ />
51
+ </div>
52
+ </template>
53
+
54
+ <style scoped>
55
+ .breadcrumbs-wrapper {
56
+ width: 100%;
57
+ }
58
+ </style>