fix: select input
parent
6e2c5a6a83
commit
82f28ce3d0
|
@ -1,6 +1,8 @@
|
||||||
import type { PropType } from 'vue';
|
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 PropTypes from './vue-types';
|
||||||
|
import type { BaseInputInnerExpose } from './BaseInputInner';
|
||||||
|
import BaseInputInner from './BaseInputInner';
|
||||||
|
|
||||||
export interface BaseInputExpose {
|
export interface BaseInputExpose {
|
||||||
focus: () => void;
|
focus: () => void;
|
||||||
|
@ -30,6 +32,8 @@ const BaseInput = defineComponent({
|
||||||
default: 'input',
|
default: 'input',
|
||||||
},
|
},
|
||||||
size: PropTypes.string,
|
size: PropTypes.string,
|
||||||
|
style: PropTypes.style,
|
||||||
|
class: PropTypes.string,
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'change',
|
'change',
|
||||||
|
@ -40,9 +44,11 @@ const BaseInput = defineComponent({
|
||||||
'compositionstart',
|
'compositionstart',
|
||||||
'compositionend',
|
'compositionend',
|
||||||
'keyup',
|
'keyup',
|
||||||
|
'paste',
|
||||||
|
'mousedown',
|
||||||
],
|
],
|
||||||
setup(props, { emit, attrs, expose }) {
|
setup(props, { emit, attrs, expose }) {
|
||||||
const inputRef = shallowRef(null);
|
const inputRef = shallowRef<BaseInputInnerExpose>(null);
|
||||||
const renderValue = ref();
|
const renderValue = ref();
|
||||||
const isComposing = ref(false);
|
const isComposing = ref(false);
|
||||||
watch(
|
watch(
|
||||||
|
@ -115,19 +121,26 @@ const BaseInput = defineComponent({
|
||||||
expose({
|
expose({
|
||||||
focus,
|
focus,
|
||||||
blur,
|
blur,
|
||||||
input: inputRef,
|
input: computed(() => inputRef.value?.input),
|
||||||
setSelectionRange,
|
setSelectionRange,
|
||||||
select,
|
select,
|
||||||
getSelectionStart: () => inputRef.value?.selectionStart,
|
getSelectionStart: () => inputRef.value?.getSelectionStart(),
|
||||||
getSelectionEnd: () => inputRef.value?.selectionEnd,
|
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
|
||||||
getScrollTop: () => inputRef.value?.scrollTop,
|
getScrollTop: () => inputRef.value?.getScrollTop(),
|
||||||
});
|
});
|
||||||
|
const handleMousedown = (e: MouseEvent) => {
|
||||||
|
emit('mousedown', e);
|
||||||
|
};
|
||||||
|
const handlePaste = (e: ClipboardEvent) => {
|
||||||
|
emit('paste', e);
|
||||||
|
};
|
||||||
return () => {
|
return () => {
|
||||||
const { tag: Tag, ...restProps } = props;
|
const { tag: Tag, style, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<Tag
|
<BaseInputInner
|
||||||
{...restProps}
|
{...restProps}
|
||||||
{...attrs}
|
{...attrs}
|
||||||
|
style={JSON.stringify(style)}
|
||||||
onInput={handleInput}
|
onInput={handleInput}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
|
@ -138,6 +151,8 @@ const BaseInput = defineComponent({
|
||||||
onCompositionend={onCompositionend}
|
onCompositionend={onCompositionend}
|
||||||
onKeyup={handleKeyUp}
|
onKeyup={handleKeyUp}
|
||||||
onKeydown={handleKeyDown}
|
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) {
|
setup(props) {
|
||||||
let blurTimeout = null;
|
let blurTimeout = null;
|
||||||
const VCSelectContainerEvent = inject('VCSelectContainerEvent') as any;
|
const VCSelectContainerEvent = inject('VCSelectContainerEvent') as any;
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
@ -97,6 +96,7 @@ const Input = defineComponent({
|
||||||
ref: inputRef,
|
ref: inputRef,
|
||||||
disabled,
|
disabled,
|
||||||
tabindex,
|
tabindex,
|
||||||
|
lazy: false,
|
||||||
autocomplete: autocomplete || 'off',
|
autocomplete: autocomplete || 'off',
|
||||||
autofocus,
|
autofocus,
|
||||||
class: classNames(`${prefixCls}-selection-search-input`, inputNode?.props?.class),
|
class: classNames(`${prefixCls}-selection-search-input`, inputNode?.props?.class),
|
||||||
|
|
|
@ -2,7 +2,7 @@ import TransBtn from '../TransBtn';
|
||||||
import type { InnerSelectorProps } from './interface';
|
import type { InnerSelectorProps } from './interface';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import type { Ref, PropType } from 'vue';
|
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 classNames from '../../_util/classNames';
|
||||||
import pickAttrs from '../../_util/pickAttrs';
|
import pickAttrs from '../../_util/pickAttrs';
|
||||||
import PropTypes from '../../_util/vue-types';
|
import PropTypes from '../../_util/vue-types';
|
||||||
|
@ -24,6 +24,8 @@ type SelectorProps = InnerSelectorProps & {
|
||||||
tagRender?: (props: CustomTagProps) => VueNode;
|
tagRender?: (props: CustomTagProps) => VueNode;
|
||||||
onToggleOpen: any;
|
onToggleOpen: any;
|
||||||
|
|
||||||
|
compositionStatus: boolean;
|
||||||
|
|
||||||
// Motion
|
// Motion
|
||||||
choiceTransitionName?: string;
|
choiceTransitionName?: string;
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ const props = {
|
||||||
autocomplete: String,
|
autocomplete: String,
|
||||||
activeDescendantId: String,
|
activeDescendantId: String,
|
||||||
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||||
|
compositionStatus: Boolean,
|
||||||
removeIcon: PropTypes.any,
|
removeIcon: PropTypes.any,
|
||||||
choiceTransitionName: String,
|
choiceTransitionName: String,
|
||||||
|
|
||||||
|
@ -91,11 +93,14 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
() =>
|
() =>
|
||||||
props.mode === 'tags' || ((props.showSearch && (props.open || focused.value)) as boolean),
|
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
|
// We measure width and set to the input immediately
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
watch(
|
watch(
|
||||||
inputValue,
|
targetValue,
|
||||||
() => {
|
() => {
|
||||||
inputWidth.value = measureRef.value.scrollWidth;
|
inputWidth.value = measureRef.value.scrollWidth;
|
||||||
},
|
},
|
||||||
|
@ -202,6 +207,14 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
return defaultRenderSelector(content, content, false);
|
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 () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
@ -215,14 +228,13 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
autocomplete,
|
autocomplete,
|
||||||
activeDescendantId,
|
activeDescendantId,
|
||||||
tabindex,
|
tabindex,
|
||||||
onInputChange,
|
compositionStatus,
|
||||||
onInputPaste,
|
onInputPaste,
|
||||||
onInputKeyDown,
|
onInputKeyDown,
|
||||||
onInputMouseDown,
|
onInputMouseDown,
|
||||||
onInputCompositionStart,
|
onInputCompositionStart,
|
||||||
onInputCompositionEnd,
|
onInputCompositionEnd,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
// >>> Input Node
|
// >>> Input Node
|
||||||
const inputNode = (
|
const inputNode = (
|
||||||
<div
|
<div
|
||||||
|
@ -241,10 +253,10 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
autocomplete={autocomplete}
|
autocomplete={autocomplete}
|
||||||
editable={inputEditable.value}
|
editable={inputEditable.value}
|
||||||
activeDescendantId={activeDescendantId}
|
activeDescendantId={activeDescendantId}
|
||||||
value={inputValue.value}
|
value={targetValue.value}
|
||||||
onKeydown={onInputKeyDown}
|
onKeydown={onInputKeyDown}
|
||||||
onMousedown={onInputMouseDown}
|
onMousedown={onInputMouseDown}
|
||||||
onChange={onInputChange}
|
onChange={handleInput}
|
||||||
onPaste={onInputPaste}
|
onPaste={onInputPaste}
|
||||||
onCompositionstart={onInputCompositionStart}
|
onCompositionstart={onInputCompositionStart}
|
||||||
onCompositionend={onInputCompositionEnd}
|
onCompositionend={onInputCompositionEnd}
|
||||||
|
@ -256,7 +268,7 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
|
|
||||||
{/* Measure Node */}
|
{/* Measure Node */}
|
||||||
<span ref={measureRef} class={`${selectionPrefixCls.value}-search-mirror`} aria-hidden>
|
<span ref={measureRef} class={`${selectionPrefixCls.value}-search-mirror`} aria-hidden>
|
||||||
{inputValue.value}
|
{targetValue.value}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -277,7 +289,7 @@ const SelectSelector = defineComponent<SelectorProps>({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectionNode}
|
{selectionNode}
|
||||||
{!values.length && !inputValue.value && (
|
{!values.length && !inputValue.value && !compositionStatus && (
|
||||||
<span class={`${selectionPrefixCls.value}-placeholder`}>{placeholder}</span>
|
<span class={`${selectionPrefixCls.value}-placeholder`}>{placeholder}</span>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import pickAttrs from '../../_util/pickAttrs';
|
import pickAttrs from '../../_util/pickAttrs';
|
||||||
import Input from './Input';
|
import Input from './Input';
|
||||||
import type { InnerSelectorProps } from './interface';
|
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 PropTypes from '../../_util/vue-types';
|
||||||
import type { VueNode } from '../../_util/type';
|
import type { VueNode } from '../../_util/type';
|
||||||
import useInjectLegacySelectContext from '../../vc-tree-select/LegacyContext';
|
import useInjectLegacySelectContext from '../../vc-tree-select/LegacyContext';
|
||||||
|
@ -10,8 +10,6 @@ interface SelectorProps extends InnerSelectorProps {
|
||||||
inputElement: VueNode;
|
inputElement: VueNode;
|
||||||
activeValue: string;
|
activeValue: string;
|
||||||
optionLabelRender: Function;
|
optionLabelRender: Function;
|
||||||
|
|
||||||
// placeholder
|
|
||||||
compositionStatus: boolean;
|
compositionStatus: boolean;
|
||||||
}
|
}
|
||||||
const props = {
|
const props = {
|
||||||
|
@ -92,6 +90,13 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const handleInput = (e: Event) => {
|
||||||
|
const composing = (e.target as any).composing;
|
||||||
|
if (!composing) {
|
||||||
|
inputChanged.value = true;
|
||||||
|
props.onInputChange(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const {
|
||||||
|
@ -109,7 +114,6 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
optionLabelRender,
|
optionLabelRender,
|
||||||
onInputKeyDown,
|
onInputKeyDown,
|
||||||
onInputMouseDown,
|
onInputMouseDown,
|
||||||
onInputChange,
|
|
||||||
onInputPaste,
|
onInputPaste,
|
||||||
onInputCompositionStart,
|
onInputCompositionStart,
|
||||||
onInputCompositionEnd,
|
onInputCompositionEnd,
|
||||||
|
@ -153,10 +157,7 @@ const SingleSelector = defineComponent<SelectorProps>({
|
||||||
value={inputValue.value}
|
value={inputValue.value}
|
||||||
onKeydown={onInputKeyDown}
|
onKeydown={onInputKeyDown}
|
||||||
onMousedown={onInputMouseDown}
|
onMousedown={onInputMouseDown}
|
||||||
onChange={e => {
|
onChange={handleInput}
|
||||||
inputChanged.value = true;
|
|
||||||
onInputChange(e as any);
|
|
||||||
}}
|
|
||||||
onPaste={onInputPaste}
|
onPaste={onInputPaste}
|
||||||
onCompositionstart={onInputCompositionStart}
|
onCompositionstart={onInputCompositionStart}
|
||||||
onCompositionend={onInputCompositionEnd}
|
onCompositionend={onInputCompositionEnd}
|
||||||
|
|
|
@ -124,7 +124,7 @@ const Selector = defineComponent<SelectorProps>({
|
||||||
} as any,
|
} as any,
|
||||||
setup(props, { expose }) {
|
setup(props, { expose }) {
|
||||||
const inputRef = createRef();
|
const inputRef = createRef();
|
||||||
let compositionStatus = ref(false);
|
const compositionStatus = ref(false);
|
||||||
|
|
||||||
// ====================== Input ======================
|
// ====================== Input ======================
|
||||||
const [getInputMouseDown, setInputMouseDown] = useLock(0);
|
const [getInputMouseDown, setInputMouseDown] = useLock(0);
|
||||||
|
|
Loading…
Reference in New Issue