ant-design-vue/components/vc-tree-select/src/SearchInput.jsx

169 lines
4.2 KiB
Vue

/**
* Since search box is in different position with different mode.
* - Single: in the popup box
* - multiple: in the selector
* Move the code as a SearchInput for easy management.
*/
import BaseInput from '../../_util/BaseInput';
import { inject, ref, onMounted, computed, watch } from 'vue';
import PropTypes from '../../_util/vue-types';
import { createRef } from './util';
const SearchInput = {
name: 'SearchInput',
inheritAttrs: false,
props: {
open: PropTypes.looseBool,
searchValue: PropTypes.string,
prefixCls: PropTypes.string,
disabled: PropTypes.looseBool,
renderPlaceholder: PropTypes.func,
needAlign: PropTypes.looseBool,
ariaId: PropTypes.string,
isMultiple: PropTypes.looseBool.def(true),
},
emits: ['mirrorSearchValueChange'],
setup(props, { emit }) {
const measureRef = ref();
const inputWidth = ref(0);
const mirrorSearchValue = ref(props.searchValue);
watch(
computed(() => props.searchValue),
() => {
mirrorSearchValue.value = props.searchValue;
},
);
watch(
mirrorSearchValue,
() => {
emit('mirrorSearchValueChange', mirrorSearchValue.value);
},
{ immediate: true },
);
// We measure width and set to the input immediately
onMounted(() => {
if (props.isMultiple) {
watch(
mirrorSearchValue,
() => {
inputWidth.value = measureRef.value.scrollWidth;
},
{ flush: 'post', immediate: true },
);
}
});
return {
measureRef,
inputWidth,
vcTreeSelect: inject('vcTreeSelect', {}),
mirrorSearchValue,
};
},
created() {
this.inputRef = createRef();
this.prevProps = { ...this.$props };
},
mounted() {
this.$nextTick(() => {
const { open } = this.$props;
if (open) {
this.focus(true);
}
});
},
updated() {
const { open } = this.$props;
const { prevProps } = this;
this.$nextTick(() => {
if (open && prevProps.open !== open) {
this.focus();
}
this.prevProps = { ...this.$props };
});
},
methods: {
/**
* Need additional timeout for focus cause parent dom is not ready when didMount trigger
*/
focus(isDidMount) {
if (this.inputRef.current) {
if (isDidMount) {
setTimeout(() => {
this.inputRef.current.focus();
}, 0);
} else {
// set it into else, Avoid scrolling when focus
this.inputRef.current.focus();
}
}
},
blur() {
if (this.inputRef.current) {
this.inputRef.current.blur();
}
},
handleInputChange(e) {
const { value, composing } = e.target;
const { searchValue = '' } = this;
if (e.isComposing || composing || searchValue === value) {
this.mirrorSearchValue = value;
return;
}
this.vcTreeSelect.onSearchInputChange(e);
},
},
render() {
const {
searchValue,
prefixCls,
disabled,
renderPlaceholder,
open,
ariaId,
isMultiple,
} = this.$props;
const {
vcTreeSelect: { onSearchInputKeyDown },
handleInputChange,
mirrorSearchValue,
inputWidth,
} = this;
return (
<>
<span
class={`${prefixCls}-selection-search`}
style={isMultiple ? { width: inputWidth + 'px' } : {}}
>
<BaseInput
type="text"
ref={this.inputRef}
onInput={handleInputChange}
onChange={handleInputChange}
onKeydown={onSearchInputKeyDown}
value={searchValue}
disabled={disabled}
class={`${prefixCls}-selection-search-input`}
aria-label="filter select"
aria-autocomplete="list"
aria-controls={open ? ariaId : undefined}
aria-multiline="false"
/>
{isMultiple ? (
<span ref="measureRef" class={`${prefixCls}-selection-search-mirror`} aria-hidden>
{mirrorSearchValue}&nbsp;
</span>
) : null}
</span>
{renderPlaceholder && !mirrorSearchValue ? renderPlaceholder() : null}
</>
);
},
};
export default SearchInput;