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