added autocomplete

This commit is contained in:
2023-05-22 17:31:50 +10:00
parent cd7366b8ff
commit 2e1c2cd0b2

View File

@@ -172,6 +172,16 @@
@blur="handleBlur" @blur="handleBlur"
@input="handleInput" @input="handleInput"
@keyup="handleKeyup" /> @keyup="handleKeyup" />
<ul
class="autocomplete-list"
v-if="computedAutocompleteItems.length > 0 && focused">
<li
v-for="item in computedAutocompleteItems"
:key="item"
@mousedown="handleAutocompleteClick(item)">
{{ item }}
</li>
</ul>
</template> </template>
</template> </template>
</div> </div>
@@ -183,7 +193,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject, watch, ref, useSlots } from "vue"; import { inject, watch, ref, useSlots, computed } from "vue";
import { isEmpty, generateRandomElementId } from "../helpers/utils"; import { isEmpty, generateRandomElementId } from "../helpers/utils";
import { toTitleCase } from "../helpers/string"; import { toTitleCase } from "../helpers/string";
import { mediaGetVariantUrl } from "../helpers/media"; import { mediaGetVariantUrl } from "../helpers/media";
@@ -289,6 +299,13 @@ const props = defineProps({
default: "form", default: "form",
required: false, required: false,
}, },
autocomplete: {
type: [Array<string>, Function],
default: () => {
[];
},
required: false,
},
}); });
const slots = useSlots(); const slots = useSlots();
@@ -466,15 +483,34 @@ const handleMediaSelect = async () => {
} }
} }
}; };
const computedAutocompleteItems = computed(() => {
let autocompleteList = [];
if (props.autocomplete) {
if (typeof props.autocomplete === "function") {
autocompleteList = props.autocomplete(value.value);
} else {
autocompleteList = props.autocomplete.filter((str) =>
str.includes(value.value)
);
}
return autocompleteList.sort((a, b) => a.localeCompare(b));
}
return autocompleteList;
});
const handleAutocompleteClick = (item) => {
value.value = item;
emits("update:modelValue", item);
};
</script> </script>
<style lang="scss"> <style lang="scss">
.control-group.control-type-input { .control-group.control-type-input {
.control-row { .control-row {
.control-item {
align-items: start;
}
.input-control-prepend { .input-control-prepend {
p { p {
display: block; display: block;
@@ -523,6 +559,7 @@ const handleMediaSelect = async () => {
.control-item { .control-item {
max-width: 100%; max-width: 100%;
align-items: start;
.control-label { .control-label {
position: absolute; position: absolute;
@@ -577,6 +614,37 @@ const handleMediaSelect = async () => {
} }
} }
.autocomplete-list {
position: absolute;
list-style-type: none;
top: 100%;
width: 100%;
margin: 0;
padding: 0;
border: 1px solid var(--base-color-darker);
background-color: var(--base-color-light);
color: var(--primary-color);
z-index: 1;
max-height: 200px;
overflow: scroll;
scroll-behavior: smooth;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
li {
cursor: pointer;
padding: 8px 16px;
margin: 2px;
&:hover {
background-color: var(--base-color);
}
}
}
.static-input-control { .static-input-control {
width: 100%; width: 100%;
padding: 22px 16px 8px 16px; padding: 22px 16px 8px 16px;
@@ -744,8 +812,10 @@ const handleMediaSelect = async () => {
} }
&.input-active { &.input-active {
.control-item .control-label:not(.control-label-checkbox) { .control-item {
transform: translate(16px, 6px) scale(0.7); .control-label:not(.control-label-checkbox) {
transform: translate(16px, 6px) scale(0.7);
}
} }
} }