UNPKG

element-plus

Version:
633 lines (623 loc) 20.2 kB
import { defineComponent, watch, reactive, toRefs, provide, ref, computed, openBlock, createElementBlock, normalizeClass, renderSlot, inject, onMounted, onUpdated, onBeforeUnmount, nextTick, h, Fragment, getCurrentInstance, resolveComponent, createVNode, withCtx, normalizeStyle, createTextVNode, toDisplayString, createCommentVNode, createElementVNode, Transition } from 'vue'; import mitt from 'mitt'; import { elFormEvents, elFormKey, elFormItemKey } from '../../tokens'; import AsyncValidator from 'async-validator'; import { NOOP } from '@vue/shared'; import { useGlobalConfig, addUnit, getPropByPath } from '../../utils/util'; import { isValidComponentSize } from '../../utils/validators'; import { addResizeListener, removeResizeListener } from '../../utils/resize-event'; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); function useFormLabelWidth() { const potentialLabelWidthArr = ref([]); const autoLabelWidth = computed(() => { if (!potentialLabelWidthArr.value.length) return "0"; const max = Math.max(...potentialLabelWidthArr.value); return max ? `${max}px` : ""; }); function getLabelWidthIndex(width) { const index = potentialLabelWidthArr.value.indexOf(width); if (index === -1) { console.warn("[Element Warn][ElementForm]unexpected width " + width); } return index; } function registerLabelWidth(val, oldVal) { if (val && oldVal) { const index = getLabelWidthIndex(oldVal); potentialLabelWidthArr.value.splice(index, 1, val); } else if (val) { potentialLabelWidthArr.value.push(val); } } function deregisterLabelWidth(val) { const index = getLabelWidthIndex(val); index > -1 && potentialLabelWidthArr.value.splice(index, 1); } return { autoLabelWidth, registerLabelWidth, deregisterLabelWidth }; } var script = defineComponent({ name: "ElForm", props: { model: Object, rules: Object, labelPosition: String, labelWidth: { type: [String, Number], default: "" }, labelSuffix: { type: String, default: "" }, inline: Boolean, inlineMessage: Boolean, statusIcon: Boolean, showMessage: { type: Boolean, default: true }, size: String, disabled: Boolean, validateOnRuleChange: { type: Boolean, default: true }, hideRequiredAsterisk: { type: Boolean, default: false } }, emits: ["validate"], setup(props, { emit }) { const formMitt = mitt(); const fields = []; watch(() => props.rules, () => { fields.forEach((field) => { field.removeValidateEvents(); field.addValidateEvents(); }); if (props.validateOnRuleChange) { validate(() => ({})); } }); formMitt.on(elFormEvents.addField, (field) => { if (field) { fields.push(field); } }); formMitt.on(elFormEvents.removeField, (field) => { if (field.prop) { fields.splice(fields.indexOf(field), 1); } }); const resetFields = () => { if (!props.model) { console.warn("[Element Warn][Form]model is required for resetFields to work."); return; } fields.forEach((field) => { field.resetField(); }); }; const clearValidate = (props2 = []) => { const fds = props2.length ? typeof props2 === "string" ? fields.filter((field) => props2 === field.prop) : fields.filter((field) => props2.indexOf(field.prop) > -1) : fields; fds.forEach((field) => { field.clearValidate(); }); }; const validate = (callback) => { if (!props.model) { console.warn("[Element Warn][Form]model is required for validate to work!"); return; } let promise; if (typeof callback !== "function") { promise = new Promise((resolve, reject) => { callback = function(valid2, invalidFields2) { if (valid2) { resolve(true); } else { reject(invalidFields2); } }; }); } if (fields.length === 0) { callback(true); } let valid = true; let count = 0; let invalidFields = {}; for (const field of fields) { field.validate("", (message, field2) => { if (message) { valid = false; } invalidFields = __spreadValues(__spreadValues({}, invalidFields), field2); if (++count === fields.length) { callback(valid, invalidFields); } }); } return promise; }; const validateField = (props2, cb) => { props2 = [].concat(props2); const fds = fields.filter((field) => props2.indexOf(field.prop) !== -1); if (!fields.length) { console.warn("[Element Warn]please pass correct props!"); return; } fds.forEach((field) => { field.validate("", cb); }); }; const elForm = reactive(__spreadValues(__spreadProps(__spreadValues({ formMitt }, toRefs(props)), { resetFields, clearValidate, validateField, emit }), useFormLabelWidth())); provide(elFormKey, elForm); return { validate, resetFields, clearValidate, validateField }; } }); function render(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("form", { class: normalizeClass(["el-form", [ _ctx.labelPosition ? "el-form--label-" + _ctx.labelPosition : "", { "el-form--inline": _ctx.inline } ]]) }, [ renderSlot(_ctx.$slots, "default") ], 2); } script.render = render; script.__file = "packages/components/form/src/form.vue"; var LabelWrap = defineComponent({ name: "ElLabelWrap", props: { isAutoWidth: Boolean, updateAll: Boolean }, setup(props, { slots }) { const el = ref(null); const elForm = inject(elFormKey); const elFormItem = inject(elFormItemKey); const computedWidth = ref(0); watch(computedWidth, (val, oldVal) => { if (props.updateAll) { elForm.registerLabelWidth(val, oldVal); elFormItem.updateComputedLabelWidth(val); } }); const getLabelWidth = () => { var _a; if ((_a = el.value) == null ? void 0 : _a.firstElementChild) { const width = window.getComputedStyle(el.value.firstElementChild).width; return Math.ceil(parseFloat(width)); } else { return 0; } }; const updateLabelWidth = (action = "update") => { nextTick(() => { if (slots.default && props.isAutoWidth) { if (action === "update") { computedWidth.value = getLabelWidth(); } else if (action === "remove") { elForm.deregisterLabelWidth(computedWidth.value); } } }); }; const updateLabelWidthFn = () => updateLabelWidth("update"); onMounted(() => { addResizeListener(el.value.firstElementChild, updateLabelWidthFn); updateLabelWidthFn(); }); onUpdated(updateLabelWidthFn); onBeforeUnmount(() => { updateLabelWidth("remove"); removeResizeListener(el.value.firstElementChild, updateLabelWidthFn); }); function render() { var _a, _b; if (!slots) return null; if (props.isAutoWidth) { const autoLabelWidth = elForm.autoLabelWidth; const style = {}; if (autoLabelWidth && autoLabelWidth !== "auto") { const marginWidth = Math.max(0, parseInt(autoLabelWidth, 10) - computedWidth.value); const marginPosition = elForm.labelPosition === "left" ? "marginRight" : "marginLeft"; if (marginWidth) { style[marginPosition] = marginWidth + "px"; } } return h("div", { ref: el, class: ["el-form-item__label-wrap"], style }, (_a = slots.default) == null ? void 0 : _a.call(slots)); } else { return h(Fragment, { ref: el }, (_b = slots.default) == null ? void 0 : _b.call(slots)); } } return render; } }); var __defProp$1 = Object.defineProperty; var __defProps$1 = Object.defineProperties; var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; var __hasOwnProp$1 = Object.prototype.hasOwnProperty; var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) { if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); } return a; }; var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); var script$1 = defineComponent({ name: "ElFormItem", componentName: "ElFormItem", components: { LabelWrap }, props: { label: String, labelWidth: { type: [String, Number], default: "" }, prop: String, required: { type: Boolean, default: void 0 }, rules: [Object, Array], error: String, validateStatus: String, for: String, inlineMessage: { type: [String, Boolean], default: "" }, showMessage: { type: Boolean, default: true }, size: { type: String, validator: isValidComponentSize } }, setup(props, { slots }) { const formItemMitt = mitt(); const $ELEMENT = useGlobalConfig(); const elForm = inject(elFormKey, {}); const validateState = ref(""); const validateMessage = ref(""); const validateDisabled = ref(false); const computedLabelWidth = ref(""); const vm = getCurrentInstance(); const isNested = computed(() => { let parent = vm.parent; while (parent && parent.type.name !== "ElForm") { if (parent.type.name === "ElFormItem") { return true; } parent = parent.parent; } return false; }); let initialValue = void 0; watch(() => props.error, (val) => { validateMessage.value = val; validateState.value = val ? "error" : ""; }, { immediate: true }); watch(() => props.validateStatus, (val) => { validateState.value = val; }); const labelFor = computed(() => props.for || props.prop); const labelStyle = computed(() => { const ret = {}; if (elForm.labelPosition === "top") return ret; const labelWidth = addUnit(props.labelWidth) || addUnit(elForm.labelWidth); if (labelWidth) { ret.width = labelWidth; } return ret; }); const contentStyle = computed(() => { const ret = {}; if (elForm.labelPosition === "top" || elForm.inline) { return ret; } if (!props.label && !props.labelWidth && isNested.value) { return ret; } const labelWidth = addUnit(props.labelWidth) || addUnit(elForm.labelWidth); if (!props.label && !slots.label) { ret.marginLeft = labelWidth; } return ret; }); const fieldValue = computed(() => { const model = elForm.model; if (!model || !props.prop) { return; } let path = props.prop; if (path.indexOf(":") !== -1) { path = path.replace(/:/, "."); } return getPropByPath(model, path, true).v; }); const isRequired = computed(() => { let rules = getRules(); let required = false; if (rules && rules.length) { rules.every((rule) => { if (rule.required) { required = true; return false; } return true; }); } return required; }); const elFormItemSize = computed(() => props.size || elForm.size); const sizeClass = computed(() => { return elFormItemSize.value || $ELEMENT.size; }); const validate = (trigger, callback = NOOP) => { validateDisabled.value = false; const rules = getFilteredRule(trigger); if ((!rules || rules.length === 0) && props.required === void 0) { callback(); return; } validateState.value = "validating"; const descriptor = {}; if (rules && rules.length > 0) { rules.forEach((rule) => { delete rule.trigger; }); } descriptor[props.prop] = rules; const validator = new AsyncValidator(descriptor); const model = {}; model[props.prop] = fieldValue.value; validator.validate(model, { firstFields: true }, (errors, invalidFields) => { var _a; validateState.value = !errors ? "success" : "error"; validateMessage.value = errors ? errors[0].message : ""; callback(validateMessage.value, invalidFields); (_a = elForm.emit) == null ? void 0 : _a.call(elForm, "validate", props.prop, !errors, validateMessage.value || null); }); }; const clearValidate = () => { validateState.value = ""; validateMessage.value = ""; validateDisabled.value = false; }; const resetField = () => { validateState.value = ""; validateMessage.value = ""; let model = elForm.model; let value = fieldValue.value; let path = props.prop; if (path.indexOf(":") !== -1) { path = path.replace(/:/, "."); } let prop = getPropByPath(model, path, true); validateDisabled.value = true; if (Array.isArray(value)) { prop.o[prop.k] = [].concat(initialValue); } else { prop.o[prop.k] = initialValue; } nextTick(() => { validateDisabled.value = false; }); }; const getRules = () => { const formRules = elForm.rules; const selfRules = props.rules; const requiredRule = props.required !== void 0 ? { required: !!props.required } : []; const prop = getPropByPath(formRules, props.prop || "", false); const normalizedRule = formRules ? prop.o[props.prop || ""] || prop.v : []; return [].concat(selfRules || normalizedRule || []).concat(requiredRule); }; const getFilteredRule = (trigger) => { const rules = getRules(); return rules.filter((rule) => { if (!rule.trigger || trigger === "") return true; if (Array.isArray(rule.trigger)) { return rule.trigger.indexOf(trigger) > -1; } else { return rule.trigger === trigger; } }).map((rule) => __spreadValues$1({}, rule)); }; const onFieldBlur = () => { validate("blur"); }; const onFieldChange = () => { if (validateDisabled.value) { validateDisabled.value = false; return; } validate("change"); }; const updateComputedLabelWidth = (width) => { computedLabelWidth.value = width ? `${width}px` : ""; }; const addValidateEvents = () => { const rules = getRules(); if (rules.length || props.required !== void 0) { formItemMitt.on("el.form.blur", onFieldBlur); formItemMitt.on("el.form.change", onFieldChange); } }; const removeValidateEvents = () => { formItemMitt.off("el.form.blur", onFieldBlur); formItemMitt.off("el.form.change", onFieldChange); }; const elFormItem = reactive(__spreadProps$1(__spreadValues$1({}, toRefs(props)), { size: sizeClass, validateState, removeValidateEvents, addValidateEvents, resetField, clearValidate, validate, formItemMitt, updateComputedLabelWidth })); onMounted(() => { var _a; if (props.prop) { (_a = elForm.formMitt) == null ? void 0 : _a.emit(elFormEvents.addField, elFormItem); let value = fieldValue.value; initialValue = Array.isArray(value) ? [...value] : value; addValidateEvents(); } }); onBeforeUnmount(() => { var _a; (_a = elForm.formMitt) == null ? void 0 : _a.emit(elFormEvents.removeField, elFormItem); }); provide(elFormItemKey, elFormItem); const formItemClass = computed(() => [ { "el-form-item--feedback": elForm.statusIcon, "is-error": validateState.value === "error", "is-validating": validateState.value === "validating", "is-success": validateState.value === "success", "is-required": isRequired.value || props.required, "is-no-asterisk": elForm.hideRequiredAsterisk }, sizeClass.value ? "el-form-item--" + sizeClass.value : "" ]); const shouldShowError = computed(() => { return validateState.value === "error" && props.showMessage && elForm.showMessage; }); return { formItemClass, shouldShowError, elForm, labelStyle, contentStyle, validateMessage, labelFor, resetField, clearValidate }; } }); const _hoisted_1 = ["for"]; function render$1(_ctx, _cache, $props, $setup, $data, $options) { const _component_LabelWrap = resolveComponent("LabelWrap"); return openBlock(), createElementBlock("div", { class: normalizeClass(["el-form-item", _ctx.formItemClass]) }, [ createVNode(_component_LabelWrap, { "is-auto-width": _ctx.labelStyle.width === "auto", "update-all": _ctx.elForm.labelWidth === "auto" }, { default: withCtx(() => [ _ctx.label || _ctx.$slots.label ? (openBlock(), createElementBlock("label", { key: 0, for: _ctx.labelFor, class: "el-form-item__label", style: normalizeStyle(_ctx.labelStyle) }, [ renderSlot(_ctx.$slots, "label", { label: _ctx.label + _ctx.elForm.labelSuffix }, () => [ createTextVNode(toDisplayString(_ctx.label + _ctx.elForm.labelSuffix), 1) ]) ], 12, _hoisted_1)) : createCommentVNode("v-if", true) ]), _: 3 }, 8, ["is-auto-width", "update-all"]), createElementVNode("div", { class: "el-form-item__content", style: normalizeStyle(_ctx.contentStyle) }, [ renderSlot(_ctx.$slots, "default"), createVNode(Transition, { name: "el-zoom-in-top" }, { default: withCtx(() => [ _ctx.shouldShowError ? renderSlot(_ctx.$slots, "error", { key: 0, error: _ctx.validateMessage }, () => [ createElementVNode("div", { class: normalizeClass(["el-form-item__error", { "el-form-item__error--inline": typeof _ctx.inlineMessage === "boolean" ? _ctx.inlineMessage : _ctx.elForm.inlineMessage || false }]) }, toDisplayString(_ctx.validateMessage), 3) ]) : createCommentVNode("v-if", true) ]), _: 3 }) ], 4) ], 2); } script$1.render = render$1; script$1.__file = "packages/components/form/src/form-item.vue"; script.install = (app) => { app.component(script.name, script); app.component(script$1.name, script$1); }; script.FormItem = script$1; const _Form = script; const ElForm = _Form; const ElFormItem = script$1; export default _Form; export { ElForm, ElFormItem };