{"version":3,"file":"form.mjs","sources":["../../../../../src/components/ivue-form/form.vue"],"sourcesContent":["<template>\r\n  <form :class=\"wrapperClasses\" @submit.prevent>\r\n    <slot></slot>\r\n  </form>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport {\r\n  computed,\r\n  defineComponent,\r\n  provide,\r\n  toRefs,\r\n  reactive,\r\n  ref,\r\n  watch,\r\n} from 'vue';\r\nimport { oneOf } from '../../utils/assist';\r\nimport { isFunction } from '../../utils/helpers';\r\nimport { debugWarn } from '../../utils/error';\r\nimport { filterFields, useFormLabelWidth } from './utils';\r\n\r\n// type\r\nimport {\r\n  Props,\r\n  FormContext,\r\n  FormContextKey,\r\n  FormValidateCallback,\r\n  FormValidationResult,\r\n} from './types/form';\r\nimport type {\r\n  FormItemProp,\r\n  Arrayable,\r\n  FormItemContext,\r\n} from './types/form-item';\r\nimport type { ValidateFieldsError } from 'async-validator';\r\n\r\nconst prefixCls = 'ivue-form';\r\n\r\nexport default defineComponent({\r\n  name: prefixCls,\r\n  props: {\r\n    /**\r\n     * 表单域标签的位置\r\n     *\r\n     * @type {String}\r\n     */\r\n    labelPosition: {\r\n      type: String,\r\n      validator(value: string) {\r\n        return oneOf(value, ['left', 'right', 'top']);\r\n      },\r\n      default: 'right',\r\n    },\r\n    /**\r\n     * 错误星号的位置\r\n     *\r\n     * @type {String}\r\n     */\r\n    requireAsteriskPosition: {\r\n      type: String,\r\n      validator(value: string) {\r\n        return oneOf(value, ['left', 'right']);\r\n      },\r\n      default: 'left',\r\n    },\r\n    /**\r\n     * 表单域标签的后缀\r\n     *\r\n     * @type {String}\r\n     */\r\n    labelSuffix: {\r\n      type: String,\r\n      default: '',\r\n    },\r\n    /**\r\n     * 标签宽度\r\n     *\r\n     * @type {String | Number}\r\n     */\r\n    labelWidth: {\r\n      type: [String, Number],\r\n      default: '',\r\n    },\r\n    /**\r\n     * 行内表单模式\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    inline: {\r\n      type: Boolean,\r\n    },\r\n    /**\r\n     * 表单数据对象\r\n     *\r\n     * @type {Object}\r\n     */\r\n    model: {\r\n      type: Object,\r\n    },\r\n    /**\r\n     * 表单验证规则\r\n     *\r\n     * @type {Object}\r\n     */\r\n    rules: {\r\n      type: Object,\r\n    },\r\n    /**\r\n     * 是否显示校验错误信息\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    showMessage: {\r\n      type: Boolean,\r\n      default: true,\r\n    },\r\n    /**\r\n     * 验证成功提示状态\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    showSuccessStatus: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 是否隐藏必填字段标签旁边的红色星号\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    hideRequiredAsterisk: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 是否在 rules 属性改变后立即触发一次验证\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    validateOnRuleChange: {\r\n      type: Boolean,\r\n      default: true,\r\n    },\r\n    /**\r\n     * 是否禁用该表单内的所有组件\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    disabled: {\r\n      type: Boolean,\r\n      default: false,\r\n    },\r\n    /**\r\n     * 当校验失败时，滚动到第一个错误表单项\r\n     *\r\n     * @type {Boolean}\r\n     */\r\n    scrollToError: {\r\n      type: Boolean,\r\n    },\r\n  },\r\n  setup(props: Props, { emit }) {\r\n    // 验证的字段\r\n    const fields = ref<FormItemContext[]>([]);\r\n\r\n    // computed\r\n\r\n    // 样式\r\n    const wrapperClasses = computed(() => [\r\n      prefixCls,\r\n      {\r\n        // 表单域标签的位置\r\n        [`${prefixCls}-label-${props.labelPosition}`]: props.labelPosition,\r\n        // 行内表单模式\r\n        [`${prefixCls}-inline`]: props.inline,\r\n      },\r\n    ]);\r\n\r\n    // 是否可以验证\r\n    const isValidatable = computed(() => {\r\n      const hasModel = !!props.model;\r\n\r\n      if (!hasModel) {\r\n        debugWarn(prefixCls, 'model is required for validate to work.');\r\n      }\r\n\r\n      return hasModel;\r\n    });\r\n\r\n    // methods\r\n\r\n    // 对整个表单的内容进行验证\r\n    const validate = async (\r\n      callback?: FormValidateCallback\r\n    ): FormValidationResult => validateField(undefined, callback);\r\n\r\n    // 验证具体的某个字段\r\n    const validateField: FormContext['validateField'] = async (\r\n      modelProps = [],\r\n      callback\r\n    ) => {\r\n      // 是否是函数\r\n      const shouldThrow = !isFunction(callback);\r\n\r\n      try {\r\n        // 验证字段\r\n        const result = await useValidateField(modelProps);\r\n\r\n        // 当结果为 false 时意味着字段不可验证\r\n        if (result === true) {\r\n          callback?.(result);\r\n        }\r\n\r\n        return result;\r\n      } catch (error) {\r\n        const invalidFields = error as ValidateFieldsError;\r\n\r\n        // 当校验失败时，滚动到第一个错误表单项\r\n        if (props.scrollToError) {\r\n          scrollToField(Object.keys(invalidFields)[0]);\r\n        }\r\n\r\n        // 返回失败\r\n        callback?.(false, invalidFields);\r\n\r\n        return shouldThrow && Promise.reject(invalidFields);\r\n      }\r\n    };\r\n\r\n    // 验证字段\r\n    const useValidateField = async (props: Arrayable<FormItemProp> = []) => {\r\n      // 是否可以验证\r\n      if (!isValidatable.value) {\r\n        return false;\r\n      }\r\n\r\n      // 获取验证字段\r\n      fields.value = getValidateFields(props);\r\n\r\n      // 都通过验证\r\n      if (fields.value.length === 0) {\r\n        return true;\r\n      }\r\n\r\n      // 验证错误的字段\r\n      let validationErrors: ValidateFieldsError = {};\r\n\r\n      // 循环触发item的验证\r\n      for (const field of fields.value) {\r\n        try {\r\n          // item验证字段\r\n          await field.validate('');\r\n        } catch (error) {\r\n          // 验证错误的字段\r\n          validationErrors = {\r\n            ...validationErrors,\r\n            ...(error as ValidateFieldsError),\r\n          };\r\n        }\r\n      }\r\n\r\n      // 有验证错误的字段\r\n      if (Object.keys(validationErrors).length === 0) {\r\n        return true;\r\n      }\r\n\r\n      return Promise.reject(validationErrors);\r\n    };\r\n\r\n    // 获取验证字段\r\n    const getValidateFields = (props: Arrayable<FormItemProp>) => {\r\n      if (fields.value.length === 0) {\r\n        return [];\r\n      }\r\n\r\n      // 过滤字段\r\n      const filteredFields = filterFields(fields.value, props);\r\n\r\n      if (!filteredFields.length) {\r\n        debugWarn(prefixCls, 'please pass correct props!');\r\n\r\n        return [];\r\n      }\r\n\r\n      return filteredFields;\r\n    };\r\n\r\n    // 添加验证字段\r\n    const addField: FormContext['addField'] = (field) => {\r\n      fields.value.push(field);\r\n    };\r\n\r\n    // 删除验证字段\r\n    const removeField: FormContext['removeField'] = (field) => {\r\n      if (field.prop) {\r\n        fields.value.splice(fields.value.indexOf(field), 1);\r\n      }\r\n    };\r\n\r\n    // 滚动到指定的字段\r\n    const scrollToField = (prop: FormItemProp) => {\r\n      // 当校验失败时，滚动到第一个错误表单项\r\n      const field = filterFields(fields.value, prop)[0];\r\n\r\n      if (field) {\r\n        field.$el?.scrollIntoView();\r\n      }\r\n    };\r\n\r\n    // 重置该表单项\r\n    const resetFields: FormContext['resetFields'] = (properties = []) => {\r\n      // 表单数据对象\r\n      if (!props.model) {\r\n        debugWarn(prefixCls, 'model is required for resetFields to work.');\r\n        return;\r\n      }\r\n\r\n      // 过滤字段\r\n      filterFields(fields.value, properties).forEach((field) =>\r\n        field.resetField()\r\n      );\r\n    };\r\n\r\n    // 清理某个字段的表单验证信息\r\n    const clearValidate: FormContext['clearValidate'] = (props = []) => {\r\n      // 获取需要清理的item\r\n      filterFields(fields.value, props).forEach((field) =>\r\n        field.clearValidate()\r\n      );\r\n    };\r\n\r\n    // watch\r\n\r\n    // 监听 rules 属性改变后立即触发一次验证\r\n    watch(\r\n      () => props.rules,\r\n      () => {\r\n        if (props.validateOnRuleChange) {\r\n          validate().catch((err) => debugWarn(err));\r\n        }\r\n      }\r\n    );\r\n\r\n    // provide\r\n    provide(\r\n      FormContextKey,\r\n      reactive({\r\n        // props\r\n        ...toRefs(props),\r\n        // emit\r\n        emit,\r\n        // 添加验证字段\r\n        addField,\r\n        // 删除验证字段\r\n        removeField,\r\n        // 清理某个字段的表单验证信息\r\n        clearValidate,\r\n        // 重置该表单项\r\n        resetFields,\r\n        // 验证具体的某个字段\r\n        validateField,\r\n\r\n        // 表单宽度\r\n        ...useFormLabelWidth(),\r\n      })\r\n    );\r\n\r\n    return {\r\n      // computed\r\n      wrapperClasses,\r\n\r\n      // methods\r\n      validate,\r\n      validateField,\r\n      resetFields,\r\n      scrollToField,\r\n      clearValidate,\r\n    };\r\n  },\r\n});\r\n</script>\r\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_withModifiers"],"mappings":";;;;AACc,SAAA,YAAA,IAAE,EAAA,MAAA,EAAc,MAAA,EAAA,MAAA,EAAA,OAAA,QAAA,EAAA;EAAG,OAAAA,SAAA,EAAM,EAAAC,kBAAA,CAAA,MAAA,EAAA;AAAA,IAAA,KAAA,EAAAC,cAAA,CAAA,IAAA,CAAA,cAAA,CAAA;AAAA,IACnC,UAAa,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAC,cAAA,MAAA;AAAA,KAAA,EAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AAAA,GAAA,EAAA;AAAA;;;;;;;"}