From 81048b901c6cbd7a7412f329757d9d340eea353d Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 3 May 2018 19:10:43 +0800 Subject: [PATCH] feat: update vc-form --- antd-tools/getBabelCommonConfig.js | 1 + components/vc-form/demo/input-array.jsx | 66 ++ components/vc-form/demo/styles.js | 11 + components/vc-form/src/createBaseForm.jsx | 822 +++++++++++----------- components/vc-form/src/createDOMForm.jsx | 71 +- components/vc-form/src/createForm.jsx | 44 +- components/vc-form/src/utils.js | 9 +- package.json | 325 ++++----- site/routes.js | 2 +- 9 files changed, 720 insertions(+), 631 deletions(-) create mode 100644 components/vc-form/demo/input-array.jsx create mode 100644 components/vc-form/demo/styles.js diff --git a/antd-tools/getBabelCommonConfig.js b/antd-tools/getBabelCommonConfig.js index b65885420..dec16d11b 100644 --- a/antd-tools/getBabelCommonConfig.js +++ b/antd-tools/getBabelCommonConfig.js @@ -7,6 +7,7 @@ module.exports = function (modules) { require.resolve('babel-plugin-transform-es3-property-literals'), require.resolve('babel-plugin-transform-object-assign'), require.resolve('babel-plugin-transform-object-rest-spread'), + require.resolve('babel-plugin-transform-class-properties'), ] plugins.push([require.resolve('babel-plugin-transform-runtime'), { polyfill: false, diff --git a/components/vc-form/demo/input-array.jsx b/components/vc-form/demo/input-array.jsx new file mode 100644 index 000000000..7a66e6c2c --- /dev/null +++ b/components/vc-form/demo/input-array.jsx @@ -0,0 +1,66 @@ +/* eslint no-console:0 */ + +import { createForm } from '../index' +import { regionStyle } from './styles' + +let uuid = 0 + +const Form = { + props: { + form: Object, + }, + methods: { + remove (k) { + const { form } = this + // can use data-binding to get + let keys = form.getFieldValue('keys') + keys = keys.filter((key) => { + return key !== k + }) + // can use data-binding to set + form.setFieldsValue({ + keys, + }) + }, + add () { + uuid++ + const { form } = this + // can use data-binding to get + let keys = form.getFieldValue('keys') + keys = keys.concat(uuid) + // can use data-binding to set + // important! notify form to detect changes + form.setFieldsValue({ + keys, + }) + }, + submit (e) { + e.preventDefault() + console.log(this.form.getFieldsValue()) + }, + }, + + render () { + const { getFieldProps, getFieldValue } = this.form + getFieldProps('keys', { + initialValue: [], + }) + const inputs = getFieldValue('keys').map((k) => { + return (
+ + delete
) + }) + return (
+ {inputs} +
+ + + +
+
) + }, +} + +export default createForm()(Form) diff --git a/components/vc-form/demo/styles.js b/components/vc-form/demo/styles.js new file mode 100644 index 000000000..e0a5fe5ac --- /dev/null +++ b/components/vc-form/demo/styles.js @@ -0,0 +1,11 @@ +export const regionStyle = { + border: '1px solid red', + marginTop: '10px', + padding: '10px', +} + +export const errorStyle = { + color: 'red', + marginTop: '10px', + padding: '10px', +} diff --git a/components/vc-form/src/createBaseForm.jsx b/components/vc-form/src/createBaseForm.jsx index 78a0a4b4a..23c60d38e 100644 --- a/components/vc-form/src/createBaseForm.jsx +++ b/components/vc-form/src/createBaseForm.jsx @@ -1,10 +1,11 @@ -import createReactClass from 'create-react-class' import AsyncValidator from 'async-validator' import warning from 'warning' import get from 'lodash/get' import set from 'lodash/set' import createFieldsStore from './createFieldsStore' import { cloneElement } from '../../_util/vnode' +import BaseMixin from '../../_util/BaseMixin' +import PropTypes from '../../_util/vue-types' import { argumentContainer, identity, @@ -35,11 +36,14 @@ function createBaseForm (option = {}, mixins = []) { } = option return function decorate (WrappedComponent) { - const Form = createReactClass({ - mixins, - - getInitialState () { - const fields = mapPropsToFields && mapPropsToFields(this.props) + const Form = { + mixins: [BaseMixin, ...mixins], + props: { + hideRequiredMark: PropTypes.bool, + layout: PropTypes.string, + }, + data () { + const fields = mapPropsToFields && mapPropsToFields(this.$props) this.fieldsStore = createFieldsStore(fields || {}) this.instances = {} @@ -56,13 +60,6 @@ function createBaseForm (option = {}, mixins = []) { 'isFieldsTouched', 'isFieldTouched'].forEach(key => { this[key] = (...args) => { - if (process.env.NODE_ENV !== 'production') { - warning( - false, - 'you should not use `ref` on enhanced form, please use `wrappedComponentRef`. ' + - 'See: https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140' - ) - } return this.fieldsStore[key](...args) } }) @@ -71,456 +68,465 @@ function createBaseForm (option = {}, mixins = []) { submitting: false, } }, - - componentWillReceiveProps (nextProps) { - if (mapPropsToFields) { - this.fieldsStore.updateFields(mapPropsToFields(nextProps)) - } + watch: { + '$props': { + handler: function (nextProps) { + if (mapPropsToFields) { + this.fieldsStore.updateFields(mapPropsToFields(nextProps)) + } + }, + deep: true, + }, }, + methods: { + onCollectCommon (name, action, args) { + const fieldMeta = this.fieldsStore.getFieldMeta(name) + if (fieldMeta[action]) { + fieldMeta[action](...args) + } else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { + fieldMeta.originalProps[action](...args) + } + const value = fieldMeta.getValueFromEvent + ? fieldMeta.getValueFromEvent(...args) + : getValueFromEvent(...args) + if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) { + const valuesAll = this.fieldsStore.getAllValues() + const valuesAllSet = {} + valuesAll[name] = value + Object.keys(valuesAll).forEach(key => set(valuesAllSet, key, valuesAll[key])) + onValuesChange(this.props, set({}, name, value), valuesAllSet) + } + const field = this.fieldsStore.getField(name) + return ({ name, field: { ...field, value, touched: true }, fieldMeta }) + }, - onCollectCommon (name, action, args) { - const fieldMeta = this.fieldsStore.getFieldMeta(name) - if (fieldMeta[action]) { - fieldMeta[action](...args) - } else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) { - fieldMeta.originalProps[action](...args) - } - const value = fieldMeta.getValueFromEvent - ? fieldMeta.getValueFromEvent(...args) - : getValueFromEvent(...args) - if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) { - const valuesAll = this.fieldsStore.getAllValues() - const valuesAllSet = {} - valuesAll[name] = value - Object.keys(valuesAll).forEach(key => set(valuesAllSet, key, valuesAll[key])) - onValuesChange(this.props, set({}, name, value), valuesAllSet) - } - const field = this.fieldsStore.getField(name) - return ({ name, field: { ...field, value, touched: true }, fieldMeta }) - }, + onCollect (name_, action, ...args) { + const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args) + const { validate } = fieldMeta + const newField = { + ...field, + dirty: hasRules(validate), + } + this.setFields({ + [name]: newField, + }) + }, - onCollect (name_, action, ...args) { - const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args) - const { validate } = fieldMeta - const newField = { - ...field, - dirty: hasRules(validate), - } - this.setFields({ - [name]: newField, - }) - }, + onCollectValidate (name_, action, ...args) { + const { field, fieldMeta } = this.onCollectCommon(name_, action, args) + const newField = { + ...field, + dirty: true, + } + this.validateFieldsInternal([newField], { + action, + options: { + firstFields: !!fieldMeta.validateFirst, + }, + }) + }, - onCollectValidate (name_, action, ...args) { - const { field, fieldMeta } = this.onCollectCommon(name_, action, args) - const newField = { - ...field, - dirty: true, - } - this.validateFieldsInternal([newField], { - action, - options: { - firstFields: !!fieldMeta.validateFirst, - }, - }) - }, + getCacheBind (name, action, fn) { + if (!this.cachedBind[name]) { + this.cachedBind[name] = {} + } + const cache = this.cachedBind[name] + if (!cache[action]) { + cache[action] = fn.bind(this, name, action) + } + return cache[action] + }, - getCacheBind (name, action, fn) { - if (!this.cachedBind[name]) { - this.cachedBind[name] = {} - } - const cache = this.cachedBind[name] - if (!cache[action]) { - cache[action] = fn.bind(this, name, action) - } - return cache[action] - }, + recoverClearedField (name) { + if (this.clearedFieldMetaCache[name]) { + this.fieldsStore.setFields({ + [name]: this.clearedFieldMetaCache[name].field, + }) + this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta) + delete this.clearedFieldMetaCache[name] + } + }, - recoverClearedField (name) { - if (this.clearedFieldMetaCache[name]) { - this.fieldsStore.setFields({ - [name]: this.clearedFieldMetaCache[name].field, - }) - this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta) - delete this.clearedFieldMetaCache[name] - } - }, + getFieldDecorator (name, fieldOption) { + const { ref, ...restProps } = this.getFieldProps(name, fieldOption) + return (fieldElem) => { + const fieldMeta = this.fieldsStore.getFieldMeta(name) + const originalProps = fieldElem.props + if (process.env.NODE_ENV !== 'production') { + const valuePropName = fieldMeta.valuePropName + warning( + !(valuePropName in originalProps), + `\`getFieldDecorator\` will override \`${valuePropName}\`, ` + + `so please don't set \`${valuePropName}\` directly ` + + `and use \`setFieldsValue\` to set it.` + ) + const defaultValuePropName = + `default${valuePropName[0].toUpperCase()}${valuePropName.slice(1)}` + warning( + !(defaultValuePropName in originalProps), + `\`${defaultValuePropName}\` is invalid ` + + `for \`getFieldDecorator\` will set \`${valuePropName}\`,` + + ` please use \`option.initialValue\` instead.` + ) + } + fieldMeta.originalProps = originalProps + fieldMeta.ref = fieldElem.ref + return cloneElement(fieldElem, { + props: { + ...restProps, + ...this.fieldsStore.getFieldValuePropValue(fieldMeta), + }, + ref, + }) + } + }, - getFieldDecorator (name, fieldOption) { - const props = this.getFieldProps(name, fieldOption) - return (fieldElem) => { - const fieldMeta = this.fieldsStore.getFieldMeta(name) - const originalProps = fieldElem.props + getFieldProps (name, usersFieldOption = {}) { + if (!name) { + throw new Error('Must call `getFieldProps` with valid name string!') + } if (process.env.NODE_ENV !== 'production') { - const valuePropName = fieldMeta.valuePropName warning( - !(valuePropName in originalProps), - `\`getFieldDecorator\` will override \`${valuePropName}\`, ` + - `so please don't set \`${valuePropName}\` directly ` + - `and use \`setFieldsValue\` to set it.` + this.fieldsStore.isValidNestedFieldName(name), + 'One field name cannot be part of another, e.g. `a` and `a.b`.' ) - const defaultValuePropName = - `default${valuePropName[0].toUpperCase()}${valuePropName.slice(1)}` warning( - !(defaultValuePropName in originalProps), - `\`${defaultValuePropName}\` is invalid ` + - `for \`getFieldDecorator\` will set \`${valuePropName}\`,` + - ` please use \`option.initialValue\` instead.` + !('exclusive' in usersFieldOption), + '`option.exclusive` of `getFieldProps`|`getFieldDecorator` had been remove.' ) } - fieldMeta.originalProps = originalProps - fieldMeta.ref = fieldElem.ref - return cloneElement(fieldElem, { - ...props, - ...this.fieldsStore.getFieldValuePropValue(fieldMeta), - }) - } - }, - getFieldProps (name, usersFieldOption = {}) { - if (!name) { - throw new Error('Must call `getFieldProps` with valid name string!') - } - if (process.env.NODE_ENV !== 'production') { - warning( - this.fieldsStore.isValidNestedFieldName(name), - 'One field name cannot be part of another, e.g. `a` and `a.b`.' - ) - warning( - !('exclusive' in usersFieldOption), - '`option.exclusive` of `getFieldProps`|`getFieldDecorator` had been remove.' - ) - } - - delete this.clearedFieldMetaCache[name] - - const fieldOption = { - name, - trigger: DEFAULT_TRIGGER, - valuePropName: 'value', - validate: [], - ...usersFieldOption, - } - - const { - rules, - trigger, - validateTrigger = trigger, - validate, - } = fieldOption - - const fieldMeta = this.fieldsStore.getFieldMeta(name) - if ('initialValue' in fieldOption) { - fieldMeta.initialValue = fieldOption.initialValue - } - - const inputProps = { - ...this.fieldsStore.getFieldValuePropValue(fieldOption), - ref: this.getCacheBind(name, `${name}__ref`, this.saveRef), - } - if (fieldNameProp) { - inputProps[fieldNameProp] = name - } + delete this.clearedFieldMetaCache[name] - const validateRules = normalizeValidateRules(validate, rules, validateTrigger) - const validateTriggers = getValidateTriggers(validateRules) - validateTriggers.forEach((action) => { - if (inputProps[action]) return - inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate) - }) + const fieldOption = { + name, + trigger: DEFAULT_TRIGGER, + valuePropName: 'value', + validate: [], + ...usersFieldOption, + } - // make sure that the value will be collect - if (trigger && validateTriggers.indexOf(trigger) === -1) { - inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect) - } + const { + rules, + trigger, + validateTrigger = trigger, + validate, + } = fieldOption - const meta = { - ...fieldMeta, - ...fieldOption, - validate: validateRules, - } - this.fieldsStore.setFieldMeta(name, meta) - if (fieldMetaProp) { - inputProps[fieldMetaProp] = meta - } + const fieldMeta = this.fieldsStore.getFieldMeta(name) + if ('initialValue' in fieldOption) { + fieldMeta.initialValue = fieldOption.initialValue + } - if (fieldDataProp) { - inputProps[fieldDataProp] = this.fieldsStore.getField(name) - } + const inputProps = { + ...this.fieldsStore.getFieldValuePropValue(fieldOption), + ref: name, + } + const saveRef = this.getCacheBind(name, `${name}__ref`, this.saveRef) + this.$nextTick(() => { + if (this.instances[name] !== this.$refs[name]) { + this.$refs[name].destroyed = () => { + this.$refs[name].destroyed() + // after destroy, delete data + this.clearedFieldMetaCache[name] = { + field: this.fieldsStore.getField(name), + meta: this.fieldsStore.getFieldMeta(name), + } + this.fieldsStore.clearField(name) + delete this.instances[name] + delete this.cachedBind[name] + } + } + saveRef(name, `${name}__ref`, this.$refs[name]) + }) + if (fieldNameProp) { + inputProps[fieldNameProp] = name + } - return inputProps - }, + const validateRules = normalizeValidateRules(validate, rules, validateTrigger) + const validateTriggers = getValidateTriggers(validateRules) + validateTriggers.forEach((action) => { + if (inputProps[action]) return + inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate) + }) - getFieldInstance (name) { - return this.instances[name] - }, + // make sure that the value will be collect + if (trigger && validateTriggers.indexOf(trigger) === -1) { + inputProps[trigger] = this.getCacheBind(name, trigger, this.onCollect) + } - getRules (fieldMeta, action) { - const actionRules = fieldMeta.validate.filter((item) => { - return !action || item.trigger.indexOf(action) >= 0 - }).map((item) => item.rules) - return flattenArray(actionRules) - }, + const meta = { + ...fieldMeta, + ...fieldOption, + validate: validateRules, + } + this.fieldsStore.setFieldMeta(name, meta) + if (fieldMetaProp) { + inputProps[fieldMetaProp] = meta + } - setFields (maybeNestedFields, callback) { - const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields) - this.fieldsStore.setFields(fields) - if (onFieldsChange) { - const changedFields = Object.keys(fields) - .reduce((acc, name) => set(acc, name, this.fieldsStore.getField(name)), {}) - onFieldsChange(this.props, changedFields, this.fieldsStore.getNestedAllFields()) - } - this.forceUpdate(callback) - }, + if (fieldDataProp) { + inputProps[fieldDataProp] = this.fieldsStore.getField(name) + } - resetFields (ns) { - const newFields = this.fieldsStore.resetFields(ns) - if (Object.keys(newFields).length > 0) { - this.setFields(newFields) - } - if (ns) { - const names = Array.isArray(ns) ? ns : [ns] - names.forEach(name => delete this.clearedFieldMetaCache[name]) - } else { - this.clearedFieldMetaCache = {} - } - }, + return inputProps + }, + + getFieldInstance (name) { + return this.instances[name] + }, + + getRules (fieldMeta, action) { + const actionRules = fieldMeta.validate.filter((item) => { + return !action || item.trigger.indexOf(action) >= 0 + }).map((item) => item.rules) + return flattenArray(actionRules) + }, + + setFields (maybeNestedFields, callback) { + const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields) + this.fieldsStore.setFields(fields) + if (onFieldsChange) { + const changedFields = Object.keys(fields) + .reduce((acc, name) => set(acc, name, this.fieldsStore.getField(name)), {}) + onFieldsChange(this.props, changedFields, this.fieldsStore.getNestedAllFields()) + } + this.forceUpdate(callback) + }, - setFieldsValue (changedValues, callback) { - const { fieldsMeta } = this.fieldsStore - const values = this.fieldsStore.flattenRegisteredFields(changedValues) - const newFields = Object.keys(values).reduce((acc, name) => { - const isRegistered = fieldsMeta[name] - if (process.env.NODE_ENV !== 'production') { - warning( - isRegistered, - 'Cannot use `setFieldsValue` until ' + - 'you use `getFieldDecorator` or `getFieldProps` to register it.' - ) + resetFields (ns) { + const newFields = this.fieldsStore.resetFields(ns) + if (Object.keys(newFields).length > 0) { + this.setFields(newFields) } - if (isRegistered) { - const value = values[name] - acc[name] = { - value, - } + if (ns) { + const names = Array.isArray(ns) ? ns : [ns] + names.forEach(name => delete this.clearedFieldMetaCache[name]) + } else { + this.clearedFieldMetaCache = {} } - return acc - }, {}) - this.setFields(newFields, callback) - if (onValuesChange) { - const allValues = this.fieldsStore.getAllValues() - onValuesChange(this.props, changedValues, allValues) - } - }, + }, - saveRef (name, _, component) { - if (!component) { - // after destroy, delete data - this.clearedFieldMetaCache[name] = { - field: this.fieldsStore.getField(name), - meta: this.fieldsStore.getFieldMeta(name), + setFieldsValue (changedValues, callback) { + const { fieldsMeta } = this.fieldsStore + const values = this.fieldsStore.flattenRegisteredFields(changedValues) + const newFields = Object.keys(values).reduce((acc, name) => { + const isRegistered = fieldsMeta[name] + if (process.env.NODE_ENV !== 'production') { + warning( + isRegistered, + 'Cannot use `setFieldsValue` until ' + + 'you use `getFieldDecorator` or `getFieldProps` to register it.' + ) + } + if (isRegistered) { + const value = values[name] + acc[name] = { + value, + } + } + return acc + }, {}) + this.setFields(newFields, callback) + if (onValuesChange) { + const allValues = this.fieldsStore.getAllValues() + onValuesChange(this.props, changedValues, allValues) } - this.fieldsStore.clearField(name) - delete this.instances[name] - delete this.cachedBind[name] - return - } - this.recoverClearedField(name) - const fieldMeta = this.fieldsStore.getFieldMeta(name) - if (fieldMeta) { - const ref = fieldMeta.ref - if (ref) { - if (typeof ref === 'string') { - throw new Error(`can not set ref string for ${name}`) + }, + + saveRef (name, _, component) { + this.recoverClearedField(name) + const fieldMeta = this.fieldsStore.getFieldMeta(name) + if (fieldMeta) { + const ref = fieldMeta.ref + if (ref) { + if (typeof ref === 'string') { + throw new Error(`can not set ref string for ${name}`) + } + ref(component) } - ref(component) } - } - this.instances[name] = component - }, + this.instances[name] = component + }, - validateFieldsInternal (fields, { - fieldNames, - action, - options = {}, - }, callback) { - const allRules = {} - const allValues = {} - const allFields = {} - const alreadyErrors = {} - fields.forEach((field) => { - const name = field.name - if (options.force !== true && field.dirty === false) { - if (field.errors) { - set(alreadyErrors, name, { errors: field.errors }) + validateFieldsInternal (fields, { + fieldNames, + action, + options = {}, + }, callback) { + const allRules = {} + const allValues = {} + const allFields = {} + const alreadyErrors = {} + fields.forEach((field) => { + const name = field.name + if (options.force !== true && field.dirty === false) { + if (field.errors) { + set(alreadyErrors, name, { errors: field.errors }) + } + return } + const fieldMeta = this.fieldsStore.getFieldMeta(name) + const newField = { + ...field, + } + newField.errors = undefined + newField.validating = true + newField.dirty = true + allRules[name] = this.getRules(fieldMeta, action) + allValues[name] = newField.value + allFields[name] = newField + }) + this.setFields(allFields) + // in case normalize + Object.keys(allValues).forEach((f) => { + allValues[f] = this.fieldsStore.getFieldValue(f) + }) + if (callback && isEmptyObject(allFields)) { + callback(isEmptyObject(alreadyErrors) ? null : alreadyErrors, + this.fieldsStore.getFieldsValue(fieldNames)) return } - const fieldMeta = this.fieldsStore.getFieldMeta(name) - const newField = { - ...field, + const validator = new AsyncValidator(allRules) + if (validateMessages) { + validator.messages(validateMessages) } - newField.errors = undefined - newField.validating = true - newField.dirty = true - allRules[name] = this.getRules(fieldMeta, action) - allValues[name] = newField.value - allFields[name] = newField - }) - this.setFields(allFields) - // in case normalize - Object.keys(allValues).forEach((f) => { - allValues[f] = this.fieldsStore.getFieldValue(f) - }) - if (callback && isEmptyObject(allFields)) { - callback(isEmptyObject(alreadyErrors) ? null : alreadyErrors, - this.fieldsStore.getFieldsValue(fieldNames)) - return - } - const validator = new AsyncValidator(allRules) - if (validateMessages) { - validator.messages(validateMessages) - } - validator.validate(allValues, options, (errors) => { - const errorsGroup = { - ...alreadyErrors, - } - if (errors && errors.length) { - errors.forEach((e) => { - const fieldName = e.field - const field = get(errorsGroup, fieldName) - if (typeof field !== 'object' || Array.isArray(field)) { - set(errorsGroup, fieldName, { errors: [] }) + validator.validate(allValues, options, (errors) => { + const errorsGroup = { + ...alreadyErrors, + } + if (errors && errors.length) { + errors.forEach((e) => { + const fieldName = e.field + const field = get(errorsGroup, fieldName) + if (typeof field !== 'object' || Array.isArray(field)) { + set(errorsGroup, fieldName, { errors: [] }) + } + const fieldErrors = get(errorsGroup, fieldName.concat('.errors')) + fieldErrors.push(e) + }) + } + const expired = [] + const nowAllFields = {} + Object.keys(allRules).forEach((name) => { + const fieldErrors = get(errorsGroup, name) + const nowField = this.fieldsStore.getField(name) + // avoid concurrency problems + if (nowField.value !== allValues[name]) { + expired.push({ + name, + }) + } else { + nowField.errors = fieldErrors && fieldErrors.errors + nowField.value = allValues[name] + nowField.validating = false + nowField.dirty = false + nowAllFields[name] = nowField } - const fieldErrors = get(errorsGroup, fieldName.concat('.errors')) - fieldErrors.push(e) }) - } - const expired = [] - const nowAllFields = {} - Object.keys(allRules).forEach((name) => { - const fieldErrors = get(errorsGroup, name) - const nowField = this.fieldsStore.getField(name) - // avoid concurrency problems - if (nowField.value !== allValues[name]) { - expired.push({ - name, - }) - } else { - nowField.errors = fieldErrors && fieldErrors.errors - nowField.value = allValues[name] - nowField.validating = false - nowField.dirty = false - nowAllFields[name] = nowField + this.setFields(nowAllFields) + if (callback) { + if (expired.length) { + expired.forEach(({ name }) => { + const fieldErrors = [{ + message: `${name} need to revalidate`, + field: name, + }] + set(errorsGroup, name, { + expired: true, + errors: fieldErrors, + }) + }) + } + + callback(isEmptyObject(errorsGroup) ? null : errorsGroup, + this.fieldsStore.getFieldsValue(fieldNames)) } }) - this.setFields(nowAllFields) - if (callback) { - if (expired.length) { - expired.forEach(({ name }) => { - const fieldErrors = [{ - message: `${name} need to revalidate`, - field: name, - }] - set(errorsGroup, name, { - expired: true, - errors: fieldErrors, - }) - }) + }, + + validateFields (ns, opt, cb) { + const { names, callback, options } = getParams(ns, opt, cb) + const fieldNames = names + ? this.fieldsStore.getValidFieldsFullName(names) + : this.fieldsStore.getValidFieldsName() + const fields = fieldNames + .filter(name => { + const fieldMeta = this.fieldsStore.getFieldMeta(name) + return hasRules(fieldMeta.validate) + }).map((name) => { + const field = this.fieldsStore.getField(name) + field.value = this.fieldsStore.getFieldValue(name) + return field + }) + if (!fields.length) { + if (callback) { + callback(null, this.fieldsStore.getFieldsValue(fieldNames)) } - - callback(isEmptyObject(errorsGroup) ? null : errorsGroup, - this.fieldsStore.getFieldsValue(fieldNames)) + return } - }) - }, - - validateFields (ns, opt, cb) { - const { names, callback, options } = getParams(ns, opt, cb) - const fieldNames = names - ? this.fieldsStore.getValidFieldsFullName(names) - : this.fieldsStore.getValidFieldsName() - const fields = fieldNames - .filter(name => { - const fieldMeta = this.fieldsStore.getFieldMeta(name) - return hasRules(fieldMeta.validate) - }).map((name) => { - const field = this.fieldsStore.getField(name) - field.value = this.fieldsStore.getFieldValue(name) - return field - }) - if (!fields.length) { - if (callback) { - callback(null, this.fieldsStore.getFieldsValue(fieldNames)) + if (!('firstFields' in options)) { + options.firstFields = fieldNames.filter((name) => { + const fieldMeta = this.fieldsStore.getFieldMeta(name) + return !!fieldMeta.validateFirst + }) } - return - } - if (!('firstFields' in options)) { - options.firstFields = fieldNames.filter((name) => { - const fieldMeta = this.fieldsStore.getFieldMeta(name) - return !!fieldMeta.validateFirst - }) - } - this.validateFieldsInternal(fields, { - fieldNames, - options, - }, callback) - }, + this.validateFieldsInternal(fields, { + fieldNames, + options, + }, callback) + }, - isSubmitting () { - if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { - warning( - false, - '`isSubmitting` is deprecated. ' + - 'Actually, it\'s more convenient to handle submitting status by yourself.' - ) - } - return this.state.submitting - }, + isSubmitting () { + if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { + warning( + false, + '`isSubmitting` is deprecated. ' + + 'Actually, it\'s more convenient to handle submitting status by yourself.' + ) + } + return this.submitting + }, - submit (callback) { - if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { - warning( - false, - '`submit` is deprecated.' + - 'Actually, it\'s more convenient to handle submitting status by yourself.' - ) - } - const fn = () => { + submit (callback) { + if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { + warning( + false, + '`submit` is deprecated.' + + 'Actually, it\'s more convenient to handle submitting status by yourself.' + ) + } + const fn = () => { + this.setState({ + submitting: false, + }) + } this.setState({ - submitting: false, + submitting: true, }) - } - this.setState({ - submitting: true, - }) - callback(fn) + callback(fn) + }, }, render () { - const { wrappedComponentRef, ...restProps } = this.props + const { $props, $listeners } = this const formProps = { [formPropName]: this.getForm(), } + + const wrappedComponentProps = { + props: mapProps.call(this, { + ...formProps, + ...$props, + }), + on: $listeners, + } if (withRef) { - if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { - warning( - false, - '`withRef` is deprecated, please use `wrappedComponentRef` instead. ' + - 'See: https://github.com/react-component/form#note-use-wrappedcomponentref-instead-of-withref-after-rc-form140' - ) - } - formProps.ref = 'wrappedComponent' - } else if (wrappedComponentRef) { - formProps.ref = wrappedComponentRef + wrappedComponentProps.ref = 'wrappedComponent' } - const props = mapProps.call(this, { - ...formProps, - ...restProps, - }) - return + return }, - }) + } return argumentContainer(Form, WrappedComponent) } diff --git a/components/vc-form/src/createDOMForm.jsx b/components/vc-form/src/createDOMForm.jsx index 90e514ab8..9fdc5dc12 100644 --- a/components/vc-form/src/createDOMForm.jsx +++ b/components/vc-form/src/createDOMForm.jsx @@ -49,50 +49,53 @@ function getScrollableContainer (n) { } const mixin = { - getForm () { - return { - ...formMixin.getForm.call(this), - validateFieldsAndScroll: this.validateFieldsAndScroll, - } - }, + methods: { + getForm () { + return { + ...formMixin.getForm.call(this), + validateFieldsAndScroll: this.validateFieldsAndScroll, + } + }, - validateFieldsAndScroll (ns, opt, cb) { - const { names, callback, options } = getParams(ns, opt, cb) + validateFieldsAndScroll (ns, opt, cb) { + const { names, callback, options } = getParams(ns, opt, cb) - const newCb = (error, values) => { - if (error) { - const validNames = this.fieldsStore.getValidFieldsName() - let firstNode - let firstTop - for (const name of validNames) { - if (has(error, name)) { - const instance = this.getFieldInstance(name) - if (instance) { - const node = instance.$el - const top = node.getBoundingClientRect().top - if (firstTop === undefined || firstTop > top) { - firstTop = top - firstNode = node + const newCb = (error, values) => { + if (error) { + const validNames = this.fieldsStore.getValidFieldsName() + let firstNode + let firstTop + for (const name of validNames) { + if (has(error, name)) { + const instance = this.getFieldInstance(name) + if (instance) { + const node = instance.$el + const top = node.getBoundingClientRect().top + if (firstTop === undefined || firstTop > top) { + firstTop = top + firstNode = node + } } } } + if (firstNode) { + const c = options.container || getScrollableContainer(firstNode) + scrollIntoView(firstNode, c, { + onlyScrollIfNeeded: true, + ...options.scroll, + }) + } } - if (firstNode) { - const c = options.container || getScrollableContainer(firstNode) - scrollIntoView(firstNode, c, { - onlyScrollIfNeeded: true, - ...options.scroll, - }) - } - } - if (typeof callback === 'function') { - callback(error, values) + if (typeof callback === 'function') { + callback(error, values) + } } - } - return this.validateFields(names, options, newCb) + return this.validateFields(names, options, newCb) + }, }, + } function createDOMForm (option) { diff --git a/components/vc-form/src/createForm.jsx b/components/vc-form/src/createForm.jsx index 4667bb451..82eb056ec 100644 --- a/components/vc-form/src/createForm.jsx +++ b/components/vc-form/src/createForm.jsx @@ -1,27 +1,29 @@ import createBaseForm from './createBaseForm' export const mixin = { - getForm () { - return { - getFieldsValue: this.fieldsStore.getFieldsValue, - getFieldValue: this.fieldsStore.getFieldValue, - getFieldInstance: this.getFieldInstance, - setFieldsValue: this.setFieldsValue, - setFields: this.setFields, - setFieldsInitialValue: this.fieldsStore.setFieldsInitialValue, - getFieldDecorator: this.getFieldDecorator, - getFieldProps: this.getFieldProps, - getFieldsError: this.fieldsStore.getFieldsError, - getFieldError: this.fieldsStore.getFieldError, - isFieldValidating: this.fieldsStore.isFieldValidating, - isFieldsValidating: this.fieldsStore.isFieldsValidating, - isFieldsTouched: this.fieldsStore.isFieldsTouched, - isFieldTouched: this.fieldsStore.isFieldTouched, - isSubmitting: this.isSubmitting, - submit: this.submit, - validateFields: this.validateFields, - resetFields: this.resetFields, - } + methods: { + getForm () { + return { + getFieldsValue: this.fieldsStore.getFieldsValue, + getFieldValue: this.fieldsStore.getFieldValue, + getFieldInstance: this.getFieldInstance, + setFieldsValue: this.setFieldsValue, + setFields: this.setFields, + setFieldsInitialValue: this.fieldsStore.setFieldsInitialValue, + getFieldDecorator: this.getFieldDecorator, + getFieldProps: this.getFieldProps, + getFieldsError: this.fieldsStore.getFieldsError, + getFieldError: this.fieldsStore.getFieldError, + isFieldValidating: this.fieldsStore.isFieldValidating, + isFieldsValidating: this.fieldsStore.isFieldsValidating, + isFieldsTouched: this.fieldsStore.isFieldsTouched, + isFieldTouched: this.fieldsStore.isFieldTouched, + isSubmitting: this.isSubmitting, + submit: this.submit, + validateFields: this.validateFields, + resetFields: this.resetFields, + } + }, }, } diff --git a/components/vc-form/src/utils.js b/components/vc-form/src/utils.js index ca3ef27b5..7819380bc 100644 --- a/components/vc-form/src/utils.js +++ b/components/vc-form/src/utils.js @@ -1,14 +1,13 @@ -import hoistStatics from 'hoist-non-react-statics' - function getDisplayName (WrappedComponent) { - return WrappedComponent.displayName || WrappedComponent.name || 'WrappedComponent' + return WrappedComponent.name || 'WrappedComponent' } export function argumentContainer (Container, WrappedComponent) { /* eslint no-param-reassign:0 */ - Container.displayName = `Form(${getDisplayName(WrappedComponent)})` + Container.name = `Form_${getDisplayName(WrappedComponent)}` Container.WrappedComponent = WrappedComponent - return hoistStatics(Container, WrappedComponent) + Container.methods = { ...Container.methods, ...WrappedComponent.methods } + return Container } export function identity (obj) { diff --git a/package.json b/package.json index f1d73f7f6..404d4bed9 100644 --- a/package.json +++ b/package.json @@ -1,164 +1,165 @@ { - "name": "vue-antd-ui", - "version": "0.4.3", - "title": "Ant Design Vue", - "description": "An enterprise-class UI design language and Vue-based implementation", - "keywords": [ - "ant", - "design", - "antd", - "vue", - "vueComponent", - "component", - "components", - "ui", - "framework", - "frontend" - ], - "main": "dist/antd.min.js", - "files": [ - "dist", - "lib", - "es" - ], - "scripts": { - "start": "NODE_ENV=development ./node_modules/.bin/webpack-dev-server --open --hot", - "test": "karma start test/karma.conf.js --single-run", - "site": "node scripts/run.js site-dist", - "copy": "node scripts/run.js copy-html", - "compile": "node antd-tools/cli/run.js compile", - "pub": "node antd-tools/cli/run.js pub", - "prepublish": "node antd-tools/cli/run.js guard", - "dist": "node antd-tools/cli/run.js dist", - "lint": "eslint -c ./.eslintrc --fix --ext .jsx,.js,.vue ./components", - "lint:style": "stylelint \"./examples/**/*.less\" --fix --syntax less", - "commitmsg": "validate-commit-msg", - "cm": "git-cz" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/vueComponent/ant-design.git" - }, - "license": "MIT", - "bugs": { - "url": "https://github.com/vueComponent/ant-design/issues" - }, - "homepage": "https://github.com/vueComponent/ant-design", - "pre-commit": [ - "lint:style", - "lint" - ], - "devDependencies": { - "@octokit/rest": "^15.2.6", - "autoprefixer": "^8.1.0", - "babel-cli": "^6.26.0", - "babel-core": "^6.26.0", - "babel-eslint": "^8.0.1", - "babel-helper-vue-jsx-merge-props": "^2.0.3", - "babel-loader": "^7.1.2", - "babel-plugin-add-module-exports": "^0.2.1", - "babel-plugin-import": "^1.1.1", - "babel-plugin-istanbul": "^4.1.1", - "babel-plugin-syntax-dynamic-import": "^6.18.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "babel-plugin-transform-decorators": "^6.24.1", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-es3-member-expression-literals": "^6.22.0", - "babel-plugin-transform-es3-property-literals": "^6.22.0", - "babel-plugin-transform-object-assign": "^6.22.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0", - "babel-plugin-transform-runtime": "~6.23.0", - "babel-plugin-transform-vue-jsx": "^3.7.0", - "babel-polyfill": "^6.26.0", - "babel-preset-env": "^1.6.1", - "case-sensitive-paths-webpack-plugin": "^2.1.2", - "chai": "^4.1.2", - "chalk": "^2.3.2", - "cheerio": "^1.0.0-rc.2", - "colorful": "^2.1.0", - "commander": "^2.15.0", - "commitizen": "^2.9.6", - "css-loader": "^0.28.7", - "deep-assign": "^2.0.0", - "eslint": "^4.7.2", - "eslint-plugin-vue": "^3.13.0", - "eslint-plugin-html": "^3.2.2", - "eslint-plugin-vue-libs": "^1.2.1", - "extract-text-webpack-plugin": "^3.0.2", - "fetch-jsonp": "^1.1.3", - "gulp": "^3.9.1", - "gulp-babel": "^7.0.0", - "gulp-strip-code": "^0.1.4", - "highlight.js": "^9.12.0", - "html-webpack-plugin": "^2.30.1", - "husky": "^0.14.3", - "istanbul-instrumenter-loader": "^3.0.0", - "jsonp": "^0.2.1", - "karma": "^1.4.1", - "karma-coverage": "^1.1.1", - "karma-coverage-istanbul-reporter": "^1.3.0", - "karma-mocha": "^1.3.0", - "karma-phantomjs-launcher": "^1.0.2", - "karma-phantomjs-shim": "^1.4.0", - "karma-sinon-chai": "^1.3.1", - "karma-sourcemap-loader": "^0.3.7", - "karma-spec-reporter": "0.0.31", - "karma-webpack": "^2.0.2", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "less-plugin-npm-import": "^2.1.0", - "markdown-it": "^8.4.0", - "markdown-it-anchor": "^4.0.0", - "marked": "^0.3.7", - "merge2": "^1.2.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "mocha": "^3.2.0", - "postcss": "^6.0.20", - "postcss-loader": "^2.1.2", - "pre-commit": "^1.2.2", - "querystring": "^0.2.0", - "reqwest": "^2.0.5", - "rimraf": "^2.6.2", - "rucksack-css": "^1.0.2", - "selenium-server": "^3.0.1", - "semver": "^5.3.0", - "sinon": "^4.0.2", - "sinon-chai": "^2.8.0", - "style-loader": "^0.18.2", - "stylelint": "^8.1.1", - "stylelint-config-standard": "^17.0.0", - "through2": "^2.0.3", - "validate-commit-msg": "^2.14.0", - "vue": "^2.5.15", - "vue-antd-md-loader": "^1.0.3", - "vue-clipboard2": "0.0.8", - "vue-loader": "^13.0.5", - "vue-router": "^3.0.1", - "vue-template-compiler": "^2.5.15", - "webpack": "^3.6.0", - "webpack-chunk-hash": "^0.5.0", - "webpack-dev-server": "^2.8.2", - "webpack-merge": "^4.1.1" - }, - "dependencies": { - "add-dom-event-listener": "^1.0.2", - "array-tree-filter": "^2.1.0", - "babel-runtime": "6.x", - "babel-helper-vue-jsx-merge-props": "^2.0.3", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "css-animation": "^1.4.1", - "dom-align": "^1.6.7", - "dom-closest": "^0.2.0", - "dom-scroll-into-view": "^1.2.1", - "enquire.js": "^2.1.6", - "is-negative-zero": "^2.0.0", - "lodash": "^4.17.5", - "moment": "^2.21.0", - "omit.js": "^1.0.0", - "shallow-equal": "^1.0.0", - "shallowequal": "^1.0.2", - "warning": "^3.0.0" - } + "name": "vue-antd-ui", + "version": "0.4.3", + "title": "Ant Design Vue", + "description": "An enterprise-class UI design language and Vue-based implementation", + "keywords": [ + "ant", + "design", + "antd", + "vue", + "vueComponent", + "component", + "components", + "ui", + "framework", + "frontend" + ], + "main": "dist/antd.min.js", + "files": [ + "dist", + "lib", + "es" + ], + "scripts": { + "start": "NODE_ENV=development ./node_modules/.bin/webpack-dev-server --open --hot", + "test": "karma start test/karma.conf.js --single-run", + "site": "node scripts/run.js site-dist", + "copy": "node scripts/run.js copy-html", + "compile": "node antd-tools/cli/run.js compile", + "pub": "node antd-tools/cli/run.js pub", + "prepublish": "node antd-tools/cli/run.js guard", + "dist": "node antd-tools/cli/run.js dist", + "lint": "eslint -c ./.eslintrc --fix --ext .jsx,.js,.vue ./components", + "lint:style": "stylelint \"./examples/**/*.less\" --fix --syntax less", + "commitmsg": "validate-commit-msg", + "cm": "git-cz" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vueComponent/ant-design.git" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/vueComponent/ant-design/issues" + }, + "homepage": "https://github.com/vueComponent/ant-design", + "pre-commit": [ + "lint:style", + "lint" + ], + "devDependencies": { + "@octokit/rest": "^15.2.6", + "autoprefixer": "^8.1.0", + "babel-cli": "^6.26.0", + "babel-core": "^6.26.0", + "babel-eslint": "^8.0.1", + "babel-helper-vue-jsx-merge-props": "^2.0.3", + "babel-loader": "^7.1.2", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-plugin-import": "^1.1.1", + "babel-plugin-istanbul": "^4.1.1", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-plugin-transform-decorators": "^6.24.1", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-es3-member-expression-literals": "^6.22.0", + "babel-plugin-transform-es3-property-literals": "^6.22.0", + "babel-plugin-transform-object-assign": "^6.22.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-plugin-transform-runtime": "~6.23.0", + "babel-plugin-transform-vue-jsx": "^3.7.0", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.6.1", + "case-sensitive-paths-webpack-plugin": "^2.1.2", + "chai": "^4.1.2", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "colorful": "^2.1.0", + "commander": "^2.15.0", + "commitizen": "^2.9.6", + "css-loader": "^0.28.7", + "deep-assign": "^2.0.0", + "eslint": "^4.7.2", + "eslint-plugin-vue": "^3.13.0", + "eslint-plugin-html": "^3.2.2", + "eslint-plugin-vue-libs": "^1.2.1", + "extract-text-webpack-plugin": "^3.0.2", + "fetch-jsonp": "^1.1.3", + "gulp": "^3.9.1", + "gulp-babel": "^7.0.0", + "gulp-strip-code": "^0.1.4", + "highlight.js": "^9.12.0", + "html-webpack-plugin": "^2.30.1", + "husky": "^0.14.3", + "istanbul-instrumenter-loader": "^3.0.0", + "jsonp": "^0.2.1", + "karma": "^1.4.1", + "karma-coverage": "^1.1.1", + "karma-coverage-istanbul-reporter": "^1.3.0", + "karma-mocha": "^1.3.0", + "karma-phantomjs-launcher": "^1.0.2", + "karma-phantomjs-shim": "^1.4.0", + "karma-sinon-chai": "^1.3.1", + "karma-sourcemap-loader": "^0.3.7", + "karma-spec-reporter": "0.0.31", + "karma-webpack": "^2.0.2", + "less": "^2.7.2", + "less-loader": "^4.0.5", + "less-plugin-npm-import": "^2.1.0", + "markdown-it": "^8.4.0", + "markdown-it-anchor": "^4.0.0", + "marked": "^0.3.7", + "merge2": "^1.2.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "mocha": "^3.2.0", + "postcss": "^6.0.20", + "postcss-loader": "^2.1.2", + "pre-commit": "^1.2.2", + "querystring": "^0.2.0", + "reqwest": "^2.0.5", + "rimraf": "^2.6.2", + "rucksack-css": "^1.0.2", + "selenium-server": "^3.0.1", + "semver": "^5.3.0", + "sinon": "^4.0.2", + "sinon-chai": "^2.8.0", + "style-loader": "^0.18.2", + "stylelint": "^8.1.1", + "stylelint-config-standard": "^17.0.0", + "through2": "^2.0.3", + "validate-commit-msg": "^2.14.0", + "vue": "^2.5.15", + "vue-antd-md-loader": "^1.0.3", + "vue-clipboard2": "0.0.8", + "vue-loader": "^13.0.5", + "vue-router": "^3.0.1", + "vue-template-compiler": "^2.5.15", + "webpack": "^3.6.0", + "webpack-chunk-hash": "^0.5.0", + "webpack-dev-server": "^2.8.2", + "webpack-merge": "^4.1.1" + }, + "dependencies": { + "add-dom-event-listener": "^1.0.2", + "array-tree-filter": "^2.1.0", + "async-validator": "^1.8.2", + "babel-helper-vue-jsx-merge-props": "^2.0.3", + "babel-runtime": "6.x", + "classnames": "^2.2.5", + "component-classes": "^1.2.6", + "css-animation": "^1.4.1", + "dom-align": "^1.6.7", + "dom-closest": "^0.2.0", + "dom-scroll-into-view": "^1.2.1", + "enquire.js": "^2.1.6", + "is-negative-zero": "^2.0.0", + "lodash": "^4.17.5", + "moment": "^2.21.0", + "omit.js": "^1.0.0", + "shallow-equal": "^1.0.0", + "shallowequal": "^1.0.2", + "warning": "^3.0.0" + } } diff --git a/site/routes.js b/site/routes.js index 6aa0a45f2..adae1220a 100644 --- a/site/routes.js +++ b/site/routes.js @@ -4,7 +4,7 @@ import Iframe from './components/iframe.vue' const AsyncTestComp = () => { const d = window.location.hash.replace('#', '') return { - component: import(`../components/menu/demo/${d}`), + component: import(`../components/vc-form/demo/${d}`), } }