edvoyui-component-library-test-flight 0.0.21 → 0.0.23
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/EUIButton.vue.d.ts.map +1 -0
- package/dist/library-vue-ts.cjs.js +4 -3
- package/dist/library-vue-ts.es.js +3 -8
- package/dist/library-vue-ts.umd.js +4 -3
- package/dist/select/EUISelect.vue.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/App.vue +16 -0
- package/src/assets/fonts/gilroy/GilroyBold/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyBold/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroyBoldItalic/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyBoldItalic/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroyExtraBold/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyExtraBold/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroyExtraBoldItalic/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyExtraBoldItalic/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroyMedium/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyMedium/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroyRegular/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroyRegular/font.woff2 +0 -0
- package/src/assets/fonts/gilroy/GilroySemiBold/font.woff +0 -0
- package/src/assets/fonts/gilroy/GilroySemiBold/font.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-Bold.woff +0 -0
- package/src/assets/fonts/inter/Inter-Bold.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-Italic.woff +0 -0
- package/src/assets/fonts/inter/Inter-Italic.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-Medium.woff +0 -0
- package/src/assets/fonts/inter/Inter-Medium.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-MediumItalic.woff +0 -0
- package/src/assets/fonts/inter/Inter-MediumItalic.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-Regular.woff +0 -0
- package/src/assets/fonts/inter/Inter-Regular.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-SemiBold.woff +0 -0
- package/src/assets/fonts/inter/Inter-SemiBold.woff2 +0 -0
- package/src/assets/fonts/inter/Inter-SemiBoldItalic.woff +0 -0
- package/src/assets/fonts/inter/Inter-SemiBoldItalic.woff2 +0 -0
- package/src/assets/scss/body.scss +15 -0
- package/src/assets/svg/ChevronDownSolid.vue +19 -0
- package/src/assets/svg/ChevronDownStroke.vue +22 -0
- package/src/assets/svg/SortArrow.vue +24 -0
- package/src/assets/svg/Student.vue +30 -0
- package/src/assets/svg/partner.vue +33 -0
- package/src/assets/svg/people.vue +25 -0
- package/src/assets/vue.svg +1 -0
- package/src/components/HelloWorld.vue +999 -0
- package/src/components/accordion/EUIAccordion.stories.ts +157 -0
- package/src/components/accordion/EUIAccordion.vue +90 -0
- package/src/components/avatar/EUIAvatar.stories.ts +157 -0
- package/src/components/avatar/EUIAvatar.vue +96 -0
- package/src/components/button/EUIButton.stories.ts +252 -0
- package/src/components/button/EUIButton.vue +151 -0
- package/src/components/checkbox/EUICheckbox.stories.ts +58 -0
- package/src/components/checkbox/EUICheckbox.vue +103 -0
- package/src/components/datepicker/EUIDatepicker.stories.ts +236 -0
- package/src/components/datepicker/EUIDatepicker.vue +185 -0
- package/src/components/delete.vue +108 -0
- package/src/components/dropdown/EUIMultiDropdown.stories.ts +187 -0
- package/src/components/dropdown/EUIMultiDropdown.vue +129 -0
- package/src/components/errorMessage/EUIErrorMessage.scss +0 -0
- package/src/components/errorMessage/EUIErrorMessage.stories.ts +41 -0
- package/src/components/errorMessage/EUIErrorMessage.vue +25 -0
- package/src/components/index.ts +46 -0
- package/src/components/input/EUIInput.stories.ts +174 -0
- package/src/components/input/EUIInput.vue +169 -0
- package/src/components/inputNormal/EUIInputNormal.stories.ts +164 -0
- package/src/components/inputNormal/EUIInputNormal.vue +161 -0
- package/src/components/loader/EUICircleLoader.vue +31 -0
- package/src/components/loader/EUICubeLoader.vue +237 -0
- package/src/components/loader/EUILoader.stories.ts +99 -0
- package/src/components/loader/EUILoader.vue +17 -0
- package/src/components/loader/EUISquareLoader.vue +47 -0
- package/src/components/modal/EUIModal.stories.ts +372 -0
- package/src/components/modal/EUIModal.vue +163 -0
- package/src/components/pillSelect/EUIPillSelect.stories.ts +74 -0
- package/src/components/pillSelect/EUIPillSelect.vue +149 -0
- package/src/components/popover/EUIPopover.stories.ts +247 -0
- package/src/components/popover/EUIPopover.vue +159 -0
- package/src/components/radio/EUIRadio.stories.ts +54 -0
- package/src/components/radio/EUIRadio.vue +78 -0
- package/src/components/searchInput/EUISearch.stories.ts +24 -0
- package/src/components/searchInput/EUISearch.vue +215 -0
- package/src/components/select/EUISelect.scss +0 -0
- package/src/components/select/EUISelect.stories.ts +49 -0
- package/src/components/select/EUISelect.vue +682 -0
- package/src/components/selectSearch/EUISelectSearch.vue +23 -0
- package/src/components/slideover/EUISlideover.stories.ts +318 -0
- package/src/components/slideover/EUISlideover.vue +207 -0
- package/src/components/stepperTimeline/EUIStepperHorizontal.vue +112 -0
- package/src/components/stepperTimeline/EUIStepperTimeline.stories.ts +54 -0
- package/src/components/stepperTimeline/EUIStepperTimeline.vue +16 -0
- package/src/components/stepperTimeline/EUIStepperVertical.vue +112 -0
- package/src/components/table/EUIDashboardTable.vue +482 -0
- package/src/components/table/EUIPageLimit.vue +66 -0
- package/src/components/table/EUIPagination.vue +175 -0
- package/src/components/table/EUIStudentPagination.vue +172 -0
- package/src/components/table/EUITable.stories.ts +190 -0
- package/src/components/table/EUITable.vue +508 -0
- package/src/components/table/EUITableCheckbox.vue +97 -0
- package/src/components/tabs/EUITabs.vue +128 -0
- package/src/components/tabs/EUItabs.stories.ts +123 -0
- package/src/components/tag/EUITag.stories.ts +46 -0
- package/src/components/tag/EUITag.vue +46 -0
- package/src/components/telephone/EUITelephone.stories.ts +202 -0
- package/src/components/telephone/EUITelephone.vue +280 -0
- package/src/components/textArea/EUITextArea.stories.ts +82 -0
- package/src/components/textArea/EUITextArea.vue +122 -0
- package/src/components/timeLine/EUITimeLine.stories.ts +247 -0
- package/src/components/timeLine/EUITimeLine.vue +43 -0
- package/src/components/timeLine/EUITimeLineItem.vue +124 -0
- package/src/components/toggle/EUIToggle.stories.ts +63 -0
- package/src/components/toggle/EUIToggle.vue +99 -0
- package/src/components/tooltip/EUITooltip.stories.ts +53 -0
- package/src/components/tooltip/EUITooltip.vue +108 -0
- package/src/data/books.ts +163 -0
- package/src/data/tab.ts +33 -0
- package/src/data/table.ts +5392 -0
- package/src/main.ts +5 -0
- package/src/utils/lodash.ts +9 -0
- package/src/utils/types.ts +9 -0
- package/src/vite-env.d.ts +5 -0
- package/dist/EUISelect.vue.d.ts.map +0 -1
- package/dist/button/EUIButton.vue.d.ts.map +0 -1
- package/dist/library-vue-ts.css +0 -1
- package/dist/style.scss +0 -118
- /package/dist/{button/EUIButton.vue.d.ts → EUIButton.vue.d.ts} +0 -0
- /package/dist/{EUISelect.vue.d.ts → select/EUISelect.vue.d.ts} +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { defineComponent } from "vue";
|
|
2
|
+
import { Meta, StoryFn } from "@storybook/vue3";
|
|
3
|
+
import EUIMultiDropdown from "./EUIMultiDropdown.vue";
|
|
4
|
+
import ChevronDownStroke from "../../assets/svg/ChevronDownStroke.vue";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Components/MultiDropdown",
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
component: EUIMultiDropdown,
|
|
10
|
+
argTypes: {
|
|
11
|
+
title: {
|
|
12
|
+
description: "The title of the dropdown menu.",
|
|
13
|
+
control: { type: "text" },
|
|
14
|
+
defaultValue: "My Students",
|
|
15
|
+
},
|
|
16
|
+
className: {
|
|
17
|
+
description: "Additional classes to apply to the dropdown button.",
|
|
18
|
+
control: { type: "text" },
|
|
19
|
+
},
|
|
20
|
+
menuItems: {
|
|
21
|
+
description: "An array of menu items, with optional submenus.",
|
|
22
|
+
control: { type: "object" },
|
|
23
|
+
defaultValue: [
|
|
24
|
+
{ text: "All Students" },
|
|
25
|
+
{ text: "My Students" },
|
|
26
|
+
{ text: "Genie Completed Students" },
|
|
27
|
+
{
|
|
28
|
+
text: "Standard Filter",
|
|
29
|
+
subMenu: [
|
|
30
|
+
{ text: "UKI Fair" },
|
|
31
|
+
{ text: "Germany Q4' 24" },
|
|
32
|
+
{ text: "Edvoy Express" },
|
|
33
|
+
{ text: "Q1 2025 Pipeline" },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
text: "Custom Filter",
|
|
38
|
+
subMenu: [{ text: "Application Intakes" }, { text: "New Students" }],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
disabled: {
|
|
43
|
+
control: "boolean",
|
|
44
|
+
description: "Disables the Menu, making it uneditable and unclickable.",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
} as Meta;
|
|
48
|
+
|
|
49
|
+
const Template: StoryFn = (args) =>
|
|
50
|
+
defineComponent({
|
|
51
|
+
components: { EUIMultiDropdown, ChevronDownStroke },
|
|
52
|
+
setup() {
|
|
53
|
+
const handleMenuItem = (item: any) => {
|
|
54
|
+
console.log("Menu clicked:", item);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleSubMenuItem = (subItem: any) => {
|
|
58
|
+
console.log("Submenu item clicked:", subItem);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return { args, handleMenuItem, handleSubMenuItem };
|
|
62
|
+
},
|
|
63
|
+
template: `<div class="min-h-96">
|
|
64
|
+
<EUIMultiDropdown v-bind="args" v-bind="args" @menuItem="handleMenuItem" @subMenuItem="handleSubMenuItem" /></div>`,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export const Default = Template.bind({});
|
|
68
|
+
Default.args = {
|
|
69
|
+
title: "My Students",
|
|
70
|
+
className: "",
|
|
71
|
+
menuItems: [
|
|
72
|
+
{ text: "All Students" },
|
|
73
|
+
{ text: "My Students" },
|
|
74
|
+
{ text: "Genie Completed Students" },
|
|
75
|
+
{
|
|
76
|
+
text: "Standard Filter",
|
|
77
|
+
subMenu: [
|
|
78
|
+
{ text: "UKI Fair" },
|
|
79
|
+
{ text: "Germany Q4' 24" },
|
|
80
|
+
{ text: "Edvoy Express" },
|
|
81
|
+
{ text: "Q1 2025 Pipeline" },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
text: "Custom Filter",
|
|
86
|
+
subMenu: [{ text: "Application Intakes" }, { text: "New Students" }],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const UseTemplate = Template.bind({});
|
|
92
|
+
(UseTemplate.args = {
|
|
93
|
+
title: "My Students",
|
|
94
|
+
className:
|
|
95
|
+
"px-3 py-2 text-gray-700 hover:text-gray-900 bg-white rounded-md focus:bg-violet-100 group focus:outline-none focus:ring-2 focus:ring-violet-400 focus:ring-opacity-100 hover:bg-gray-100 active:bg-violet-200",
|
|
96
|
+
menuItems: [
|
|
97
|
+
{ text: "All Students" },
|
|
98
|
+
{ text: "My Students" },
|
|
99
|
+
{ text: "Genie Completed Students" },
|
|
100
|
+
{
|
|
101
|
+
text: "Standard Filter",
|
|
102
|
+
subMenu: [
|
|
103
|
+
{ text: "UKI Fair" },
|
|
104
|
+
{ text: "Germany Q4' 24" },
|
|
105
|
+
{ text: "Edvoy Express" },
|
|
106
|
+
{ text: "Q1 2025 Pipeline" },
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
text: "Custom Filter",
|
|
111
|
+
subMenu: [{ text: "Application Intakes" }, { text: "New Students" }],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
(UseTemplate.parameters = {
|
|
116
|
+
docs: {
|
|
117
|
+
source: {
|
|
118
|
+
code: `<script lang="ts" setup>
|
|
119
|
+
const menuItems = [
|
|
120
|
+
{
|
|
121
|
+
"text": "All Students"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"text": "My Students"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"text": "Genie Completed Students"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"text": "Standard Filter",
|
|
131
|
+
"subMenu": [
|
|
132
|
+
{
|
|
133
|
+
"text": "UKI Fair"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"text": "Germany Q4' 24"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"text": "Edvoy Express"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"text": "Q1 2025 Pipeline"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"text": "Custom Filter",
|
|
148
|
+
"subMenu": [
|
|
149
|
+
{
|
|
150
|
+
"text": "Application Intakes"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"text": "New Students"
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const handleMenuItem = (item: any) => {
|
|
160
|
+
console.log("Menu clicked:", item);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const handleSubMenuItem = (subItem: any) => {
|
|
164
|
+
console.log("Submenu item clicked:", subItem);
|
|
165
|
+
};
|
|
166
|
+
</script>
|
|
167
|
+
<template>
|
|
168
|
+
<EUIMultiDropdown :menu-items="menuItems" @menuItem="handleMenuItem" @subMenuItem="handleSubMenuItem">
|
|
169
|
+
<template #dropdownName="{ open }">
|
|
170
|
+
<span>{{ title }}</span>
|
|
171
|
+
<ChevronDownStroke
|
|
172
|
+
:class="open ? 'text-gray-900 rotate-180' : 'text-gray-500'"
|
|
173
|
+
class="transition duration-100 ease-in-out transform rotate-0 size-6 group-hover:text-opacity-80"
|
|
174
|
+
aria-hidden="true"
|
|
175
|
+
/>
|
|
176
|
+
</template>
|
|
177
|
+
<template #menu="{menuitem}">
|
|
178
|
+
{{menuitem.text}}
|
|
179
|
+
</template>
|
|
180
|
+
<template #submenu="{subItem}">
|
|
181
|
+
{{subItem.text}}
|
|
182
|
+
</template>
|
|
183
|
+
</EUIMultiDropdown>
|
|
184
|
+
</template>`,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="relative">
|
|
3
|
+
<!-- Main Dropdown Button -->
|
|
4
|
+
<button
|
|
5
|
+
type="button"
|
|
6
|
+
ref="dropdownButton"
|
|
7
|
+
:class="['inline-flex items-center text-sm font-semibold gap-x-2 capitalize outline-none focus:outline-none', className]"
|
|
8
|
+
:disabled="disabled"
|
|
9
|
+
@click="toggleDropdown()"
|
|
10
|
+
>
|
|
11
|
+
<slot name="dropdownName" :open="isOpen">
|
|
12
|
+
{{ title }}
|
|
13
|
+
<ChevronDownStroke :class="isOpen ? 'text-gray-900 rotate-180' : 'text-gray-500'"
|
|
14
|
+
class="transition duration-100 ease-in-out transform rotate-0 size-6 group-hover:text-opacity-80"
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
/>
|
|
17
|
+
</slot>
|
|
18
|
+
</button>
|
|
19
|
+
<!-- Menu lists -->
|
|
20
|
+
<div v-if="isOpen && menuItems.length" class="absolute left-0 z-0 p-2 mt-1 transition-all duration-300 ease-in-out bg-white border border-gray-200 border-solid rounded-lg shadow-2xl top-full shadow-gray-300 min-w-36 max-w-64 w-max" @click.stop>
|
|
21
|
+
<div
|
|
22
|
+
v-for="item in menuItems"
|
|
23
|
+
:key="item.text"
|
|
24
|
+
class="relative flex items-center px-4 py-2 rounded-lg cursor-pointer hover:bg-gray-100"
|
|
25
|
+
@mouseenter="setActiveMenuItem(item.text)"
|
|
26
|
+
@mouseleave="clearActiveMenuItem"
|
|
27
|
+
@click.stop="$emit('menuItem', item)"
|
|
28
|
+
>
|
|
29
|
+
<div class="flex items-center justify-between w-full gap-2 text-sm font-medium text-gray-800 break-words hover:text-gray-900">
|
|
30
|
+
<slot name="menu" :menuitem="item">
|
|
31
|
+
{{ item.text }}
|
|
32
|
+
<ChevronDownStroke v-if="item.subMenu" :class="activeMenuItem === item.text ? 'text-gray-900 -rotate-90' : 'text-gray-500 rotate-0'"
|
|
33
|
+
class="ml-auto transition duration-300 ease-in-out transform size-6 group-hover:text-opacity-80"
|
|
34
|
+
aria-hidden="true" />
|
|
35
|
+
</slot>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- Sub-menu lists-->
|
|
39
|
+
<div v-if="item.subMenu && activeMenuItem === item.text" class="absolute top-0 z-10 transition-all duration-300 ease-in-out left-full min-w-36 max-w-64 w-max">
|
|
40
|
+
<div class="p-2 bg-white border border-gray-200 border-solid rounded-lg shadow-2xl ms-2 shadow-gray-300">
|
|
41
|
+
<div
|
|
42
|
+
v-for="subItem in item.subMenu"
|
|
43
|
+
:key="subItem.text"
|
|
44
|
+
class="flex items-center justify-between gap-2 px-3 py-2 text-sm font-medium text-gray-700 rounded-lg cursor-pointer hover:bg-gray-100 hover:text-gray-900"
|
|
45
|
+
@click.stop="$emit('subMenuItem', subItem)"
|
|
46
|
+
>
|
|
47
|
+
<slot name="submenu" :subItem="subItem">
|
|
48
|
+
{{ subItem.text }}
|
|
49
|
+
</slot>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
import { ref, defineProps, PropType } from "vue";
|
|
61
|
+
import { onClickOutside } from "@vueuse/core";
|
|
62
|
+
import ChevronDownStroke from "../../assets/svg/ChevronDownStroke.vue";
|
|
63
|
+
|
|
64
|
+
interface MenuItem {
|
|
65
|
+
text: string;
|
|
66
|
+
subMenu?: MenuItem[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
defineProps({
|
|
70
|
+
title: {
|
|
71
|
+
type: String,
|
|
72
|
+
default: "My Students",
|
|
73
|
+
},
|
|
74
|
+
className: {
|
|
75
|
+
type: String,
|
|
76
|
+
required: false,
|
|
77
|
+
},
|
|
78
|
+
menuItems: {
|
|
79
|
+
type: Array as PropType<MenuItem[]>,
|
|
80
|
+
default: () => [
|
|
81
|
+
{ text: "All Students" },
|
|
82
|
+
{ text: "My Students" },
|
|
83
|
+
{ text: "Genie Completed Students" },
|
|
84
|
+
{
|
|
85
|
+
text: "Standard Filter",
|
|
86
|
+
subMenu: [
|
|
87
|
+
{ text: "UKI Fair" },
|
|
88
|
+
{ text: "Germany Q4' 24" },
|
|
89
|
+
{ text: "Edvoy Express" },
|
|
90
|
+
{ text: "Q1 2025 Pipeline" }
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
text: "Custom Filter",
|
|
95
|
+
subMenu: [
|
|
96
|
+
{ text: "Application Intakes" },
|
|
97
|
+
{ text: "New Students" }
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
disabled: Boolean,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const isOpen = ref(false);
|
|
106
|
+
const activeMenuItem = ref<string | null>(null);
|
|
107
|
+
const dropdownButton = ref<HTMLElement | null>(null);
|
|
108
|
+
|
|
109
|
+
defineEmits(['subMenuItem', 'menuItem'])
|
|
110
|
+
|
|
111
|
+
const toggleDropdown = () => {
|
|
112
|
+
isOpen.value = !isOpen.value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const setActiveMenuItem = (text:string) => {
|
|
116
|
+
activeMenuItem.value = text;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const clearActiveMenuItem = () => {
|
|
120
|
+
activeMenuItem.value = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
onClickOutside(dropdownButton, () => {
|
|
124
|
+
isOpen.value = false;
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
|
|
128
|
+
<style lang="scss" scoped>
|
|
129
|
+
</style>
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/vue3";
|
|
2
|
+
import EUIErrorMessage from "./EUIErrorMessage.vue"; // Adjust the path if necessary
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Example/ErrorMessage",
|
|
6
|
+
component: EUIErrorMessage,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
argTypes: {
|
|
9
|
+
name: {
|
|
10
|
+
control: "text", // Allows setting the field name
|
|
11
|
+
description: "The name of the input field, used as a key to display the error message",
|
|
12
|
+
},
|
|
13
|
+
errors: {
|
|
14
|
+
control: "object", // Allows setting errors as an object
|
|
15
|
+
description: "Object containing validation errors where keys are field names and values are the error messages",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
} satisfies Meta<typeof EUIErrorMessage>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
// Default story to demonstrate error display
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
name: "username",
|
|
27
|
+
errors: {
|
|
28
|
+
username: "This field is required.",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Story for showing custom error message
|
|
34
|
+
export const CustomError: Story = {
|
|
35
|
+
args: {
|
|
36
|
+
name: "email",
|
|
37
|
+
errors: {
|
|
38
|
+
email: "Please provide a valid email address.",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<template v-if="Array.isArray(errors)">
|
|
3
|
+
<div class="text-red-500 text-xs font-medium first-letter:uppercase">
|
|
4
|
+
{{ errors?.at(0)?.$message ? errors?.at(0)?.$message : errors.at(0) }}
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
<template v-else>
|
|
8
|
+
<div class="text-red-500 text-xs font-medium first-letter:uppercase">
|
|
9
|
+
{{ name ? errors?.[name] : errors }}
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { PropType, toRefs } from "vue";
|
|
16
|
+
import { ValidationErrors, ErrorObject } from "../../utils/types";
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
name: { type: String, required: true },
|
|
19
|
+
errors: {
|
|
20
|
+
type: Object as PropType<ValidationErrors | ErrorObject[]>,
|
|
21
|
+
required: true,
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const { errors, name } = toRefs(props);
|
|
25
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "../style.scss";
|
|
2
|
+
export { default as EUIButton } from "./button/EUIButton.vue";
|
|
3
|
+
export { default as EUIInput } from "./input/EUIInput.vue";
|
|
4
|
+
export { default as EUIInputNormal } from "./inputNormal/EUIInputNormal.vue";
|
|
5
|
+
export { default as EUITelephone } from "./telephone/EUITelephone.vue";
|
|
6
|
+
export { default as EUITextArea } from "./textArea/EUITextArea.vue";
|
|
7
|
+
|
|
8
|
+
export { default as EUISelect } from "./select/EUISelect.vue";
|
|
9
|
+
export { default as EUISelectSearch } from "./selectSearch/EUISelectSearch.vue";
|
|
10
|
+
export { default as EUICheckbox } from "./checkbox/EUICheckbox.vue";
|
|
11
|
+
export { default as EUIRadio } from "./radio/EUIRadio.vue";
|
|
12
|
+
export { default as EUIToggle } from "./toggle/EUIToggle.vue";
|
|
13
|
+
|
|
14
|
+
export { default as EUIAvatar } from "./avatar/EUIAvatar.vue";
|
|
15
|
+
export { default as EUIStepperTimeline } from "./stepperTimeline/EUIStepperTimeline.vue";
|
|
16
|
+
export { default as EUIStepperVertical } from "./stepperTimeline/EUIStepperVertical.vue";
|
|
17
|
+
export { default as EUIStepperHorizontal } from "./stepperTimeline/EUIStepperHorizontal.vue";
|
|
18
|
+
|
|
19
|
+
export { default as EUIAccordion } from "./accordion/EUIAccordion.vue";
|
|
20
|
+
export { default as EUIPopover } from "./popover/EUIPopover.vue";
|
|
21
|
+
export { default as EUIModal } from "./modal/EUIModal.vue";
|
|
22
|
+
export { default as EUISlideover } from "./slideover/EUISlideover.vue";
|
|
23
|
+
export { default as EUIDatepicker } from "./datepicker/EUIDatepicker.vue";
|
|
24
|
+
|
|
25
|
+
export { default as EUITabs } from "./tabs/EUITabs.vue";
|
|
26
|
+
export { default as EUIPillSelect } from "./pillSelect/EUIPillSelect.vue";
|
|
27
|
+
export { default as EUITimeLine } from "./timeLine/EUITimeLine.vue";
|
|
28
|
+
export { default as EUITag } from "./tag/EUITag.vue";
|
|
29
|
+
|
|
30
|
+
export { default as EUIDashboardTable } from "./table/EUIDashboardTable.vue";
|
|
31
|
+
export { default as EUIPagination } from "./table/EUIPagination.vue";
|
|
32
|
+
export { default as EUIPageLimit } from "./table/EUIPageLimit.vue";
|
|
33
|
+
export { default as EUITableCheckbox } from "./table/EUITableCheckbox.vue";
|
|
34
|
+
|
|
35
|
+
export { default as EUITable } from "./table/EUITable.vue";
|
|
36
|
+
export { default as EUIStudentPagination } from "./table/EUIStudentPagination.vue";
|
|
37
|
+
export { default as EUIMultiDropdown } from "./dropdown/EUIMultiDropdown.vue";
|
|
38
|
+
|
|
39
|
+
export { default as EUILoader } from "./loader/EUILoader.vue";
|
|
40
|
+
export { default as EUICircleLoader } from "./loader/EUICircleLoader.vue";
|
|
41
|
+
export { default as EUICubeLoader } from "./loader/EUICubeLoader.vue";
|
|
42
|
+
export { default as EUISquareLoader } from "./loader/EUISquareLoader.vue";
|
|
43
|
+
export { default as EUIErrorMessage } from "./errorMessage/EUIErrorMessage.vue";
|
|
44
|
+
|
|
45
|
+
export { default as EUITooltip } from "./tooltip/EUITooltip.vue";
|
|
46
|
+
export { default as EUISearch } from "./searchInput/EUISearch.vue";
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { expect, userEvent, within } from "@storybook/test";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/vue3";
|
|
3
|
+
import EUIInput from "./EUIInput.vue";
|
|
4
|
+
import { UserCircleIcon } from "@heroicons/vue/24/outline";
|
|
5
|
+
|
|
6
|
+
// Meta configuration for the component's stories
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Forms/Input",
|
|
9
|
+
component: EUIInput,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
argTypes: {
|
|
12
|
+
modelValue: {
|
|
13
|
+
control: "text",
|
|
14
|
+
description:
|
|
15
|
+
"The value of the input. This is a two-way binding property, used to reflect the current value of the input field.",
|
|
16
|
+
},
|
|
17
|
+
name: {
|
|
18
|
+
control: "text",
|
|
19
|
+
description:
|
|
20
|
+
"The `name` attribute of the input, typically used for form identification and validation.",
|
|
21
|
+
},
|
|
22
|
+
label: {
|
|
23
|
+
control: "text",
|
|
24
|
+
description:
|
|
25
|
+
"The label for the input field, usually displayed above or inside the input.",
|
|
26
|
+
},
|
|
27
|
+
type: {
|
|
28
|
+
control: {
|
|
29
|
+
type: "select",
|
|
30
|
+
options: [
|
|
31
|
+
"text",
|
|
32
|
+
"number",
|
|
33
|
+
"email",
|
|
34
|
+
"password",
|
|
35
|
+
"search",
|
|
36
|
+
"date",
|
|
37
|
+
"url",
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
description:
|
|
41
|
+
"Specifies the type of input, such as `text`, `number`, `email`, etc.",
|
|
42
|
+
},
|
|
43
|
+
placeholder: {
|
|
44
|
+
control: "text",
|
|
45
|
+
description:
|
|
46
|
+
"A short hint that describes the expected value when the input is empty.",
|
|
47
|
+
},
|
|
48
|
+
autoFocus: {
|
|
49
|
+
control: "boolean",
|
|
50
|
+
description:
|
|
51
|
+
"Automatically focuses the input field when the page loads or the component mounts.",
|
|
52
|
+
},
|
|
53
|
+
required: {
|
|
54
|
+
control: "boolean",
|
|
55
|
+
description:
|
|
56
|
+
"Marks the field as required, showing validation for non-empty input.",
|
|
57
|
+
},
|
|
58
|
+
readonly: {
|
|
59
|
+
control: "boolean",
|
|
60
|
+
description:
|
|
61
|
+
"Makes the input field read-only, which means users can see the value but cannot edit it.",
|
|
62
|
+
},
|
|
63
|
+
disabled: {
|
|
64
|
+
control: "boolean",
|
|
65
|
+
description:
|
|
66
|
+
"Disables the input field, making it uneditable and unclickable.",
|
|
67
|
+
},
|
|
68
|
+
iconType: {
|
|
69
|
+
control: "select",
|
|
70
|
+
options: ["", "startIcon", "endIcon"],
|
|
71
|
+
description:
|
|
72
|
+
"Defines the position of the icon. It can be placed at the `start` or `end` of the input field.",
|
|
73
|
+
},
|
|
74
|
+
icon: {
|
|
75
|
+
control: { type: "text" },
|
|
76
|
+
description:
|
|
77
|
+
"Specifies an SVG icon or icon component to be displayed inside the input field.",
|
|
78
|
+
},
|
|
79
|
+
errors: {
|
|
80
|
+
control: "object",
|
|
81
|
+
description:
|
|
82
|
+
"An object containing error messages or validation information, typically used for form validation.",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
} satisfies Meta<typeof EUIInput>;
|
|
86
|
+
|
|
87
|
+
export default meta;
|
|
88
|
+
type Story = StoryObj<typeof meta>;
|
|
89
|
+
|
|
90
|
+
// Default story with minimum props
|
|
91
|
+
export const Default: Story = {
|
|
92
|
+
args: {
|
|
93
|
+
modelValue: "",
|
|
94
|
+
label: "User Name",
|
|
95
|
+
type: "text",
|
|
96
|
+
placeholder: "Enter fullname here..",
|
|
97
|
+
name: "userName",
|
|
98
|
+
required: false,
|
|
99
|
+
readonly: false,
|
|
100
|
+
disabled: false,
|
|
101
|
+
autoFocus: false,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const TypeOfInput: Story = {
|
|
106
|
+
args: {
|
|
107
|
+
modelValue: "",
|
|
108
|
+
name: "inputName",
|
|
109
|
+
label: "Email Address",
|
|
110
|
+
type: "email",
|
|
111
|
+
placeholder: "Enter your email here...",
|
|
112
|
+
disabled: false,
|
|
113
|
+
errors: {
|
|
114
|
+
message: "Enter valid mobile number",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
render: (args) => ({
|
|
118
|
+
components: { EUIInput },
|
|
119
|
+
setup() {
|
|
120
|
+
return { args };
|
|
121
|
+
},
|
|
122
|
+
template: '<div class="max-w-xl"><EUIInput v-bind="args" /></div>',
|
|
123
|
+
}),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Add Storybook interaction test
|
|
127
|
+
export const InputValue: Story = {
|
|
128
|
+
args: {
|
|
129
|
+
modelValue: "John Cena",
|
|
130
|
+
label: "User Name",
|
|
131
|
+
placeholder: "Enter fullname here..",
|
|
132
|
+
name: "inputName",
|
|
133
|
+
},
|
|
134
|
+
play: async ({ canvasElement }) => {
|
|
135
|
+
const canvas = within(canvasElement);
|
|
136
|
+
const inputElement = canvas.getByPlaceholderText("Enter fullname here..");
|
|
137
|
+
await userEvent.type(inputElement, "Storybook Test");
|
|
138
|
+
await expect(inputElement).toBe("Storybook Test");
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const IconUsingStart: Story = {
|
|
143
|
+
args: {
|
|
144
|
+
iconType: "startIcon",
|
|
145
|
+
icon: UserCircleIcon,
|
|
146
|
+
label: "User Name",
|
|
147
|
+
placeholder: "Enter fullname here..",
|
|
148
|
+
name: "inputStarIcon",
|
|
149
|
+
modelValue: "",
|
|
150
|
+
},
|
|
151
|
+
play: async ({ canvasElement }) => {
|
|
152
|
+
const canvas = within(canvasElement);
|
|
153
|
+
const inputElement = canvas.getByPlaceholderText("Enter fullname here..");
|
|
154
|
+
await userEvent.type(inputElement, "Jane Doe");
|
|
155
|
+
expect(inputElement).toBe("Jane Doe");
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const IconUsingEnd: Story = {
|
|
160
|
+
args: {
|
|
161
|
+
modelValue: "",
|
|
162
|
+
iconType: "endIcon",
|
|
163
|
+
icon: UserCircleIcon,
|
|
164
|
+
label: "User Name",
|
|
165
|
+
placeholder: "Enter fullname here..",
|
|
166
|
+
name: "inputEndIcon",
|
|
167
|
+
},
|
|
168
|
+
play: async ({ canvasElement }) => {
|
|
169
|
+
const canvas = within(canvasElement);
|
|
170
|
+
const inputElement = canvas.getByPlaceholderText("Enter fullname here..");
|
|
171
|
+
await userEvent.type(inputElement, "Jane Doe");
|
|
172
|
+
expect(inputElement).toBe("Jane Doe");
|
|
173
|
+
},
|
|
174
|
+
};
|