Skip to content

Commit 82f28ce

Browse files
committed
fix: select input
1 parent 6e2c5a6 commit 82f28ce

File tree

6 files changed

+152
-28
lines changed

6 files changed

+152
-28
lines changed

components/_util/BaseInput.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { PropType } from 'vue';
2-
import { defineComponent, shallowRef, ref, watch } from 'vue';
2+
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
33
import PropTypes from './vue-types';
4+
import type { BaseInputInnerExpose } from './BaseInputInner';
5+
import BaseInputInner from './BaseInputInner';
46

57
export interface BaseInputExpose {
68
focus: () => void;
@@ -30,6 +32,8 @@ const BaseInput = defineComponent({
3032
default: 'input',
3133
},
3234
size: PropTypes.string,
35+
style: PropTypes.style,
36+
class: PropTypes.string,
3337
},
3438
emits: [
3539
'change',
@@ -40,9 +44,11 @@ const BaseInput = defineComponent({
4044
'compositionstart',
4145
'compositionend',
4246
'keyup',
47+
'paste',
48+
'mousedown',
4349
],
4450
setup(props, { emit, attrs, expose }) {
45-
const inputRef = shallowRef(null);
51+
const inputRef = shallowRef<BaseInputInnerExpose>(null);
4652
const renderValue = ref();
4753
const isComposing = ref(false);
4854
watch(
@@ -115,19 +121,26 @@ const BaseInput = defineComponent({
115121
expose({
116122
focus,
117123
blur,
118-
input: inputRef,
124+
input: computed(() => inputRef.value?.input),
119125
setSelectionRange,
120126
select,
121-
getSelectionStart: () => inputRef.value?.selectionStart,
122-
getSelectionEnd: () => inputRef.value?.selectionEnd,
123-
getScrollTop: () => inputRef.value?.scrollTop,
127+
getSelectionStart: () => inputRef.value?.getSelectionStart(),
128+
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
129+
getScrollTop: () => inputRef.value?.getScrollTop(),
124130
});
131+
const handleMousedown = (e: MouseEvent) => {
132+
emit('mousedown', e);
133+
};
134+
const handlePaste = (e: ClipboardEvent) => {
135+
emit('paste', e);
136+
};
125137
return () => {
126-
const { tag: Tag, ...restProps } = props;
138+
const { tag: Tag, style, ...restProps } = props;
127139
return (
128-
<Tag
140+
<BaseInputInner
129141
{...restProps}
130142
{...attrs}
143+
style={JSON.stringify(style)}
131144
onInput={handleInput}
132145
onChange={handleChange}
133146
onBlur={handleBlur}
@@ -138,6 +151,8 @@ const BaseInput = defineComponent({
138151
onCompositionend={onCompositionend}
139152
onKeyup={handleKeyUp}
140153
onKeydown={handleKeyDown}
154+
onPaste={handlePaste}
155+
onMousedown={handleMousedown}
141156
/>
142157
);
143158
};

components/_util/BaseInputInner.tsx

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import type { PropType } from 'vue';
2+
import { defineComponent, shallowRef } from 'vue';
3+
import PropTypes from './vue-types';
4+
5+
export interface BaseInputInnerExpose {
6+
focus: () => void;
7+
blur: () => void;
8+
input: HTMLInputElement | HTMLTextAreaElement | null;
9+
setSelectionRange: (
10+
start: number,
11+
end: number,
12+
direction?: 'forward' | 'backward' | 'none',
13+
) => void;
14+
select: () => void;
15+
getSelectionStart: () => number | null;
16+
getSelectionEnd: () => number | null;
17+
getScrollTop: () => number | null;
18+
setScrollTop: (scrollTop: number) => void;
19+
}
20+
const BaseInputInner = defineComponent({
21+
compatConfig: { MODE: 3 },
22+
// inheritAttrs: false,
23+
props: {
24+
disabled: PropTypes.looseBool,
25+
type: PropTypes.string,
26+
value: PropTypes.any,
27+
tag: {
28+
type: String as PropType<'input' | 'textarea'>,
29+
default: 'input',
30+
},
31+
size: PropTypes.string,
32+
onChange: Function as PropType<(e: Event) => void>,
33+
onInput: Function as PropType<(e: Event) => void>,
34+
onBlur: Function as PropType<(e: Event) => void>,
35+
onFocus: Function as PropType<(e: Event) => void>,
36+
onKeydown: Function as PropType<(e: Event) => void>,
37+
onCompositionstart: Function as PropType<(e: Event) => void>,
38+
onCompositionend: Function as PropType<(e: Event) => void>,
39+
onKeyup: Function as PropType<(e: Event) => void>,
40+
onPaste: Function as PropType<(e: Event) => void>,
41+
onMousedown: Function as PropType<(e: Event) => void>,
42+
},
43+
emits: [
44+
'change',
45+
'input',
46+
'blur',
47+
'keydown',
48+
'focus',
49+
'compositionstart',
50+
'compositionend',
51+
'keyup',
52+
'paste',
53+
'mousedown',
54+
],
55+
setup(props, { expose }) {
56+
const inputRef = shallowRef(null);
57+
58+
const focus = () => {
59+
if (inputRef.value) {
60+
inputRef.value.focus();
61+
}
62+
};
63+
const blur = () => {
64+
if (inputRef.value) {
65+
inputRef.value.blur();
66+
}
67+
};
68+
const setSelectionRange = (
69+
start: number,
70+
end: number,
71+
direction?: 'forward' | 'backward' | 'none',
72+
) => {
73+
inputRef.value?.setSelectionRange(start, end, direction);
74+
};
75+
76+
const select = () => {
77+
inputRef.value?.select();
78+
};
79+
expose({
80+
focus,
81+
blur,
82+
input: inputRef,
83+
setSelectionRange,
84+
select,
85+
getSelectionStart: () => inputRef.value?.selectionStart,
86+
getSelectionEnd: () => inputRef.value?.selectionEnd,
87+
getScrollTop: () => inputRef.value?.scrollTop,
88+
});
89+
return () => {
90+
const { tag: Tag, value, ...restProps } = props;
91+
return <Tag {...restProps} ref={inputRef} value={value} />;
92+
};
93+
},
94+
});
95+
96+
export default BaseInputInner;

components/vc-select/Selector/Input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ const Input = defineComponent({
4848
setup(props) {
4949
let blurTimeout = null;
5050
const VCSelectContainerEvent = inject('VCSelectContainerEvent') as any;
51-
5251
return () => {
5352
const {
5453
prefixCls,
@@ -97,6 +96,7 @@ const Input = defineComponent({
9796
ref: inputRef,
9897
disabled,
9998
tabindex,
99+
lazy: false,
100100
autocomplete: autocomplete || 'off',
101101
autofocus,
102102
class: classNames(`${prefixCls}-selection-search-input`, inputNode?.props?.class),

components/vc-select/Selector/MultipleSelector.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import TransBtn from '../TransBtn';
22
import type { InnerSelectorProps } from './interface';
33
import Input from './Input';
44
import type { Ref, PropType } from 'vue';
5-
import { computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
5+
import { ref, watchEffect, computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
66
import classNames from '../../_util/classNames';
77
import pickAttrs from '../../_util/pickAttrs';
88
import PropTypes from '../../_util/vue-types';
@@ -24,6 +24,8 @@ type SelectorProps = InnerSelectorProps & {
2424
tagRender?: (props: CustomTagProps) => VueNode;
2525
onToggleOpen: any;
2626

27+
compositionStatus: boolean;
28+
2729
// Motion
2830
choiceTransitionName?: string;
2931

@@ -46,7 +48,7 @@ const props = {
4648
autocomplete: String,
4749
activeDescendantId: String,
4850
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
49-
51+
compositionStatus: Boolean,
5052
removeIcon: PropTypes.any,
5153
choiceTransitionName: String,
5254

@@ -91,11 +93,14 @@ const SelectSelector = defineComponent<SelectorProps>({
9193
() =>
9294
props.mode === 'tags' || ((props.showSearch && (props.open || focused.value)) as boolean),
9395
);
94-
96+
const targetValue = ref('');
97+
watchEffect(() => {
98+
targetValue.value = inputValue.value;
99+
});
95100
// We measure width and set to the input immediately
96101
onMounted(() => {
97102
watch(
98-
inputValue,
103+
targetValue,
99104
() => {
100105
inputWidth.value = measureRef.value.scrollWidth;
101106
},
@@ -202,6 +207,14 @@ const SelectSelector = defineComponent<SelectorProps>({
202207
return defaultRenderSelector(content, content, false);
203208
}
204209

210+
const handleInput = (e: Event) => {
211+
const composing = (e.target as any).composing;
212+
targetValue.value = (e.target as any).value;
213+
if (!composing) {
214+
props.onInputChange(e);
215+
}
216+
};
217+
205218
return () => {
206219
const {
207220
id,
@@ -215,14 +228,13 @@ const SelectSelector = defineComponent<SelectorProps>({
215228
autocomplete,
216229
activeDescendantId,
217230
tabindex,
218-
onInputChange,
231+
compositionStatus,
219232
onInputPaste,
220233
onInputKeyDown,
221234
onInputMouseDown,
222235
onInputCompositionStart,
223236
onInputCompositionEnd,
224237
} = props;
225-
226238
// >>> Input Node
227239
const inputNode = (
228240
<div
@@ -241,10 +253,10 @@ const SelectSelector = defineComponent<SelectorProps>({
241253
autocomplete={autocomplete}
242254
editable={inputEditable.value}
243255
activeDescendantId={activeDescendantId}
244-
value={inputValue.value}
256+
value={targetValue.value}
245257
onKeydown={onInputKeyDown}
246258
onMousedown={onInputMouseDown}
247-
onChange={onInputChange}
259+
onChange={handleInput}
248260
onPaste={onInputPaste}
249261
onCompositionstart={onInputCompositionStart}
250262
onCompositionend={onInputCompositionEnd}
@@ -256,7 +268,7 @@ const SelectSelector = defineComponent<SelectorProps>({
256268

257269
{/* Measure Node */}
258270
<span ref={measureRef} class={`${selectionPrefixCls.value}-search-mirror`} aria-hidden>
259-
{inputValue.value}&nbsp;
271+
{targetValue.value}&nbsp;
260272
</span>
261273
</div>
262274
);
@@ -277,7 +289,7 @@ const SelectSelector = defineComponent<SelectorProps>({
277289
return (
278290
<>
279291
{selectionNode}
280-
{!values.length && !inputValue.value && (
292+
{!values.length && !inputValue.value && !compositionStatus && (
281293
<span class={`${selectionPrefixCls.value}-placeholder`}>{placeholder}</span>
282294
)}
283295
</>

components/vc-select/Selector/SingleSelector.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pickAttrs from '../../_util/pickAttrs';
22
import Input from './Input';
33
import type { InnerSelectorProps } from './interface';
4-
import { Fragment, Ref, computed, defineComponent, shallowRef, watch } from 'vue';
4+
import { Fragment, computed, defineComponent, shallowRef, watch } from 'vue';
55
import PropTypes from '../../_util/vue-types';
66
import type { VueNode } from '../../_util/type';
77
import useInjectLegacySelectContext from '../../vc-tree-select/LegacyContext';
@@ -10,8 +10,6 @@ interface SelectorProps extends InnerSelectorProps {
1010
inputElement: VueNode;
1111
activeValue: string;
1212
optionLabelRender: Function;
13-
14-
// placeholder
1513
compositionStatus: boolean;
1614
}
1715
const props = {
@@ -92,6 +90,13 @@ const SingleSelector = defineComponent<SelectorProps>({
9290
</span>
9391
);
9492
};
93+
const handleInput = (e: Event) => {
94+
const composing = (e.target as any).composing;
95+
if (!composing) {
96+
inputChanged.value = true;
97+
props.onInputChange(e);
98+
}
99+
};
95100

96101
return () => {
97102
const {
@@ -109,7 +114,6 @@ const SingleSelector = defineComponent<SelectorProps>({
109114
optionLabelRender,
110115
onInputKeyDown,
111116
onInputMouseDown,
112-
onInputChange,
113117
onInputPaste,
114118
onInputCompositionStart,
115119
onInputCompositionEnd,
@@ -153,10 +157,7 @@ const SingleSelector = defineComponent<SelectorProps>({
153157
value={inputValue.value}
154158
onKeydown={onInputKeyDown}
155159
onMousedown={onInputMouseDown}
156-
onChange={e => {
157-
inputChanged.value = true;
158-
onInputChange(e as any);
159-
}}
160+
onChange={handleInput}
160161
onPaste={onInputPaste}
161162
onCompositionstart={onInputCompositionStart}
162163
onCompositionend={onInputCompositionEnd}

components/vc-select/Selector/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const Selector = defineComponent<SelectorProps>({
124124
} as any,
125125
setup(props, { expose }) {
126126
const inputRef = createRef();
127-
let compositionStatus = ref(false);
127+
const compositionStatus = ref(false);
128128

129129
// ====================== Input ======================
130130
const [getInputMouseDown, setInputMouseDown] = useLock(0);

0 commit comments

Comments
 (0)