edvoyui-component-library-test-flight 0.0.223 → 0.0.225
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/components/dropdown/EUIMultiDropdown.d.ts +21 -0
- package/dist/components/dropdown/EUIMultiDropdown.vue +66 -10
- package/dist/components/searchexpand/EUISearchExpand.vue +25 -6
- package/dist/edvoy-ui.cjs.js +11 -11
- package/dist/edvoy-ui.es.js +4153 -4111
- package/dist/edvoy-ui.umd.js +11 -11
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ declare function __VLS_template(): {
|
|
|
19
19
|
}): any;
|
|
20
20
|
};
|
|
21
21
|
refs: {
|
|
22
|
+
dropdownRoot: HTMLDivElement;
|
|
22
23
|
dropdownButton: HTMLButtonElement;
|
|
23
24
|
dropdownMenu: HTMLDivElement;
|
|
24
25
|
};
|
|
@@ -67,6 +68,15 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
|
|
|
67
68
|
type: PropType<"top" | "bottom" | "left" | "right">;
|
|
68
69
|
default: string;
|
|
69
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Keep the dropdown open while the user interacts with content inside the menu
|
|
73
|
+
* (search fields, row actions). Selecting an item and clicking outside still close it.
|
|
74
|
+
* Off by default so existing menus keep dismissing on any click inside them.
|
|
75
|
+
*/
|
|
76
|
+
keepOpenOnContentClick: {
|
|
77
|
+
type: BooleanConstructor;
|
|
78
|
+
default: boolean;
|
|
79
|
+
};
|
|
70
80
|
}>, {}, {}, {}, {}, import('../../../node_modules/vue').ComponentOptionsMixin, import('../../../node_modules/vue').ComponentOptionsMixin, {
|
|
71
81
|
subMenuItem: (...args: any[]) => void;
|
|
72
82
|
menuItem: (...args: any[]) => void;
|
|
@@ -113,6 +123,15 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
|
|
|
113
123
|
type: PropType<"top" | "bottom" | "left" | "right">;
|
|
114
124
|
default: string;
|
|
115
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* Keep the dropdown open while the user interacts with content inside the menu
|
|
128
|
+
* (search fields, row actions). Selecting an item and clicking outside still close it.
|
|
129
|
+
* Off by default so existing menus keep dismissing on any click inside them.
|
|
130
|
+
*/
|
|
131
|
+
keepOpenOnContentClick: {
|
|
132
|
+
type: BooleanConstructor;
|
|
133
|
+
default: boolean;
|
|
134
|
+
};
|
|
116
135
|
}>> & Readonly<{
|
|
117
136
|
onSubMenuItem?: ((...args: any[]) => any) | undefined;
|
|
118
137
|
onMenuItem?: ((...args: any[]) => any) | undefined;
|
|
@@ -123,7 +142,9 @@ declare const __VLS_component: import('../../../node_modules/vue').DefineCompone
|
|
|
123
142
|
placement: "top" | "bottom" | "right" | "left";
|
|
124
143
|
isSolidArrow: boolean;
|
|
125
144
|
menuItems: MenuItem[];
|
|
145
|
+
keepOpenOnContentClick: boolean;
|
|
126
146
|
}, {}, {}, {}, string, import('../../../node_modules/vue').ComponentProvideOptions, true, {
|
|
147
|
+
dropdownRoot: HTMLDivElement;
|
|
127
148
|
dropdownButton: HTMLButtonElement;
|
|
128
149
|
dropdownMenu: HTMLDivElement;
|
|
129
150
|
}, HTMLDivElement>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="relative">
|
|
2
|
+
<div ref="dropdownRoot" class="relative">
|
|
3
3
|
<!-- Main Dropdown Button -->
|
|
4
4
|
<button
|
|
5
5
|
type="button"
|
|
@@ -34,8 +34,10 @@
|
|
|
34
34
|
:key="item.text"
|
|
35
35
|
class="relative flex items-center px-4 py-2 rounded-lg cursor-pointer hover:bg-gray-100"
|
|
36
36
|
@mouseenter="setActiveMenuItem(item.text)"
|
|
37
|
-
@mouseleave="
|
|
38
|
-
@
|
|
37
|
+
@mouseleave="scheduleClearActiveMenuItem(item.text)"
|
|
38
|
+
@focusin="setActiveMenuItem(item.text)"
|
|
39
|
+
@focusout="scheduleClearActiveMenuItem(item.text)"
|
|
40
|
+
@click.stop="selectMenuItem(item)"
|
|
39
41
|
>
|
|
40
42
|
<div
|
|
41
43
|
class="flex items-center justify-between w-full gap-2 text-sm font-medium text-gray-800 break-words hover:text-gray-900"
|
|
@@ -59,6 +61,7 @@
|
|
|
59
61
|
<div
|
|
60
62
|
v-if="item.subMenu && activeMenuItem === item.text"
|
|
61
63
|
:class="['absolute top-0 z-10 transition-all duration-300 ease-in-out min-w-32 max-w-64 w-max', placement === 'right' ? 'right-full' : 'left-full']"
|
|
64
|
+
@mouseenter="setActiveMenuItem(item.text)"
|
|
62
65
|
>
|
|
63
66
|
<div
|
|
64
67
|
class="bg-white border border-gray-200 border-solid rounded-lg shadow-2xl ms-2 shadow-gray-300"
|
|
@@ -66,7 +69,7 @@
|
|
|
66
69
|
<div
|
|
67
70
|
v-if="item.enableAction"
|
|
68
71
|
class="flex items-center justify-center w-full gap-1 px-6 py-3 text-sm font-medium text-gray-900 bg-purple-100 rounded-t-md"
|
|
69
|
-
@click.prevent="
|
|
72
|
+
@click.stop.prevent="triggerActionItem()"
|
|
70
73
|
>
|
|
71
74
|
<slot name="actionName">{{ "+ Action Name" }}</slot>
|
|
72
75
|
</div>
|
|
@@ -77,7 +80,7 @@
|
|
|
77
80
|
v-for="subItem in item.subMenu"
|
|
78
81
|
:key="subItem.text"
|
|
79
82
|
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"
|
|
80
|
-
@click.stop="
|
|
83
|
+
@click.stop="selectSubMenuItem(subItem)"
|
|
81
84
|
>
|
|
82
85
|
<slot name="submenu" :subItem="subItem">
|
|
83
86
|
{{ subItem.text }}
|
|
@@ -156,32 +159,84 @@ const props = defineProps({
|
|
|
156
159
|
type: String as PropType<"top" | "bottom" | "left" | "right">,
|
|
157
160
|
default: "bottom",
|
|
158
161
|
},
|
|
162
|
+
/**
|
|
163
|
+
* Keep the dropdown open while the user interacts with content inside the menu
|
|
164
|
+
* (search fields, row actions). Selecting an item and clicking outside still close it.
|
|
165
|
+
* Off by default so existing menus keep dismissing on any click inside them.
|
|
166
|
+
*/
|
|
167
|
+
keepOpenOnContentClick: {
|
|
168
|
+
type: Boolean,
|
|
169
|
+
default: false,
|
|
170
|
+
},
|
|
159
171
|
});
|
|
160
172
|
|
|
161
173
|
const isOpen = ref(false);
|
|
162
174
|
const activeMenuItem = ref<string | null>(null);
|
|
175
|
+
const dropdownRoot = ref<HTMLElement | null>(null);
|
|
163
176
|
const dropdownButton = ref<HTMLElement | null>(null);
|
|
164
177
|
const dropdownMenu = ref<HTMLElement | null>(null);
|
|
165
178
|
const resolvedPlacement = ref<"top" | "bottom" | "left" | "right">(
|
|
166
179
|
props.placement
|
|
167
180
|
);
|
|
181
|
+
let activeMenuCloseTimer: ReturnType<typeof setTimeout> | undefined;
|
|
168
182
|
|
|
169
|
-
defineEmits(["subMenuItem", "menuItem", "actionItem"]);
|
|
183
|
+
const emit = defineEmits(["subMenuItem", "menuItem", "actionItem"]);
|
|
170
184
|
|
|
171
185
|
const toggleDropdown = () => {
|
|
172
|
-
isOpen.value
|
|
186
|
+
if (isOpen.value) {
|
|
187
|
+
closeDropdown();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
isOpen.value = true;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const closeDropdown = () => {
|
|
195
|
+
clearTimeout(activeMenuCloseTimer);
|
|
196
|
+
isOpen.value = false;
|
|
197
|
+
activeMenuItem.value = null;
|
|
173
198
|
};
|
|
174
199
|
|
|
175
200
|
const setActiveMenuItem = (text: string) => {
|
|
201
|
+
clearTimeout(activeMenuCloseTimer);
|
|
176
202
|
activeMenuItem.value = text;
|
|
177
203
|
};
|
|
178
204
|
|
|
179
|
-
const
|
|
180
|
-
|
|
205
|
+
const scheduleClearActiveMenuItem = (text: string) => {
|
|
206
|
+
clearTimeout(activeMenuCloseTimer);
|
|
207
|
+
activeMenuCloseTimer = setTimeout(() => {
|
|
208
|
+
// Interactive submenu content (for example, search) must stay mounted while focused.
|
|
209
|
+
if (dropdownMenu.value?.contains(document.activeElement)) return;
|
|
210
|
+
if (activeMenuItem.value === text) activeMenuItem.value = null;
|
|
211
|
+
}, 150);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const selectMenuItem = (item: MenuItem) => {
|
|
215
|
+
emit("menuItem", item);
|
|
216
|
+
closeDropdown();
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const selectSubMenuItem = (subItem: MenuItem) => {
|
|
220
|
+
emit("subMenuItem", subItem);
|
|
221
|
+
closeDropdown();
|
|
181
222
|
};
|
|
182
223
|
|
|
224
|
+
const triggerActionItem = () => {
|
|
225
|
+
emit("actionItem", "action");
|
|
226
|
+
closeDropdown();
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// A click anywhere outside the dropdown always closes it.
|
|
230
|
+
onClickOutside(dropdownRoot, () => {
|
|
231
|
+
closeDropdown();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Legacy behaviour: the watcher used to sit on the trigger button alone, so clicks on the
|
|
235
|
+
// menu itself counted as "outside" and dismissed it. Menus that host interactive content
|
|
236
|
+
// opt out with `keepOpenOnContentClick` - they close on selection instead.
|
|
183
237
|
onClickOutside(dropdownButton, () => {
|
|
184
|
-
|
|
238
|
+
if (props.keepOpenOnContentClick) return;
|
|
239
|
+
closeDropdown();
|
|
185
240
|
});
|
|
186
241
|
|
|
187
242
|
const updateDropdownPlacement = () => {
|
|
@@ -233,6 +288,7 @@ onMounted(() => {
|
|
|
233
288
|
});
|
|
234
289
|
|
|
235
290
|
onBeforeUnmount(() => {
|
|
291
|
+
clearTimeout(activeMenuCloseTimer);
|
|
236
292
|
window.removeEventListener("resize", updateDropdownPlacement);
|
|
237
293
|
window.removeEventListener("scroll", updateDropdownPlacement, true);
|
|
238
294
|
});
|
|
@@ -63,7 +63,16 @@
|
|
|
63
63
|
</template>
|
|
64
64
|
|
|
65
65
|
<script lang="ts" setup>
|
|
66
|
-
import {
|
|
66
|
+
import {
|
|
67
|
+
computed,
|
|
68
|
+
nextTick,
|
|
69
|
+
onBeforeUnmount,
|
|
70
|
+
onMounted,
|
|
71
|
+
PropType,
|
|
72
|
+
ref,
|
|
73
|
+
toRefs,
|
|
74
|
+
watch,
|
|
75
|
+
} from "vue";
|
|
67
76
|
import SearchBigZoomIn from "../../assets/svg/SearchBigZoomIn.vue";
|
|
68
77
|
|
|
69
78
|
const props = defineProps({
|
|
@@ -87,12 +96,13 @@ const emit = defineEmits(["update:modelValue"]);
|
|
|
87
96
|
|
|
88
97
|
const input = ref<HTMLInputElement>();
|
|
89
98
|
const isExpanded = ref(true);
|
|
90
|
-
const searchQuery = ref();
|
|
99
|
+
const searchQuery = ref<string | number>(props.modelValue ?? "");
|
|
91
100
|
const componentWrapper = ref<HTMLElement | null>(null);
|
|
92
101
|
|
|
93
|
-
function expandInput() {
|
|
102
|
+
async function expandInput() {
|
|
94
103
|
isExpanded.value = true;
|
|
95
|
-
|
|
104
|
+
await nextTick();
|
|
105
|
+
input.value?.focus();
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
const inputValue = computed(() => {
|
|
@@ -124,10 +134,19 @@ watch(
|
|
|
124
134
|
{ immediate: true, deep: true }
|
|
125
135
|
);
|
|
126
136
|
|
|
137
|
+
watch(
|
|
138
|
+
() => props.modelValue,
|
|
139
|
+
(newValue) => {
|
|
140
|
+
if (newValue !== searchQuery.value) {
|
|
141
|
+
searchQuery.value = newValue ?? "";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
127
146
|
onMounted(() => {
|
|
128
147
|
document.addEventListener("click", handleOutsideClick);
|
|
129
|
-
if (
|
|
130
|
-
|
|
148
|
+
if (isExpanded.value) {
|
|
149
|
+
nextTick(() => input.value?.focus());
|
|
131
150
|
}
|
|
132
151
|
});
|
|
133
152
|
|