fix: select input
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}
|
||||
{targetValue.value}
|
||||
</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…
Reference in New Issue