element-plus
Version:
A Component Library for Vue3.0
586 lines (574 loc) • 23.6 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
var vue = require('vue');
var hooks = require('../hooks');
var constants = require('../utils/constants');
var util = require('../utils/util');
var isServer = require('../utils/isServer');
var isDef = require('../utils/isDef');
var validators = require('../utils/validators');
var form = require('../el-form');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var isServer__default = /*#__PURE__*/_interopDefaultLegacy(isServer);
let hiddenTextarea;
const HIDDEN_STYLE = `
height:0 !important;
visibility:hidden !important;
overflow:hidden !important;
position:absolute !important;
z-index:-1000 !important;
top:0 !important;
right:0 !important;
`;
const CONTEXT_STYLE = [
'letter-spacing',
'line-height',
'padding-top',
'padding-bottom',
'font-family',
'font-weight',
'font-size',
'text-rendering',
'text-transform',
'width',
'text-indent',
'padding-left',
'padding-right',
'border-width',
'box-sizing',
];
function calculateNodeStyling(targetElement) {
const style = window.getComputedStyle(targetElement);
const boxSizing = style.getPropertyValue('box-sizing');
const paddingSize = (parseFloat(style.getPropertyValue('padding-bottom')) +
parseFloat(style.getPropertyValue('padding-top')));
const borderSize = (parseFloat(style.getPropertyValue('border-bottom-width')) +
parseFloat(style.getPropertyValue('border-top-width')));
const contextStyle = CONTEXT_STYLE
.map(name => `${name}:${style.getPropertyValue(name)}`)
.join(';');
return { contextStyle, paddingSize, borderSize, boxSizing };
}
function calcTextareaHeight(targetElement, minRows = 1, maxRows = null) {
var _a;
if (!hiddenTextarea) {
hiddenTextarea = document.createElement('textarea');
document.body.appendChild(hiddenTextarea);
}
const { paddingSize, borderSize, boxSizing, contextStyle, } = calculateNodeStyling(targetElement);
hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';
let height = hiddenTextarea.scrollHeight;
const result = {};
if (boxSizing === 'border-box') {
height = height + borderSize;
}
else if (boxSizing === 'content-box') {
height = height - paddingSize;
}
hiddenTextarea.value = '';
const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;
if (minRows !== null) {
let minHeight = singleRowHeight * minRows;
if (boxSizing === 'border-box') {
minHeight = minHeight + paddingSize + borderSize;
}
height = Math.max(minHeight, height);
result.minHeight = `${minHeight}px`;
}
if (maxRows !== null) {
let maxHeight = singleRowHeight * maxRows;
if (boxSizing === 'border-box') {
maxHeight = maxHeight + paddingSize + borderSize;
}
height = Math.min(maxHeight, height);
}
result.height = `${height}px`;
(_a = hiddenTextarea.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(hiddenTextarea);
hiddenTextarea = null;
return result;
}
const PENDANT_MAP = {
suffix: 'append',
prefix: 'prepend',
};
var script = vue.defineComponent({
name: 'ElInput',
inheritAttrs: false,
props: {
modelValue: {
type: [String, Number],
default: '',
},
type: {
type: String,
default: 'text',
},
size: {
type: String,
validator: validators.isValidComponentSize,
},
resize: {
type: String,
validator: (val) => ['none', 'both', 'horizontal', 'vertical'].includes(val),
},
autosize: {
type: [Boolean, Object],
default: false,
},
autocomplete: {
type: String,
default: 'off',
validator: (val) => ['on', 'off'].includes(val),
},
placeholder: {
type: String,
},
form: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
readonly: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: false,
},
showPassword: {
type: Boolean,
default: false,
},
showWordLimit: {
type: Boolean,
default: false,
},
suffixIcon: {
type: String,
default: '',
},
prefixIcon: {
type: String,
default: '',
},
label: {
type: String,
default: '',
},
tabindex: {
type: String,
default: '',
},
validateEvent: {
type: Boolean,
default: true,
},
},
emits: [constants.UPDATE_MODEL_EVENT, 'input', 'change', 'focus', 'blur', 'clear',
'mouseleave', 'mouseenter', 'keydown'],
setup(props, ctx) {
const instance = vue.getCurrentInstance();
const attrs = hooks.useAttrs();
const $ELEMENT = util.useGlobalConfig();
const elForm = vue.inject(form.elFormKey, {});
const elFormItem = vue.inject(form.elFormItemKey, {});
const input = vue.ref(null);
const textarea = vue.ref(null);
const focused = vue.ref(false);
const hovering = vue.ref(false);
const isComposing = vue.ref(false);
const passwordVisible = vue.ref(false);
const _textareaCalcStyle = vue.shallowRef({});
const inputOrTextarea = vue.computed(() => input.value || textarea.value);
const inputSize = vue.computed(() => props.size || elFormItem.size || $ELEMENT.size);
const needStatusIcon = vue.computed(() => elForm.statusIcon);
const validateState = vue.computed(() => elFormItem.validateState || '');
const validateIcon = vue.computed(() => constants.VALIDATE_STATE_MAP[validateState.value]);
const textareaStyle = vue.computed(() => (Object.assign(Object.assign({}, _textareaCalcStyle.value), { resize: props.resize })));
const inputDisabled = vue.computed(() => props.disabled || elForm.disabled);
const nativeInputValue = vue.computed(() => (props.modelValue === null || props.modelValue === undefined) ? '' : String(props.modelValue));
const upperLimit = vue.computed(() => ctx.attrs.maxlength);
const showClear = vue.computed(() => {
return props.clearable &&
!inputDisabled.value &&
!props.readonly &&
nativeInputValue.value &&
(focused.value || hovering.value);
});
const showPwdVisible = vue.computed(() => {
return props.showPassword &&
!inputDisabled.value &&
!props.readonly &&
(!!nativeInputValue.value || focused.value);
});
const isWordLimitVisible = vue.computed(() => {
return props.showWordLimit &&
ctx.attrs.maxlength &&
(props.type === 'text' || props.type === 'textarea') &&
!inputDisabled.value &&
!props.readonly &&
!props.showPassword;
});
const textLength = vue.computed(() => {
return typeof props.modelValue === 'number' ? String(props.modelValue).length : (props.modelValue || '').length;
});
const inputExceed = vue.computed(() => {
return isWordLimitVisible.value && (textLength.value > upperLimit.value);
});
const resizeTextarea = () => {
const { type, autosize } = props;
if (isServer__default['default'] || type !== 'textarea')
return;
if (autosize) {
const minRows = util.isObject(autosize) ? autosize.minRows : void 0;
const maxRows = util.isObject(autosize) ? autosize.maxRows : void 0;
_textareaCalcStyle.value = calcTextareaHeight(textarea.value, minRows, maxRows);
}
else {
_textareaCalcStyle.value = {
minHeight: calcTextareaHeight(textarea.value).minHeight,
};
}
};
const setNativeInputValue = () => {
const input = inputOrTextarea.value;
if (!input || input.value === nativeInputValue.value)
return;
input.value = nativeInputValue.value;
};
const calcIconOffset = place => {
const { el } = instance.vnode;
const elList = Array.from(el.querySelectorAll(`.el-input__${place}`));
const target = elList.find(item => item.parentNode === el);
if (!target)
return;
const pendant = PENDANT_MAP[place];
if (ctx.slots[pendant]) {
target.style.transform = `translateX(${place === 'suffix' ? '-' : ''}${el.querySelector(`.el-input-group__${pendant}`).offsetWidth}px)`;
}
else {
target.removeAttribute('style');
}
};
const updateIconOffset = () => {
calcIconOffset('prefix');
calcIconOffset('suffix');
};
const handleInput = event => {
const { value } = event.target;
if (isComposing.value)
return;
if (value === nativeInputValue.value)
return;
ctx.emit(constants.UPDATE_MODEL_EVENT, value);
ctx.emit('input', value);
vue.nextTick(setNativeInputValue);
};
const handleChange = event => {
ctx.emit('change', event.target.value);
};
const focus = () => {
vue.nextTick(() => {
inputOrTextarea.value.focus();
});
};
const blur = () => {
inputOrTextarea.value.blur();
};
const handleFocus = event => {
focused.value = true;
ctx.emit('focus', event);
};
const handleBlur = event => {
var _a;
focused.value = false;
ctx.emit('blur', event);
if (props.validateEvent) {
(_a = elFormItem.formItemMitt) === null || _a === void 0 ? void 0 : _a.emit('el.form.blur', [props.modelValue]);
}
};
const select = () => {
inputOrTextarea.value.select();
};
const handleCompositionStart = () => {
isComposing.value = true;
};
const handleCompositionUpdate = event => {
const text = event.target.value;
const lastCharacter = text[text.length - 1] || '';
isComposing.value = !isDef.isKorean(lastCharacter);
};
const handleCompositionEnd = event => {
if (isComposing.value) {
isComposing.value = false;
handleInput(event);
}
};
const clear = () => {
ctx.emit(constants.UPDATE_MODEL_EVENT, '');
ctx.emit('change', '');
ctx.emit('clear');
};
const handlePasswordVisible = () => {
passwordVisible.value = !passwordVisible.value;
focus();
};
const getSuffixVisible = () => {
return ctx.slots.suffix ||
props.suffixIcon ||
showClear.value ||
props.showPassword ||
isWordLimitVisible.value ||
(validateState.value && needStatusIcon.value);
};
vue.watch(() => props.modelValue, val => {
var _a;
vue.nextTick(resizeTextarea);
if (props.validateEvent) {
(_a = elFormItem.formItemMitt) === null || _a === void 0 ? void 0 : _a.emit('el.form.change', [val]);
}
});
vue.watch(nativeInputValue, () => {
setNativeInputValue();
});
vue.watch(() => props.type, () => {
vue.nextTick(() => {
setNativeInputValue();
resizeTextarea();
updateIconOffset();
});
});
vue.onMounted(() => {
setNativeInputValue();
updateIconOffset();
vue.nextTick(resizeTextarea);
});
vue.onUpdated(() => {
vue.nextTick(updateIconOffset);
});
const onMouseLeave = e => {
hovering.value = false;
ctx.emit('mouseleave', e);
};
const onMouseEnter = e => {
hovering.value = true;
ctx.emit('mouseenter', e);
};
const handleKeydown = e => {
ctx.emit('keydown', e);
};
return {
input,
textarea,
attrs,
inputSize,
validateState,
validateIcon,
textareaStyle,
resizeTextarea,
inputDisabled,
showClear,
showPwdVisible,
isWordLimitVisible,
upperLimit,
textLength,
hovering,
inputExceed,
passwordVisible,
inputOrTextarea,
handleInput,
handleChange,
handleFocus,
handleBlur,
handleCompositionStart,
handleCompositionUpdate,
handleCompositionEnd,
handlePasswordVisible,
clear,
select,
focus,
blur,
getSuffixVisible,
onMouseLeave,
onMouseEnter,
handleKeydown,
};
},
});
const _hoisted_1 = {
key: 0,
class: "el-input-group__prepend"
};
const _hoisted_2 = {
key: 2,
class: "el-input__prefix"
};
const _hoisted_3 = {
key: 3,
class: "el-input__suffix"
};
const _hoisted_4 = { class: "el-input__suffix-inner" };
const _hoisted_5 = {
key: 3,
class: "el-input__count"
};
const _hoisted_6 = { class: "el-input__count-inner" };
const _hoisted_7 = {
key: 4,
class: "el-input-group__append"
};
const _hoisted_8 = {
key: 2,
class: "el-input__count"
};
function render(_ctx, _cache, $props, $setup, $data, $options) {
return (vue.openBlock(), vue.createBlock("div", {
class: [
_ctx.type === 'textarea' ? 'el-textarea' : 'el-input',
_ctx.inputSize ? 'el-input--' + _ctx.inputSize : '',
{
'is-disabled': _ctx.inputDisabled,
'is-exceed': _ctx.inputExceed,
'el-input-group': _ctx.$slots.prepend || _ctx.$slots.append,
'el-input-group--append': _ctx.$slots.append,
'el-input-group--prepend': _ctx.$slots.prepend,
'el-input--prefix': _ctx.$slots.prefix || _ctx.prefixIcon,
'el-input--suffix': _ctx.$slots.suffix || _ctx.suffixIcon || _ctx.clearable || _ctx.showPassword
},
_ctx.$attrs.class
],
style: _ctx.$attrs.style,
onMouseenter: _cache[19] || (_cache[19] = (...args) => (_ctx.onMouseEnter && _ctx.onMouseEnter(...args))),
onMouseleave: _cache[20] || (_cache[20] = (...args) => (_ctx.onMouseLeave && _ctx.onMouseLeave(...args)))
}, [
(_ctx.type !== 'textarea')
? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 0 }, [
vue.createCommentVNode(" 前置元素 "),
(_ctx.$slots.prepend)
? (vue.openBlock(), vue.createBlock("div", _hoisted_1, [
vue.renderSlot(_ctx.$slots, "prepend")
]))
: vue.createCommentVNode("v-if", true),
(_ctx.type !== 'textarea')
? (vue.openBlock(), vue.createBlock("input", vue.mergeProps({
key: 1,
ref: "input",
class: "el-input__inner"
}, _ctx.attrs, {
type: _ctx.showPassword ? (_ctx.passwordVisible ? 'text': 'password') : _ctx.type,
disabled: _ctx.inputDisabled,
readonly: _ctx.readonly,
autocomplete: _ctx.autocomplete,
tabindex: _ctx.tabindex,
"aria-label": _ctx.label,
placeholder: _ctx.placeholder,
onCompositionstart: _cache[1] || (_cache[1] = (...args) => (_ctx.handleCompositionStart && _ctx.handleCompositionStart(...args))),
onCompositionupdate: _cache[2] || (_cache[2] = (...args) => (_ctx.handleCompositionUpdate && _ctx.handleCompositionUpdate(...args))),
onCompositionend: _cache[3] || (_cache[3] = (...args) => (_ctx.handleCompositionEnd && _ctx.handleCompositionEnd(...args))),
onInput: _cache[4] || (_cache[4] = (...args) => (_ctx.handleInput && _ctx.handleInput(...args))),
onFocus: _cache[5] || (_cache[5] = (...args) => (_ctx.handleFocus && _ctx.handleFocus(...args))),
onBlur: _cache[6] || (_cache[6] = (...args) => (_ctx.handleBlur && _ctx.handleBlur(...args))),
onChange: _cache[7] || (_cache[7] = (...args) => (_ctx.handleChange && _ctx.handleChange(...args))),
onKeydown: _cache[8] || (_cache[8] = (...args) => (_ctx.handleKeydown && _ctx.handleKeydown(...args)))
}), null, 16 /* FULL_PROPS */, ["type", "disabled", "readonly", "autocomplete", "tabindex", "aria-label", "placeholder"]))
: vue.createCommentVNode("v-if", true),
vue.createCommentVNode(" 前置内容 "),
(_ctx.$slots.prefix || _ctx.prefixIcon)
? (vue.openBlock(), vue.createBlock("span", _hoisted_2, [
vue.renderSlot(_ctx.$slots, "prefix"),
(_ctx.prefixIcon)
? (vue.openBlock(), vue.createBlock("i", {
key: 0,
class: ['el-input__icon', _ctx.prefixIcon]
}, null, 2 /* CLASS */))
: vue.createCommentVNode("v-if", true)
]))
: vue.createCommentVNode("v-if", true),
vue.createCommentVNode(" 后置内容 "),
(_ctx.getSuffixVisible())
? (vue.openBlock(), vue.createBlock("span", _hoisted_3, [
vue.createVNode("span", _hoisted_4, [
(!_ctx.showClear || !_ctx.showPwdVisible || !_ctx.isWordLimitVisible)
? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 0 }, [
vue.renderSlot(_ctx.$slots, "suffix"),
(_ctx.suffixIcon)
? (vue.openBlock(), vue.createBlock("i", {
key: 0,
class: ['el-input__icon', _ctx.suffixIcon]
}, null, 2 /* CLASS */))
: vue.createCommentVNode("v-if", true)
], 64 /* STABLE_FRAGMENT */))
: vue.createCommentVNode("v-if", true),
(_ctx.showClear)
? (vue.openBlock(), vue.createBlock("i", {
key: 1,
class: "el-input__icon el-icon-circle-close el-input__clear",
onMousedown: _cache[9] || (_cache[9] = vue.withModifiers(() => {}, ["prevent"])),
onClick: _cache[10] || (_cache[10] = (...args) => (_ctx.clear && _ctx.clear(...args)))
}, null, 32 /* HYDRATE_EVENTS */))
: vue.createCommentVNode("v-if", true),
(_ctx.showPwdVisible)
? (vue.openBlock(), vue.createBlock("i", {
key: 2,
class: "el-input__icon el-icon-view el-input__clear",
onClick: _cache[11] || (_cache[11] = (...args) => (_ctx.handlePasswordVisible && _ctx.handlePasswordVisible(...args)))
}))
: vue.createCommentVNode("v-if", true),
(_ctx.isWordLimitVisible)
? (vue.openBlock(), vue.createBlock("span", _hoisted_5, [
vue.createVNode("span", _hoisted_6, vue.toDisplayString(_ctx.textLength) + "/" + vue.toDisplayString(_ctx.upperLimit), 1 /* TEXT */)
]))
: vue.createCommentVNode("v-if", true)
]),
(_ctx.validateState)
? (vue.openBlock(), vue.createBlock("i", {
key: 0,
class: ['el-input__icon', 'el-input__validateIcon', _ctx.validateIcon]
}, null, 2 /* CLASS */))
: vue.createCommentVNode("v-if", true)
]))
: vue.createCommentVNode("v-if", true),
vue.createCommentVNode(" 后置元素 "),
(_ctx.$slots.append)
? (vue.openBlock(), vue.createBlock("div", _hoisted_7, [
vue.renderSlot(_ctx.$slots, "append")
]))
: vue.createCommentVNode("v-if", true)
], 64 /* STABLE_FRAGMENT */))
: (vue.openBlock(), vue.createBlock("textarea", vue.mergeProps({
key: 1,
ref: "textarea",
class: "el-textarea__inner"
}, _ctx.attrs, {
tabindex: _ctx.tabindex,
disabled: _ctx.inputDisabled,
readonly: _ctx.readonly,
autocomplete: _ctx.autocomplete,
style: _ctx.textareaStyle,
"aria-label": _ctx.label,
placeholder: _ctx.placeholder,
onCompositionstart: _cache[12] || (_cache[12] = (...args) => (_ctx.handleCompositionStart && _ctx.handleCompositionStart(...args))),
onCompositionupdate: _cache[13] || (_cache[13] = (...args) => (_ctx.handleCompositionUpdate && _ctx.handleCompositionUpdate(...args))),
onCompositionend: _cache[14] || (_cache[14] = (...args) => (_ctx.handleCompositionEnd && _ctx.handleCompositionEnd(...args))),
onInput: _cache[15] || (_cache[15] = (...args) => (_ctx.handleInput && _ctx.handleInput(...args))),
onFocus: _cache[16] || (_cache[16] = (...args) => (_ctx.handleFocus && _ctx.handleFocus(...args))),
onBlur: _cache[17] || (_cache[17] = (...args) => (_ctx.handleBlur && _ctx.handleBlur(...args))),
onChange: _cache[18] || (_cache[18] = (...args) => (_ctx.handleChange && _ctx.handleChange(...args)))
}), null, 16 /* FULL_PROPS */, ["tabindex", "disabled", "readonly", "autocomplete", "aria-label", "placeholder"])),
(_ctx.isWordLimitVisible && _ctx.type === 'textarea')
? (vue.openBlock(), vue.createBlock("span", _hoisted_8, vue.toDisplayString(_ctx.textLength) + "/" + vue.toDisplayString(_ctx.upperLimit), 1 /* TEXT */))
: vue.createCommentVNode("v-if", true)
], 38 /* CLASS, STYLE, HYDRATE_EVENTS */))
}
script.render = render;
script.__file = "packages/input/src/index.vue";
script.install = (app) => {
app.component(script.name, script);
};
const _Input = script;
exports.default = _Input;
;