fix: select input

pull/7632/head
tangjinzhou 6 months ago
parent 6e2c5a6a83
commit 82f28ce3d0

@ -1,6 +1,8 @@
import type { PropType } from 'vue';
import { defineComponent, shallowRef, ref, watch } from 'vue';
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
import PropTypes from './vue-types';
import type { BaseInputInnerExpose } from './BaseInputInner';
import BaseInputInner from './BaseInputInner';
export interface BaseInputExpose {
focus: () => void;
@ -30,6 +32,8 @@ const BaseInput = defineComponent({
default: 'input',
},
size: PropTypes.string,
style: PropTypes.style,
class: PropTypes.string,
},
emits: [
'change',
@ -40,9 +44,11 @@ const BaseInput = defineComponent({
'compositionstart',
'compositionend',
'keyup',
'paste',
'mousedown',
],
setup(props, { emit, attrs, expose }) {
const inputRef = shallowRef(null);
const inputRef = shallowRef<BaseInputInnerExpose>(null);
const renderValue = ref();
const isComposing = ref(false);
watch(
@ -115,19 +121,26 @@ const BaseInput = defineComponent({
expose({
focus,
blur,
input: inputRef,
input: computed(() => inputRef.value?.input),
setSelectionRange,
select,
getSelectionStart: () => inputRef.value?.selectionStart,
getSelectionEnd: () => inputRef.value?.selectionEnd,
getScrollTop: () => inputRef.value?.scrollTop,
getSelectionStart: () => inputRef.value?.getSelectionStart(),
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
getScrollTop: () => inputRef.value?.getScrollTop(),
});
const handleMousedown = (e: MouseEvent) => {
emit('mousedown', e);
};
const handlePaste = (e: ClipboardEvent) => {
emit('paste', e);
};
return () => {
const { tag: Tag, ...restProps } = props;
const { tag: Tag, style, ...restProps } = props;
return (
<Tag
<BaseInputInner
{...restProps}
{...attrs}
style={JSON.stringify(style)}
onInput={handleInput}
onChange={handleChange}
onBlur={handleBlur}
@ -138,6 +151,8 @@ const BaseInput = defineComponent({
onCompositionend={onCompositionend}
onKeyup={handleKeyUp}
onKeydown={handleKeyDown}
onPaste={handlePaste}
onMousedown={handleMousedown}
/>
);
};

@ -0,0 +1,96 @@
import type { PropType } from 'vue';
import { defineComponent, shallowRef } from 'vue';
import PropTypes from './vue-types';
export interface BaseInputInnerExpose {
focus: () => void;
blur: () => void;
input: HTMLInputElement | HTMLTextAreaElement | null;
setSelectionRange: (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => void;
select: () => void;
getSelectionStart: () => number | null;
getSelectionEnd: () => number | null;
getScrollTop: () => number | null;
setScrollTop: (scrollTop: number) => void;
}
const BaseInputInner = defineComponent({
compatConfig: { MODE: 3 },
// inheritAttrs: false,
props: {
disabled: PropTypes.looseBool,
type: PropTypes.string,
value: PropTypes.any,
tag: {
type: String as PropType<'input' | 'textarea'>,
default: 'input',
},
size: PropTypes.string,
onChange: Function as PropType<(e: Event) => void>,
onInput: Function as PropType<(e: Event) => void>,
onBlur: Function as PropType<(e: Event) => void>,
onFocus: Function as PropType<(e: Event) => void>,
onKeydown: Function as PropType<(e: Event) => void>,
onCompositionstart: Function as PropType<(e: Event) => void>,
onCompositionend: Function as PropType<(e: Event) => void>,
onKeyup: Function as PropType<(e: Event) => void>,
onPaste: Function as PropType<(e: Event) => void>,
onMousedown: Function as PropType<(e: Event) => void>,
},
emits: [
'change',
'input',
'blur',
'keydown',
'focus',
'compositionstart',
'compositionend',
'keyup',
'paste',
'mousedown',
],
setup(props, { expose }) {
const inputRef = shallowRef(null);
const focus = () => {
if (inputRef.value) {
inputRef.value.focus();
}
};
const blur = () => {
if (inputRef.value) {
inputRef.value.blur();
}
};
const setSelectionRange = (
start: number,
end: number,
direction?: 'forward' | 'backward' | 'none',
) => {
inputRef.value?.setSelectionRange(start, end, direction);
};
const select = () => {
inputRef.value?.select();
};
expose({
focus,
blur,
input: inputRef,
setSelectionRange,
select,
getSelectionStart: () => inputRef.value?.selectionStart,
getSelectionEnd: () => inputRef.value?.selectionEnd,
getScrollTop: () => inputRef.value?.scrollTop,
});
return () => {
const { tag: Tag, value, ...restProps } = props;
return <Tag {...restProps} ref={inputRef} value={value} />;
};
},
});
export default BaseInputInner;

@ -48,7 +48,6 @@ const Input = defineComponent({
setup(props) {
let blurTimeout = null;
const VCSelectContainerEvent = inject('VCSelectContainerEvent') as any;
return () => {
const {
prefixCls,
@ -97,6 +96,7 @@ const Input = defineComponent({
ref: inputRef,
disabled,
tabindex,
lazy: false,
autocomplete: autocomplete || 'off',
autofocus,
class: classNames(`${prefixCls}-selection-search-input`, inputNode?.props?.class),

@ -2,7 +2,7 @@ import TransBtn from '../TransBtn';
import type { InnerSelectorProps } from './interface';
import Input from './Input';
import type { Ref, PropType } from 'vue';
import { computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
import { ref, watchEffect, computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
import classNames from '../../_util/classNames';
import pickAttrs from '../../_util/pickAttrs';
import PropTypes from '../../_util/vue-types';
@ -24,6 +24,8 @@ type SelectorProps = InnerSelectorProps & {
tagRender?: (props: CustomTagProps) => VueNode;
onToggleOpen: any;
compositionStatus: boolean;
// Motion
choiceTransitionName?: string;
@ -46,7 +48,7 @@ const props = {
autocomplete: String,
activeDescendantId: String,
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
compositionStatus: Boolean,
removeIcon: PropTypes.any,
choiceTransitionName: String,
@ -91,11 +93,14 @@ const SelectSelector = defineComponent<SelectorProps>({
() =>
props.mode === 'tags' || ((props.showSearch && (props.open || focused.value)) as boolean),
);
const targetValue = ref('');
watchEffect(() => {
targetValue.value = inputValue.value;
});
// We measure width and set to the input immediately
onMounted(() => {
watch(
inputValue,
targetValue,
() => {
inputWidth.value = measureRef.value.scrollWidth;
},
@ -202,6 +207,14 @@ const SelectSelector = defineComponent<SelectorProps>({
return defaultRenderSelector(content, content, false);
}
const handleInput = (e: Event) => {
const composing = (e.target as any).composing;
targetValue.value = (e.target as any).value;
if (!composing) {
props.onInputChange(e);
}
};
return () => {
const {
id,
@ -215,14 +228,13 @@ const SelectSelector = defineComponent<SelectorProps>({
autocomplete,
activeDescendantId,
tabindex,
onInputChange,
compositionStatus,
onInputPaste,
onInputKeyDown,
onInputMouseDown,
onInputCompositionStart,
onInputCompositionEnd,
} = props;
// >>> Input Node
const inputNode = (
<div
@ -241,10 +253,10 @@ const SelectSelector = defineComponent<SelectorProps>({
autocomplete={autocomplete}
editable={inputEditable.value}
activeDescendantId={activeDescendantId}
value={inputValue.value}
value={targetValue.value}
onKeydown={onInputKeyDown}
onMousedown={onInputMouseDown}
onChange={onInputChange}
onChange={handleInput}
onPaste={onInputPaste}
onCompositionstart={onInputCompositionStart}
onCompositionend={onInputCompositionEnd}
@ -256,7 +268,7 @@ const SelectSelector = defineComponent<SelectorProps>({
{/* Measure Node */}
<span ref={measureRef} class={`${selectionPrefixCls.value}-search-mirror`} aria-hidden>
{inputValue.value}&nbsp;
{targetValue.value}&nbsp;
</span>
</div>
);
@ -277,7 +289,7 @@ const SelectSelector = defineComponent<SelectorProps>({
return (
<>
{selectionNode}
{!values.length && !inputValue.value && (
{!values.length && !inputValue.value && !compositionStatus && (
<span class={`${selectionPrefixCls.value}-placeholder`}>{placeholder}</span>
)}
</>

@ -1,7 +1,7 @@
import pickAttrs from '../../_util/pickAttrs';
import Input from './Input';
import type { InnerSelectorProps } from './interface';
import { Fragment, Ref, computed, defineComponent, shallowRef, watch } from 'vue';
import { Fragment, computed, defineComponent, shallowRef, watch } from 'vue';
import PropTypes from '../../_util/vue-types';
import type { VueNode } from '../../_util/type';
import useInjectLegacySelectContext from '../../vc-tree-select/LegacyContext';
@ -10,8 +10,6 @@ interface SelectorProps extends InnerSelectorProps {
inputElement: VueNode;
activeValue: string;
optionLabelRender: Function;
// placeholder
compositionStatus: boolean;
}
const props = {
@ -92,6 +90,13 @@ const SingleSelector = defineComponent<SelectorProps>({
</span>
);
};
const handleInput = (e: Event) => {
const composing = (e.target as any).composing;
if (!composing) {
inputChanged.value = true;
props.onInputChange(e);
}
};
return () => {
const {
@ -109,7 +114,6 @@ const SingleSelector = defineComponent<SelectorProps>({
optionLabelRender,
onInputKeyDown,
onInputMouseDown,
onInputChange,
onInputPaste,
onInputCompositionStart,
onInputCompositionEnd,
@ -153,10 +157,7 @@ const SingleSelector = defineComponent<SelectorProps>({
value={inputValue.value}
onKeydown={onInputKeyDown}
onMousedown={onInputMouseDown}
onChange={e => {
inputChanged.value = true;
onInputChange(e as any);
}}
onChange={handleInput}
onPaste={onInputPaste}
onCompositionstart={onInputCompositionStart}
onCompositionend={onInputCompositionEnd}

@ -124,7 +124,7 @@ const Selector = defineComponent<SelectorProps>({
} as any,
setup(props, { expose }) {
const inputRef = createRef();
let compositionStatus = ref(false);
const compositionStatus = ref(false);
// ====================== Input ======================
const [getInputMouseDown, setInputMouseDown] = useLock(0);

Loading…
Cancel
Save