edvoyui-component-library-test-flight 0.0.255 → 0.0.257
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/searchexpand/EUISearchExpand.d.ts +17 -34
- package/dist/components/searchexpand/EUISearchExpand.vue +113 -116
- package/dist/components/table/UTable.vue +1 -1
- package/dist/edvoy-ui.cjs.js +8 -8
- package/dist/edvoy-ui.css +1 -1
- package/dist/edvoy-ui.es.js +789 -811
- package/dist/edvoy-ui.umd.js +22 -22
- package/package.json +1 -1
|
@@ -1,40 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
default: string;
|
|
14
|
-
};
|
|
15
|
-
}>, {}, {}, {}, {}, import('../../../node_modules/vue').ComponentOptionsMixin, import('../../../node_modules/vue').ComponentOptionsMixin, {
|
|
16
|
-
"update:modelValue": (...args: any[]) => void;
|
|
17
|
-
}, string, import('../../../node_modules/vue').PublicProps, Readonly<import('../../../node_modules/vue').ExtractPropTypes<{
|
|
18
|
-
modelValue: {
|
|
19
|
-
type: (StringConstructor | NumberConstructor)[];
|
|
20
|
-
default: string;
|
|
21
|
-
};
|
|
22
|
-
searchSync: {
|
|
23
|
-
type: BooleanConstructor;
|
|
24
|
-
default: boolean;
|
|
25
|
-
};
|
|
26
|
-
type: {
|
|
27
|
-
type: PropType<"text" | "number" | "email" | "password" | "search">;
|
|
28
|
-
default: string;
|
|
29
|
-
};
|
|
30
|
-
}>> & Readonly<{
|
|
31
|
-
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
1
|
+
type InputType = "text" | "number" | "email" | "password" | "search";
|
|
2
|
+
interface Props {
|
|
3
|
+
autoFocus?: boolean;
|
|
4
|
+
modelValue?: string | number;
|
|
5
|
+
defaultExpand?: boolean;
|
|
6
|
+
searchSync?: boolean;
|
|
7
|
+
type?: InputType;
|
|
8
|
+
}
|
|
9
|
+
declare const _default: import('../../../node_modules/vue').DefineComponent<Props, {}, {}, {}, {}, import('../../../node_modules/vue').ComponentOptionsMixin, import('../../../node_modules/vue').ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: string | number) => any;
|
|
11
|
+
}, string, import('../../../node_modules/vue').PublicProps, Readonly<Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
32
13
|
}>, {
|
|
33
|
-
type:
|
|
14
|
+
type: InputType;
|
|
34
15
|
modelValue: string | number;
|
|
16
|
+
autoFocus: boolean;
|
|
17
|
+
defaultExpand: boolean;
|
|
35
18
|
searchSync: boolean;
|
|
36
|
-
}, {}, {}, {}, string, import('../../../node_modules/vue').ComponentProvideOptions,
|
|
19
|
+
}, {}, {}, {}, string, import('../../../node_modules/vue').ComponentProvideOptions, false, {
|
|
37
20
|
componentWrapper: HTMLDivElement;
|
|
38
|
-
|
|
21
|
+
inputRef: HTMLInputElement;
|
|
39
22
|
}, HTMLDivElement>;
|
|
40
23
|
export default _default;
|
|
@@ -1,128 +1,146 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative rounded-full size-10">
|
|
3
|
-
<div class="absolute top-0 right-0">
|
|
3
|
+
<div ref="componentWrapper" class="absolute top-0 right-0 z-50">
|
|
4
4
|
<div
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
:class="[
|
|
6
|
+
'relative flex h-10 items-center rounded-full bg-gray-100 ring-offset-0',
|
|
7
|
+
'transition-all duration-300 ease-in-out',
|
|
8
|
+
'border border-gray-200 focus-within:border-gray-100',
|
|
9
|
+
'focus-within:ring-2 focus-within:ring-purple-500',
|
|
10
|
+
isExpanded
|
|
11
|
+
? 'w-72 group-focus-within:w-72 text-gray-400'
|
|
12
|
+
: 'w-10 text-gray-500',
|
|
13
|
+
]"
|
|
14
|
+
@click.stop="expandInput"
|
|
8
15
|
>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
<SearchBigZoomIn
|
|
17
|
+
class="absolute text-current pointer-events-none left-2 top-2 size-6"
|
|
18
|
+
/>
|
|
19
|
+
|
|
20
|
+
<!-- Expand trigger -->
|
|
21
|
+
<button
|
|
22
|
+
v-if="!isExpanded"
|
|
23
|
+
type="button"
|
|
24
|
+
class="absolute inset-0 rounded-full cursor-pointer"
|
|
25
|
+
aria-label="Open search"
|
|
26
|
+
@click="expandInput"
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
<!-- Search input -->
|
|
30
|
+
<input
|
|
31
|
+
v-else
|
|
32
|
+
ref="inputRef"
|
|
33
|
+
v-model="searchQuery"
|
|
34
|
+
:type="inputType"
|
|
35
|
+
placeholder="Search here..."
|
|
36
|
+
autocomplete="off"
|
|
37
|
+
class="w-full h-10 text-sm font-medium text-gray-900 bg-transparent outline-none ps-10 pe-10"
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
<!-- Clear -->
|
|
41
|
+
<button
|
|
42
|
+
v-if="isExpanded && hasSearchValue"
|
|
43
|
+
type="button"
|
|
44
|
+
class="absolute inset-y-0 z-20 flex items-center justify-center text-gray-500 transition-colors pointer-events-auto right-2 hover:text-red-500"
|
|
45
|
+
@mousedown.prevent
|
|
46
|
+
@click="clearSearch"
|
|
47
|
+
>
|
|
48
|
+
<span
|
|
49
|
+
class="flex items-center justify-center p-1 bg-white rounded-full hover:bg-red-50 size-6"
|
|
17
50
|
>
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<button
|
|
23
|
-
v-if="isExpanded"
|
|
24
|
-
type="button"
|
|
25
|
-
aria-label="Clear search"
|
|
26
|
-
:class="
|
|
27
|
-
inputValue ? ' absolute inset-y-0 right-3 ' : ' hidden '
|
|
28
|
-
"
|
|
29
|
-
@mousedown.prevent
|
|
30
|
-
@click.stop="clearSearch"
|
|
31
|
-
>
|
|
32
|
-
<svg
|
|
33
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
34
|
-
fill="none"
|
|
35
|
-
viewBox="0 0 24 24"
|
|
36
|
-
stroke-width="1.5"
|
|
37
|
-
stroke="currentColor"
|
|
38
|
-
class="size-5"
|
|
39
|
-
>
|
|
40
|
-
<!-- <path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
|
41
|
-
-->
|
|
42
|
-
<path
|
|
43
|
-
stroke-linecap="round"
|
|
44
|
-
stroke-linejoin="round"
|
|
45
|
-
d="M6 18 18 6M6 6l12 12"
|
|
46
|
-
/>
|
|
47
|
-
</svg>
|
|
48
|
-
</button>
|
|
49
|
-
|
|
50
|
-
<input
|
|
51
|
-
v-if="isExpanded"
|
|
52
|
-
v-model="searchQuery"
|
|
53
|
-
ref="input"
|
|
54
|
-
:type="type === 'search' ? 'text' : type"
|
|
55
|
-
placeholder="Search here..."
|
|
56
|
-
class="h-10 text-sm font-medium text-gray-900 bg-transparent w-80 ps-10 pe-2 focus:outline-none"
|
|
57
|
-
autocomplete="off"
|
|
58
|
-
@input="handleSearch"
|
|
59
|
-
@blur="closeInput"
|
|
60
|
-
/>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
51
|
+
<XMarkIcon class="transition-colors size-5" />
|
|
52
|
+
</span>
|
|
53
|
+
</button>
|
|
63
54
|
</div>
|
|
64
55
|
</div>
|
|
65
56
|
</div>
|
|
66
57
|
</template>
|
|
67
58
|
|
|
68
|
-
<script lang="ts"
|
|
59
|
+
<script setup lang="ts">
|
|
69
60
|
import {
|
|
70
61
|
computed,
|
|
71
62
|
nextTick,
|
|
72
63
|
onBeforeUnmount,
|
|
73
64
|
onMounted,
|
|
74
|
-
PropType,
|
|
75
65
|
ref,
|
|
76
|
-
toRefs,
|
|
77
66
|
watch,
|
|
78
67
|
} from "vue";
|
|
79
68
|
import SearchBigZoomIn from "../../assets/svg/SearchBigZoomIn.vue";
|
|
69
|
+
import { XMarkIcon } from "@heroicons/vue/20/solid";
|
|
80
70
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
71
|
+
type InputType = "text" | "number" | "email" | "password" | "search";
|
|
72
|
+
|
|
73
|
+
interface Props {
|
|
74
|
+
autoFocus?: boolean;
|
|
75
|
+
modelValue?: string | number;
|
|
76
|
+
defaultExpand?: boolean;
|
|
77
|
+
searchSync?: boolean;
|
|
78
|
+
type?: InputType;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
82
|
+
autoFocus: true,
|
|
83
|
+
modelValue: "",
|
|
84
|
+
defaultExpand: false,
|
|
85
|
+
searchSync: false,
|
|
86
|
+
type: "text",
|
|
96
87
|
});
|
|
97
|
-
const { searchSync } = toRefs(props);
|
|
98
|
-
const emit = defineEmits(["update:modelValue"]);
|
|
99
88
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
const emit = defineEmits<{
|
|
90
|
+
"update:modelValue": [value: string | number];
|
|
91
|
+
}>();
|
|
92
|
+
|
|
93
|
+
const inputRef = ref<HTMLInputElement | null>(null);
|
|
103
94
|
const componentWrapper = ref<HTMLElement | null>(null);
|
|
104
95
|
|
|
96
|
+
const hasValue = (value: string | number | undefined) =>
|
|
97
|
+
value === 0 || Boolean(value);
|
|
98
|
+
|
|
99
|
+
const isExpanded = ref(
|
|
100
|
+
props.defaultExpand || props.searchSync || hasValue(props.modelValue)
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Direct v-model bridge.
|
|
105
|
+
*
|
|
106
|
+
* Removes the need for:
|
|
107
|
+
* - local searchQuery ref
|
|
108
|
+
* - modelValue watcher
|
|
109
|
+
* - @input handler
|
|
110
|
+
*/
|
|
111
|
+
const searchQuery = computed({
|
|
112
|
+
get: () => props.modelValue ?? "",
|
|
113
|
+
set: (value: string | number) => {
|
|
114
|
+
emit("update:modelValue", value);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const hasSearchValue = computed(() => hasValue(searchQuery.value));
|
|
119
|
+
|
|
120
|
+
const inputType = computed(() =>
|
|
121
|
+
props.type === "search" ? "text" : props.type
|
|
122
|
+
);
|
|
123
|
+
|
|
105
124
|
async function expandInput() {
|
|
125
|
+
if (isExpanded.value) return;
|
|
126
|
+
|
|
106
127
|
isExpanded.value = true;
|
|
128
|
+
|
|
107
129
|
await nextTick();
|
|
108
|
-
|
|
130
|
+
inputRef.value?.focus();
|
|
109
131
|
}
|
|
110
132
|
|
|
111
133
|
async function clearSearch() {
|
|
112
134
|
searchQuery.value = "";
|
|
113
|
-
|
|
135
|
+
|
|
114
136
|
await nextTick();
|
|
115
|
-
|
|
137
|
+
inputRef.value?.focus();
|
|
116
138
|
}
|
|
117
139
|
|
|
118
|
-
const inputValue = computed(() => {
|
|
119
|
-
return props.modelValue === 0 ? true : !!props.modelValue;
|
|
120
|
-
});
|
|
121
|
-
|
|
122
140
|
function closeInput() {
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
if (props.defaultExpand || hasSearchValue.value) return;
|
|
142
|
+
|
|
143
|
+
isExpanded.value = false;
|
|
126
144
|
}
|
|
127
145
|
|
|
128
146
|
function handleOutsideClick(event: MouseEvent) {
|
|
@@ -135,43 +153,22 @@ function handleOutsideClick(event: MouseEvent) {
|
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
watch(
|
|
138
|
-
searchSync,
|
|
139
|
-
(
|
|
140
|
-
if (!
|
|
156
|
+
() => props.searchSync,
|
|
157
|
+
(enabled) => {
|
|
158
|
+
if (!enabled) {
|
|
141
159
|
closeInput();
|
|
142
160
|
}
|
|
143
|
-
},
|
|
144
|
-
{ immediate: true, deep: true }
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
watch(
|
|
148
|
-
() => props.modelValue,
|
|
149
|
-
(newValue) => {
|
|
150
|
-
if (newValue !== searchQuery.value) {
|
|
151
|
-
searchQuery.value = newValue ?? "";
|
|
152
|
-
}
|
|
153
161
|
}
|
|
154
162
|
);
|
|
155
163
|
|
|
156
164
|
onMounted(() => {
|
|
157
165
|
document.addEventListener("click", handleOutsideClick);
|
|
158
|
-
if (isExpanded.value) {
|
|
159
|
-
nextTick(() =>
|
|
166
|
+
if (isExpanded.value && props.autoFocus) {
|
|
167
|
+
nextTick(() => inputRef.value?.focus());
|
|
160
168
|
}
|
|
161
169
|
});
|
|
162
170
|
|
|
163
171
|
onBeforeUnmount(() => {
|
|
164
172
|
document.removeEventListener("click", handleOutsideClick);
|
|
165
173
|
});
|
|
166
|
-
|
|
167
|
-
function handleSearch(event: Event) {
|
|
168
|
-
const newValue = (event?.target as HTMLInputElement)?.value;
|
|
169
|
-
if (newValue !== undefined) {
|
|
170
|
-
emit("update:modelValue", newValue);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
174
|
</script>
|
|
174
|
-
|
|
175
|
-
<style scoped>
|
|
176
|
-
/* Add custom styles here */
|
|
177
|
-
</style>
|