You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
6.8 KiB
254 lines
6.8 KiB
// base 0.0.1-alpha.7
|
|
import type { ComponentPublicInstance } from 'vue';
|
|
import { computed, onMounted, defineComponent, nextTick, shallowRef, watch } from 'vue';
|
|
import classNames from '../_util/classNames';
|
|
import type { ChangeEvent, FocusEventHandler } from '../_util/EventInterface';
|
|
import omit from '../_util/omit';
|
|
import type { InputProps } from './inputProps';
|
|
import { inputProps } from './inputProps';
|
|
import type { InputFocusOptions } from './utils/commonUtils';
|
|
import {
|
|
fixControlledValue,
|
|
hasAddon,
|
|
hasPrefixSuffix,
|
|
resolveOnChange,
|
|
triggerFocus,
|
|
} from './utils/commonUtils';
|
|
import BaseInput from './BaseInput';
|
|
import BaseInputCore, { type BaseInputExpose } from '../_util/BaseInput';
|
|
|
|
export default defineComponent({
|
|
name: 'VCInput',
|
|
inheritAttrs: false,
|
|
props: inputProps(),
|
|
setup(props, { slots, attrs, expose, emit }) {
|
|
const stateValue = shallowRef(props.value === undefined ? props.defaultValue : props.value);
|
|
const focused = shallowRef(false);
|
|
const inputRef = shallowRef<BaseInputExpose>();
|
|
const rootRef = shallowRef<ComponentPublicInstance>();
|
|
watch(
|
|
() => props.value,
|
|
() => {
|
|
stateValue.value = props.value;
|
|
},
|
|
);
|
|
watch(
|
|
() => props.disabled,
|
|
() => {
|
|
if (props.disabled) {
|
|
focused.value = false;
|
|
}
|
|
},
|
|
);
|
|
const focus = (option?: InputFocusOptions) => {
|
|
if (inputRef.value) {
|
|
triggerFocus(inputRef.value.input, option);
|
|
}
|
|
};
|
|
|
|
const blur = () => {
|
|
inputRef.value.input?.blur();
|
|
};
|
|
|
|
const setSelectionRange = (
|
|
start: number,
|
|
end: number,
|
|
direction?: 'forward' | 'backward' | 'none',
|
|
) => {
|
|
inputRef.value.input?.setSelectionRange(start, end, direction);
|
|
};
|
|
|
|
const select = () => {
|
|
inputRef.value.input?.select();
|
|
};
|
|
|
|
expose({
|
|
focus,
|
|
blur,
|
|
input: computed(() => (inputRef.value.input as any)?.input),
|
|
stateValue,
|
|
setSelectionRange,
|
|
select,
|
|
});
|
|
const triggerChange = (e: Event) => {
|
|
emit('change', e);
|
|
};
|
|
const setValue = (value: string | number, callback?: Function) => {
|
|
if (stateValue.value === value) {
|
|
return;
|
|
}
|
|
if (props.value === undefined) {
|
|
stateValue.value = value;
|
|
} else {
|
|
nextTick(() => {
|
|
if (inputRef.value.input.value !== stateValue.value) {
|
|
rootRef.value?.$forceUpdate();
|
|
}
|
|
});
|
|
}
|
|
nextTick(() => {
|
|
callback && callback();
|
|
});
|
|
};
|
|
const handleChange = (e: ChangeEvent) => {
|
|
const { value } = e.target as any;
|
|
if (stateValue.value === value) return;
|
|
const newVal = e.target.value;
|
|
resolveOnChange(inputRef.value.input as HTMLInputElement, e, triggerChange);
|
|
setValue(newVal);
|
|
};
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.keyCode === 13) {
|
|
emit('pressEnter', e);
|
|
}
|
|
emit('keydown', e);
|
|
};
|
|
|
|
const handleFocus: FocusEventHandler = e => {
|
|
focused.value = true;
|
|
emit('focus', e);
|
|
};
|
|
|
|
const handleBlur: FocusEventHandler = e => {
|
|
focused.value = false;
|
|
emit('blur', e);
|
|
};
|
|
|
|
const handleReset = (e: MouseEvent) => {
|
|
resolveOnChange(inputRef.value.input as HTMLInputElement, e, triggerChange);
|
|
setValue('', () => {
|
|
focus();
|
|
});
|
|
};
|
|
|
|
const getInputElement = () => {
|
|
const {
|
|
addonBefore = slots.addonBefore,
|
|
addonAfter = slots.addonAfter,
|
|
disabled,
|
|
valueModifiers = {},
|
|
htmlSize,
|
|
autocomplete,
|
|
prefixCls,
|
|
inputClassName,
|
|
prefix = slots.prefix?.(),
|
|
suffix = slots.suffix?.(),
|
|
allowClear,
|
|
type = 'text',
|
|
} = props;
|
|
const otherProps = omit(props as InputProps & { placeholder: string }, [
|
|
'prefixCls',
|
|
'onPressEnter',
|
|
'addonBefore',
|
|
'addonAfter',
|
|
'prefix',
|
|
'suffix',
|
|
'allowClear',
|
|
// Input elements must be either controlled or uncontrolled,
|
|
// specify either the value prop, or the defaultValue prop, but not both.
|
|
'defaultValue',
|
|
'size',
|
|
'bordered',
|
|
'htmlSize',
|
|
'lazy',
|
|
'showCount',
|
|
'valueModifiers',
|
|
'showCount',
|
|
'affixWrapperClassName',
|
|
'groupClassName',
|
|
'inputClassName',
|
|
'wrapperClassName',
|
|
]);
|
|
const inputProps = {
|
|
...otherProps,
|
|
...attrs,
|
|
autocomplete,
|
|
onChange: handleChange,
|
|
onInput: handleChange,
|
|
onFocus: handleFocus,
|
|
onBlur: handleBlur,
|
|
onKeydown: handleKeyDown,
|
|
class: classNames(
|
|
prefixCls,
|
|
{
|
|
[`${prefixCls}-disabled`]: disabled,
|
|
},
|
|
inputClassName,
|
|
!hasAddon({ addonAfter, addonBefore }) &&
|
|
!hasPrefixSuffix({ prefix, suffix, allowClear }) &&
|
|
attrs.class,
|
|
),
|
|
ref: inputRef,
|
|
key: 'ant-input',
|
|
size: htmlSize,
|
|
type,
|
|
lazy: props.lazy,
|
|
};
|
|
if (valueModifiers.lazy) {
|
|
delete inputProps.onInput;
|
|
}
|
|
if (!inputProps.autofocus) {
|
|
delete inputProps.autofocus;
|
|
}
|
|
const inputNode = <BaseInputCore {...omit(inputProps, ['size'])} />;
|
|
return inputNode;
|
|
};
|
|
const getSuffix = () => {
|
|
const { maxlength, suffix = slots.suffix?.(), showCount, prefixCls } = props;
|
|
// Max length value
|
|
const hasMaxLength = Number(maxlength) > 0;
|
|
|
|
if (suffix || showCount) {
|
|
const valueLength = [...fixControlledValue(stateValue.value)].length;
|
|
const dataCount =
|
|
typeof showCount === 'object'
|
|
? showCount.formatter({ count: valueLength, maxlength })
|
|
: `${valueLength}${hasMaxLength ? ` / ${maxlength}` : ''}`;
|
|
|
|
return (
|
|
<>
|
|
{!!showCount && (
|
|
<span
|
|
class={classNames(`${prefixCls}-show-count-suffix`, {
|
|
[`${prefixCls}-show-count-has-suffix`]: !!suffix,
|
|
})}
|
|
>
|
|
{dataCount}
|
|
</span>
|
|
)}
|
|
{suffix}
|
|
</>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
onMounted(() => {
|
|
if (process.env.NODE_ENV === 'test') {
|
|
if (props.autofocus) {
|
|
focus();
|
|
}
|
|
}
|
|
});
|
|
return () => {
|
|
const { prefixCls, disabled, ...rest } = props;
|
|
return (
|
|
<BaseInput
|
|
{...rest}
|
|
{...attrs}
|
|
ref={rootRef}
|
|
prefixCls={prefixCls}
|
|
inputElement={getInputElement()}
|
|
handleReset={handleReset}
|
|
value={fixControlledValue(stateValue.value)}
|
|
focused={focused.value}
|
|
triggerFocus={focus}
|
|
suffix={getSuffix()}
|
|
disabled={disabled}
|
|
v-slots={slots}
|
|
/>
|
|
);
|
|
};
|
|
},
|
|
});
|