@arco-design/web-vue
Version:
Arco Design Vue 2.0: A Vue.js 3 UI Library
329 lines (328 loc) • 10.9 kB
JavaScript
import { defineComponent, toRefs, ref, computed, watch, createVNode, mergeProps, createTextVNode, nextTick } from "vue";
import { getPrefixCls } from "../_utils/global-config.js";
import { INPUT_EVENTS } from "../_utils/constant.js";
import FeedbackIcon from "../_components/feedback-icon.js";
import { Enter } from "../_utils/keycode.js";
import IconHover from "../_components/icon-hover.js";
import IconClose from "../icon/icon-close/index.js";
import { omit } from "../_utils/omit.js";
import pick from "../_utils/pick.js";
import { isUndefined, isNull, isObject, isFunction } from "../_utils/is.js";
import { useFormItem } from "../_hooks/use-form-item.js";
import { useSize } from "../_hooks/use-size.js";
import { useCursor } from "../_hooks/use-cursor.js";
var _Input = defineComponent({
name: "Input",
inheritAttrs: false,
props: {
modelValue: String,
defaultValue: {
type: String,
default: ""
},
size: {
type: String
},
allowClear: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
error: {
type: Boolean,
default: false
},
placeholder: String,
maxLength: {
type: [Number, Object],
default: 0
},
showWordLimit: {
type: Boolean,
default: false
},
wordLength: {
type: Function
},
wordSlice: {
type: Function
},
inputAttrs: {
type: Object
},
type: {
type: String,
default: "text"
},
prepend: String,
append: String
},
emits: {
"update:modelValue": (value) => true,
"input": (value, ev) => true,
"change": (value, ev) => true,
"pressEnter": (ev) => true,
"clear": (ev) => true,
"focus": (ev) => true,
"blur": (ev) => true
},
setup(props, {
emit,
slots,
attrs
}) {
const {
size,
disabled,
error,
modelValue
} = toRefs(props);
const prefixCls = getPrefixCls("input");
const inputRef = ref();
const {
mergedSize: _mergedSize,
mergedDisabled,
mergedError: _mergedError,
feedback,
eventHandlers
} = useFormItem({
size,
disabled,
error
});
const {
mergedSize
} = useSize(_mergedSize);
const [recordCursor, setCursor] = useCursor(inputRef);
const _value = ref(props.defaultValue);
const computedValue = computed(() => {
var _a;
return (_a = props.modelValue) != null ? _a : _value.value;
});
let preValue = computedValue.value;
watch(modelValue, (value) => {
if (isUndefined(value) || isNull(value)) {
_value.value = "";
}
});
watch(computedValue, (value, oldValue) => {
preValue = oldValue;
});
const focused = ref(false);
const showClearBtn = computed(() => props.allowClear && !props.readonly && !mergedDisabled.value && Boolean(computedValue.value));
const isComposition = ref(false);
const compositionValue = ref("");
const getValueLength = (value) => {
var _a;
if (isFunction(props.wordLength)) {
return props.wordLength(value);
}
return (_a = value.length) != null ? _a : 0;
};
const valueLength = computed(() => getValueLength(computedValue.value));
const mergedError = computed(() => _mergedError.value || Boolean(isObject(props.maxLength) && props.maxLength.errorOnly && valueLength.value > maxLength.value));
const maxLengthErrorOnly = computed(() => isObject(props.maxLength) && Boolean(props.maxLength.errorOnly));
const maxLength = computed(() => {
if (isObject(props.maxLength)) {
return props.maxLength.length;
}
return props.maxLength;
});
const defaultMaxLength = computed(() => {
const bytePerChar = getValueLength("a");
return Math.floor(maxLength.value / bytePerChar);
});
const updateValue = (value) => {
var _a, _b;
if (maxLength.value && !maxLengthErrorOnly.value && getValueLength(value) > maxLength.value) {
value = (_b = (_a = props.wordSlice) == null ? void 0 : _a.call(props, value, maxLength.value)) != null ? _b : value.slice(0, defaultMaxLength.value);
}
_value.value = value;
emit("update:modelValue", value);
};
const handleMousedown = (e) => {
if (inputRef.value && e.target !== inputRef.value) {
e.preventDefault();
inputRef.value.focus();
}
};
const emitChange = (value, ev) => {
var _a, _b;
if (value !== preValue) {
preValue = value;
emit("change", value, ev);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a, ev);
}
};
const handleFocus = (ev) => {
var _a, _b;
focused.value = true;
emit("focus", ev);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onFocus) == null ? void 0 : _b.call(_a, ev);
};
const handleBlur = (ev) => {
var _a, _b;
focused.value = false;
emitChange(computedValue.value, ev);
emit("blur", ev);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onBlur) == null ? void 0 : _b.call(_a, ev);
};
const handleComposition = (e) => {
var _a, _b, _c;
const {
value,
selectionStart,
selectionEnd
} = e.target;
if (e.type === "compositionend") {
isComposition.value = false;
compositionValue.value = "";
if (maxLength.value && !maxLengthErrorOnly.value && valueLength.value >= maxLength.value && getValueLength(value) > maxLength.value && selectionStart === selectionEnd) {
keepControl();
return;
}
updateValue(value);
emit("input", value, e);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onInput) == null ? void 0 : _b.call(_a, e);
keepControl();
} else {
isComposition.value = true;
compositionValue.value = computedValue.value + ((_c = e.data) != null ? _c : "");
}
};
const keepControl = () => {
recordCursor();
nextTick(() => {
if (inputRef.value && computedValue.value !== inputRef.value.value) {
inputRef.value.value = computedValue.value;
setCursor();
}
});
};
const handleInput = (e) => {
var _a, _b;
const {
value
} = e.target;
if (!isComposition.value) {
if (maxLength.value && !maxLengthErrorOnly.value && valueLength.value >= maxLength.value && getValueLength(value) > maxLength.value && e.inputType === "insertText") {
keepControl();
return;
}
updateValue(value);
emit("input", value, e);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onInput) == null ? void 0 : _b.call(_a, e);
keepControl();
}
};
const handleClear = (ev) => {
updateValue("");
emitChange("", ev);
emit("clear", ev);
};
const handleKeyDown = (e) => {
const keyCode = e.key || e.code;
if (!isComposition.value && keyCode === Enter.key) {
emitChange(computedValue.value, e);
emit("pressEnter", e);
}
};
const outerCls = computed(() => [`${prefixCls}-outer`, `${prefixCls}-outer-size-${mergedSize.value}`, {
[`${prefixCls}-outer-has-suffix`]: Boolean(slots.suffix),
[`${prefixCls}-outer-disabled`]: mergedDisabled.value
}]);
const wrapperCls = computed(() => [`${prefixCls}-wrapper`, {
[`${prefixCls}-error`]: mergedError.value,
[`${prefixCls}-disabled`]: mergedDisabled.value,
[`${prefixCls}-focus`]: focused.value
}]);
const cls = computed(() => [prefixCls, `${prefixCls}-size-${mergedSize.value}`]);
const wrapperAttrs = computed(() => omit(attrs, INPUT_EVENTS));
const inputAttrs = computed(() => pick(attrs, INPUT_EVENTS));
const mergeInputAttrs = computed(() => {
const attrs2 = {
...inputAttrs.value,
...props.inputAttrs
};
if (mergedError.value) {
attrs2["aria-invalid"] = true;
}
return attrs2;
});
const renderInput = (hasOuter) => {
var _a;
return createVNode("span", mergeProps({
"class": wrapperCls.value,
"onMousedown": handleMousedown
}, !hasOuter ? wrapperAttrs.value : void 0), [slots.prefix && createVNode("span", {
"class": `${prefixCls}-prefix`
}, [slots.prefix()]), createVNode("input", mergeProps({
"ref": inputRef,
"class": cls.value,
"value": computedValue.value,
"type": props.type,
"placeholder": props.placeholder,
"readonly": props.readonly,
"disabled": mergedDisabled.value,
"onInput": handleInput,
"onKeydown": handleKeyDown,
"onFocus": handleFocus,
"onBlur": handleBlur,
"onCompositionstart": handleComposition,
"onCompositionupdate": handleComposition,
"onCompositionend": handleComposition
}, mergeInputAttrs.value), null), showClearBtn.value && createVNode(IconHover, {
"prefix": prefixCls,
"class": `${prefixCls}-clear-btn`,
"onClick": handleClear
}, {
default: () => [createVNode(IconClose, null, null)]
}), (slots.suffix || Boolean(props.maxLength) && props.showWordLimit || Boolean(feedback.value)) && createVNode("span", {
"class": [`${prefixCls}-suffix`, {
[`${prefixCls}-suffix-has-feedback`]: feedback.value
}]
}, [Boolean(props.maxLength) && props.showWordLimit && createVNode("span", {
"class": `${prefixCls}-word-limit`
}, [valueLength.value, createTextVNode("/"), maxLength.value]), (_a = slots.suffix) == null ? void 0 : _a.call(slots), Boolean(feedback.value) && createVNode(FeedbackIcon, {
"type": feedback.value
}, null)])]);
};
const render = () => {
if (slots.prepend || slots.append || props.prepend || props.append) {
return createVNode("span", mergeProps({
"class": outerCls.value
}, wrapperAttrs.value), [(slots.prepend || props.prepend) && createVNode("span", {
"class": `${prefixCls}-prepend`
}, [slots.prepend ? slots.prepend() : props.prepend]), renderInput(true), (slots.append || props.append) && createVNode("span", {
"class": `${prefixCls}-append`
}, [slots.append ? slots.append() : props.append])]);
}
return renderInput();
};
return {
inputRef,
render
};
},
methods: {
focus() {
var _a;
(_a = this.inputRef) == null ? void 0 : _a.focus();
},
blur() {
var _a;
(_a = this.inputRef) == null ? void 0 : _a.blur();
}
},
render() {
return this.render();
}
});
export { _Input as default };