import _mergeJSXProps2 from "@vue/babel-helper-vue-jsx-merge-props"; import _mergeJSXProps from "@vue/babel-helper-vue-jsx-merge-props"; import _extends from "@babel/runtime/helpers/esm/extends"; // Utils import { resetScroll } from '../utils/dom/reset-scroll'; import { formatNumber } from '../utils/format/number'; import { preventDefault } from '../utils/dom/event'; import { getRootScrollTop, setRootScrollTop } from '../utils/dom/scroll'; import { isDef, addUnit, isObject, isPromise, isFunction, createNamespace } from '../utils'; // Components import Icon from '../icon'; import Cell from '../cell'; import { cellProps } from '../cell/shared'; var _createNamespace = createNamespace('field'), createComponent = _createNamespace[0], bem = _createNamespace[1]; export default createComponent({ inheritAttrs: false, provide: function provide() { return { vanField: this }; }, inject: { vanForm: { default: null } }, props: _extends({}, cellProps, { name: String, rules: Array, disabled: { type: Boolean, default: null }, readonly: { type: Boolean, default: null }, autosize: [Boolean, Object], leftIcon: String, rightIcon: String, clearable: Boolean, formatter: Function, maxlength: [Number, String], labelWidth: [Number, String], labelClass: null, labelAlign: String, inputAlign: String, placeholder: String, errorMessage: String, errorMessageAlign: String, showWordLimit: Boolean, value: { type: [Number, String], default: '' }, type: { type: String, default: 'text' }, error: { type: Boolean, default: null }, colon: { type: Boolean, default: null }, clearTrigger: { type: String, default: 'focus' }, formatTrigger: { type: String, default: 'onChange' } }), data: function data() { return { focused: false, validateFailed: false, validateMessage: '' }; }, watch: { value: function value() { this.updateValue(this.value); this.resetValidation(); this.validateWithTrigger('onChange'); this.$nextTick(this.adjustSize); } }, mounted: function mounted() { this.updateValue(this.value, this.formatTrigger); this.$nextTick(this.adjustSize); if (this.vanForm) { this.vanForm.addField(this); } }, beforeDestroy: function beforeDestroy() { if (this.vanForm) { this.vanForm.removeField(this); } }, computed: { showClear: function showClear() { var readonly = this.getProp('readonly'); if (this.clearable && !readonly) { var hasValue = isDef(this.value) && this.value !== ''; var trigger = this.clearTrigger === 'always' || this.clearTrigger === 'focus' && this.focused; return hasValue && trigger; } }, showError: function showError() { if (this.error !== null) { return this.error; } if (this.vanForm && this.vanForm.showError && this.validateFailed) { return true; } }, listeners: function listeners() { return _extends({}, this.$listeners, { blur: this.onBlur, focus: this.onFocus, input: this.onInput, click: this.onClickInput, keypress: this.onKeypress }); }, labelStyle: function labelStyle() { var labelWidth = this.getProp('labelWidth'); if (labelWidth) { return { width: addUnit(labelWidth) }; } }, formValue: function formValue() { if (this.children && (this.$scopedSlots.input || this.$slots.input)) { return this.children.value; } return this.value; } }, methods: { // @exposed-api focus: function focus() { if (this.$refs.input) { this.$refs.input.focus(); } }, // @exposed-api blur: function blur() { if (this.$refs.input) { this.$refs.input.blur(); } }, runValidator: function runValidator(value, rule) { return new Promise(function (resolve) { var returnVal = rule.validator(value, rule); if (isPromise(returnVal)) { return returnVal.then(resolve); } resolve(returnVal); }); }, isEmptyValue: function isEmptyValue(value) { if (Array.isArray(value)) { return !value.length; } if (value === 0) { return false; } return !value; }, runSyncRule: function runSyncRule(value, rule) { if (rule.required && this.isEmptyValue(value)) { return false; } if (rule.pattern && !rule.pattern.test(value)) { return false; } return true; }, getRuleMessage: function getRuleMessage(value, rule) { var message = rule.message; if (isFunction(message)) { return message(value, rule); } return message; }, runRules: function runRules(rules) { var _this = this; return rules.reduce(function (promise, rule) { return promise.then(function () { if (_this.validateFailed) { return; } var value = _this.formValue; if (rule.formatter) { value = rule.formatter(value, rule); } if (!_this.runSyncRule(value, rule)) { _this.validateFailed = true; _this.validateMessage = _this.getRuleMessage(value, rule); return; } if (rule.validator) { return _this.runValidator(value, rule).then(function (result) { if (result === false) { _this.validateFailed = true; _this.validateMessage = _this.getRuleMessage(value, rule); } }); } }); }, Promise.resolve()); }, validate: function validate(rules) { var _this2 = this; if (rules === void 0) { rules = this.rules; } return new Promise(function (resolve) { if (!rules) { resolve(); } _this2.resetValidation(); _this2.runRules(rules).then(function () { if (_this2.validateFailed) { resolve({ name: _this2.name, message: _this2.validateMessage }); } else { resolve(); } }); }); }, validateWithTrigger: function validateWithTrigger(trigger) { if (this.vanForm && this.rules) { var defaultTrigger = this.vanForm.validateTrigger === trigger; var rules = this.rules.filter(function (rule) { if (rule.trigger) { return rule.trigger === trigger; } return defaultTrigger; }); if (rules.length) { this.validate(rules); } } }, resetValidation: function resetValidation() { if (this.validateFailed) { this.validateFailed = false; this.validateMessage = ''; } }, updateValue: function updateValue(value, trigger) { if (trigger === void 0) { trigger = 'onChange'; } value = isDef(value) ? String(value) : ''; // native maxlength have incorrect line-break counting // see: https://github.com/vant-ui/vant/issues/5033 var maxlength = this.maxlength; if (isDef(maxlength) && value.length > maxlength) { if (this.value && this.value.length === +maxlength) { value = this.value; } else { value = value.slice(0, maxlength); } } if (this.type === 'number' || this.type === 'digit') { var isNumber = this.type === 'number'; value = formatNumber(value, isNumber, isNumber); } if (this.formatter && trigger === this.formatTrigger) { value = this.formatter(value); } var input = this.$refs.input; if (input && value !== input.value) { input.value = value; } if (value !== this.value) { this.$emit('input', value); } }, onInput: function onInput(event) { // not update v-model when composing if (event.target.composing) { return; } this.updateValue(event.target.value); }, onFocus: function onFocus(event) { this.focused = true; this.$emit('focus', event); // https://github.com/vant-ui/vant/issues/9715 this.$nextTick(this.adjustSize); // readonly not work in legacy mobile safari /* istanbul ignore if */ if (this.getProp('readonly')) { this.blur(); } }, onBlur: function onBlur(event) { if (this.getProp('readonly')) { return; } this.focused = false; this.updateValue(this.value, 'onBlur'); this.$emit('blur', event); this.validateWithTrigger('onBlur'); this.$nextTick(this.adjustSize); resetScroll(); }, onClick: function onClick(event) { this.$emit('click', event); }, onClickInput: function onClickInput(event) { this.$emit('click-input', event); }, onClickLeftIcon: function onClickLeftIcon(event) { this.$emit('click-left-icon', event); }, onClickRightIcon: function onClickRightIcon(event) { this.$emit('click-right-icon', event); }, onClear: function onClear(event) { preventDefault(event); this.$emit('input', ''); this.$emit('clear', event); }, onKeypress: function onKeypress(event) { var ENTER_CODE = 13; if (event.keyCode === ENTER_CODE) { var submitOnEnter = this.getProp('submitOnEnter'); if (!submitOnEnter && this.type !== 'textarea') { preventDefault(event); } // trigger blur after click keyboard search button if (this.type === 'search') { this.blur(); } } this.$emit('keypress', event); }, adjustSize: function adjustSize() { var input = this.$refs.input; if (!(this.type === 'textarea' && this.autosize) || !input) { return; } var scrollTop = getRootScrollTop(); input.style.height = 'auto'; var height = input.scrollHeight; if (isObject(this.autosize)) { var _this$autosize = this.autosize, maxHeight = _this$autosize.maxHeight, minHeight = _this$autosize.minHeight; if (maxHeight) { height = Math.min(height, maxHeight); } if (minHeight) { height = Math.max(height, minHeight); } } if (height) { input.style.height = height + 'px'; // https://github.com/vant-ui/vant/issues/9178 setRootScrollTop(scrollTop); } }, genInput: function genInput() { var h = this.$createElement; var type = this.type; var disabled = this.getProp('disabled'); var readonly = this.getProp('readonly'); var inputSlot = this.slots('input'); var inputAlign = this.getProp('inputAlign'); if (inputSlot) { return h("div", { "class": bem('control', [inputAlign, 'custom']), "on": { "click": this.onClickInput } }, [inputSlot]); } var inputProps = { ref: 'input', class: bem('control', inputAlign), domProps: { value: this.value }, attrs: _extends({}, this.$attrs, { name: this.name, disabled: disabled, readonly: readonly, placeholder: this.placeholder }), on: this.listeners, // add model directive to skip IME composition directives: [{ name: 'model', value: this.value }] }; if (type === 'textarea') { return h("textarea", _mergeJSXProps([{}, inputProps])); } var inputType = type; var inputMode; // type="number" is weird in iOS, and can't prevent dot in Android // so use inputmode to set keyboard in modern browsers if (type === 'number') { inputType = 'text'; inputMode = 'decimal'; } if (type === 'digit') { inputType = 'tel'; inputMode = 'numeric'; } return h("input", _mergeJSXProps2([{ "attrs": { "type": inputType, "inputmode": inputMode } }, inputProps])); }, genLeftIcon: function genLeftIcon() { var h = this.$createElement; var showLeftIcon = this.slots('left-icon') || this.leftIcon; if (showLeftIcon) { return h("div", { "class": bem('left-icon'), "on": { "click": this.onClickLeftIcon } }, [this.slots('left-icon') || h(Icon, { "attrs": { "name": this.leftIcon, "classPrefix": this.iconPrefix } })]); } }, genRightIcon: function genRightIcon() { var h = this.$createElement; var slots = this.slots; var showRightIcon = slots('right-icon') || this.rightIcon; if (showRightIcon) { return h("div", { "class": bem('right-icon'), "on": { "click": this.onClickRightIcon } }, [slots('right-icon') || h(Icon, { "attrs": { "name": this.rightIcon, "classPrefix": this.iconPrefix } })]); } }, genWordLimit: function genWordLimit() { var h = this.$createElement; if (this.showWordLimit && this.maxlength) { var count = (this.value || '').length; return h("div", { "class": bem('word-limit') }, [h("span", { "class": bem('word-num') }, [count]), "/", this.maxlength]); } }, genMessage: function genMessage() { var h = this.$createElement; if (this.vanForm && this.vanForm.showErrorMessage === false) { return; } var message = this.errorMessage || this.validateMessage; if (message) { var errorMessageAlign = this.getProp('errorMessageAlign'); return h("div", { "class": bem('error-message', errorMessageAlign) }, [message]); } }, getProp: function getProp(key) { if (isDef(this[key])) { return this[key]; } if (this.vanForm && isDef(this.vanForm[key])) { return this.vanForm[key]; } }, genLabel: function genLabel() { var h = this.$createElement; var colon = this.getProp('colon') ? ':' : ''; if (this.slots('label')) { return [this.slots('label'), colon]; } if (this.label) { return h("span", [this.label + colon]); } } }, render: function render() { var _bem; var h = arguments[0]; var slots = this.slots; var disabled = this.getProp('disabled'); var labelAlign = this.getProp('labelAlign'); var scopedSlots = { icon: this.genLeftIcon }; var Label = this.genLabel(); if (Label) { scopedSlots.title = function () { return Label; }; } var extra = this.slots('extra'); if (extra) { scopedSlots.extra = function () { return extra; }; } return h(Cell, { "attrs": { "icon": this.leftIcon, "size": this.size, "center": this.center, "border": this.border, "isLink": this.isLink, "required": this.required, "clickable": this.clickable, "titleStyle": this.labelStyle, "valueClass": bem('value'), "titleClass": [bem('label', labelAlign), this.labelClass], "arrowDirection": this.arrowDirection }, "scopedSlots": scopedSlots, "class": bem((_bem = { error: this.showError, disabled: disabled }, _bem["label-" + labelAlign] = labelAlign, _bem['min-height'] = this.type === 'textarea' && !this.autosize, _bem)), "on": { "click": this.onClick } }, [h("div", { "class": bem('body') }, [this.genInput(), this.showClear && h(Icon, { "attrs": { "name": "clear" }, "class": bem('clear'), "on": { "touchstart": this.onClear } }), this.genRightIcon(), slots('button') && h("div", { "class": bem('button') }, [slots('button')])]), this.genWordLimit(), this.genMessage()]); } });