| <script setup lang="ts"> |
| import { ref, defineProps, defineEmits } from 'vue'; |
| import useSnackbar from "@plugin/composables/snackbar.ts"; |
| |
| const props = defineProps({ |
| showButtonText: { |
| type: Boolean, |
| default: false, |
| }, |
| modelValue: { |
| type: String, |
| default: '', |
| }, |
| }); |
| |
| const emit = defineEmits(['update:modelValue', 'on-submit']); |
| |
| const { createNotification } = useSnackbar(); |
| |
| const textInput = ref<HTMLInputElement | null>(null); |
| |
| function updateValue(event: Event) { |
| const value = (event.target as HTMLInputElement)?.value; |
| validateTextLength(value); |
| validateTextIsNotUrl(value); |
| |
| emit('update:modelValue', value); |
| } |
| |
| const validateTextIsNotUrl = (value: string): Boolean => { |
| const urlPattern = /^(https?:\/\/)?([\w\-]+\.)+[\w\-]{2,}(\/[\w\-._~:/?#[\]@!$&'()*+,;=%]*)?$/i; |
| |
| if (urlPattern.test(value)) { |
| createNotification({ |
| message: 'Please use only keywords for text search. URLs are not allowed.', |
| type: 'error', |
| }); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| function validateTextLength(value: string): boolean { |
| if (value.length >= 256) { |
| createNotification({ |
| message: 'You have reached the maximum number of allowed characters for text search (256).', |
| type: 'info', |
| }) |
| |
| return false; |
| } |
| return true; |
| } |
| |
| function validateTextNotEmpty(value: string): boolean { |
| if (value.length === 0) { |
| createNotification({ |
| message: 'Please type in the text search prompt to proceed', |
| type: 'warning', |
| }); |
| |
| return false; |
| } |
| return true; |
| } |
| |
| const onEnter = (e: Event): void => { |
| if (!validateTextIsNotUrl(props.modelValue)) { |
| return; |
| } |
| |
| if (!validateTextNotEmpty(props.modelValue)) { |
| return; |
| } |
| |
| emit('on-submit'); |
| } |
| </script> |
|
|
| <template> |
| <div class="search-input" > |
| <input |
| ref="textInput" |
| :value="modelValue" |
| @input="updateValue" |
| v-bind="$attrs" |
| @keydown.enter="onEnter" |
| placeholder="or type to search" |
| maxlength="256" |
| /> |
| <button @click="onEnter" :with-text="showButtonText"> |
| <svg class="app-svg-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| <path d="M17.5 17.5L13.875 13.875M15.8333 9.16667C15.8333 12.8486 12.8486 15.8333 9.16667 15.8333C5.48477 15.8333 2.5 12.8486 2.5 9.16667C2.5 5.48477 5.48477 2.5 9.16667 2.5C12.8486 2.5 15.8333 5.48477 15.8333 9.16667Z" stroke="#8586AD" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| </svg> |
|
|
| <span v-if="showButtonText"> Search </span> |
| </button> |
| </div> |
| </template> |
|
|
| <style scoped lang="scss"> |
| @import "@/assets/mixins"; |
| @import '@plugin/assets/main.scss'; |
| @import '@plugin/assets/_variables_override.scss'; |
| |
| .search-input { |
| display: flex; |
| height: 48px; |
| width: 100%; |
| color: $primary-400; |
| |
| button { |
| padding: 0px; |
| @include tertiary-icon-only; |
| border: unset; |
| border-radius: 0px 6px 6px 0px; |
| border: 1px solid $main-50; |
| color: inherit; |
| |
| &[with-text="true"] { |
| padding:12px 24px; |
| |
| span { |
| color: inherit; |
| } |
| } |
| } |
| |
| input { |
| @include input; |
| border: 1px solid $main-50; |
| border-radius: 6px 0px 0px 6px; |
| padding: 12px 16px; |
| |
| &:disabled { |
| background-color: dimgrey; |
| color: linen; |
| opacity: 1; |
| } |
| } |
| } |
| </style> |