107 lines
2.0 KiB
Vue
107 lines
2.0 KiB
Vue
<template>
|
|
<div
|
|
:class="[
|
|
cn.b(),
|
|
cn.m(size),
|
|
cn.is('focused', focused),
|
|
cn.is('disabled', disabled),
|
|
]"
|
|
>
|
|
<label :class="cn.e('wrapper')">
|
|
<Component
|
|
:is="searchIcon"
|
|
:class="cn.e('icon')"
|
|
/>
|
|
|
|
<input
|
|
ref="inputRef"
|
|
v-model="value"
|
|
type="search"
|
|
:class="cn.e('input')"
|
|
:placeholder="label"
|
|
:disabled="disabled"
|
|
@focus="focused = true"
|
|
@blur="focused = false"
|
|
>
|
|
|
|
<UiButton
|
|
v-show="value.length > 0"
|
|
size="small"
|
|
type="link"
|
|
color="secondary"
|
|
:class="cn.e('clear')"
|
|
:icon="clearIcon"
|
|
@click="value = ''"
|
|
@mousedown.prevent
|
|
/>
|
|
</label>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue'
|
|
import { debounce } from 'lodash-es'
|
|
import useClassname from '../../composables/use-classname'
|
|
import UiButton from '../button/index.vue'
|
|
|
|
export interface Props {
|
|
label?: string
|
|
size?: 'small' | 'medium' | 'large'
|
|
disabled?: false
|
|
modelValue?: string
|
|
}
|
|
|
|
defineOptions({
|
|
name: 'UiSearch',
|
|
})
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
size: 'medium',
|
|
disabled: false,
|
|
modelValue: '',
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [term: string]
|
|
}>()
|
|
|
|
const cn = useClassname('ui-search')
|
|
|
|
const inputRef = ref(null)
|
|
const value = ref(props.modelValue)
|
|
const focused = ref(false)
|
|
|
|
const searchIcon = computed(() => {
|
|
return resolveComponent(props.size === 'small' ? 'ui-icon-s-search' : 'ui-icon-search')
|
|
})
|
|
|
|
const clearIcon = computed(() => {
|
|
return props.size === 'small' ? 's-cross' : 'cross'
|
|
})
|
|
|
|
const onInput = debounce(() => {
|
|
emit('update:modelValue', value.value)
|
|
}, 300)
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
(term) => {
|
|
value.value = term
|
|
},
|
|
)
|
|
|
|
watch(value, onInput)
|
|
|
|
function focus() {
|
|
inputRef.value?.focus()
|
|
}
|
|
|
|
defineExpose({
|
|
focus,
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@use 'styles';
|
|
</style>
|