From be98a04520c8c150f4896d20ab88f7496c73f987 Mon Sep 17 00:00:00 2001
From: tangjinzhou <415800467@qq.com>
Date: Fri, 4 May 2018 16:02:31 +0800
Subject: [PATCH] feat: add vc-form demo
---
components/_util/ContainerRender.jsx | 2 +
components/_util/antRefDirective.js | 12 +
components/modal/confirm.js | 4 +
components/trigger/Trigger.jsx | 2 +
components/vc-form/demo/modal.js | 84 +++++++
components/vc-form/demo/nested-field.js | 194 +++++++++++++++
components/vc-form/demo/normalize.js | 151 ++++++++++++
components/vc-form/demo/overview.js | 259 ++++++++++++++++++++
components/vc-form/src/createBaseForm.jsx | 15 +-
components/vc-form/src/createDOMForm.jsx | 4 +-
components/vc-form/src/index.jsx | 11 +-
components/vc-form/src/utils.js | 2 +-
components/vc-notification/Notification.jsx | 3 +
13 files changed, 726 insertions(+), 17 deletions(-)
create mode 100644 components/_util/antRefDirective.js
create mode 100644 components/vc-form/demo/modal.js
create mode 100644 components/vc-form/demo/nested-field.js
create mode 100644 components/vc-form/demo/normalize.js
create mode 100644 components/vc-form/demo/overview.js
diff --git a/components/_util/ContainerRender.jsx b/components/_util/ContainerRender.jsx
index 9540e6db4..523922b95 100644
--- a/components/_util/ContainerRender.jsx
+++ b/components/_util/ContainerRender.jsx
@@ -1,6 +1,8 @@
import Vue from 'vue'
import PropTypes from './vue-types'
+import antRefDirective from './antRefDirective'
+Vue.use(antRefDirective)
export default {
props: {
diff --git a/components/_util/antRefDirective.js b/components/_util/antRefDirective.js
new file mode 100644
index 000000000..c7d0afde4
--- /dev/null
+++ b/components/_util/antRefDirective.js
@@ -0,0 +1,12 @@
+export default {
+ install: (Vue, options) => {
+ Vue.directive('ant-ref', {
+ bind: function (el, binding, vnode) {
+ binding.value(vnode)
+ },
+ unbind: function (el, binding, vnode) {
+ binding.value()
+ },
+ })
+ },
+}
diff --git a/components/modal/confirm.js b/components/modal/confirm.js
index 69ac8082d..fc2f7913a 100644
--- a/components/modal/confirm.js
+++ b/components/modal/confirm.js
@@ -1,5 +1,9 @@
import Vue from 'vue'
import ConfirmDialog from './ConfirmDialog'
+
+import antRefDirective from '../_util/antRefDirective'
+Vue.use(antRefDirective)
+
export default function confirm (config) {
const div = document.createElement('div')
const el = document.createElement('div')
diff --git a/components/trigger/Trigger.jsx b/components/trigger/Trigger.jsx
index 547411e7f..731b27425 100644
--- a/components/trigger/Trigger.jsx
+++ b/components/trigger/Trigger.jsx
@@ -10,6 +10,8 @@ import Popup from './Popup'
import { getAlignFromPlacement, getPopupClassNameFromAlign, noop } from './utils'
import BaseMixin from '../_util/BaseMixin'
import { cloneElement } from '../_util/vnode'
+import antRefDirective from '../_util/antRefDirective'
+Vue.use(antRefDirective)
function returnEmptyString () {
return ''
diff --git a/components/vc-form/demo/modal.js b/components/vc-form/demo/modal.js
new file mode 100644
index 000000000..a9d127886
--- /dev/null
+++ b/components/vc-form/demo/modal.js
@@ -0,0 +1,84 @@
+/* eslint react/no-multi-comp:0, no-console:0 */
+
+import BaseMixin from '../../_util/BaseMixin'
+import createDOMForm from '../src/createDOMForm'
+import { Modal } from 'antd'
+import { regionStyle, errorStyle } from './styles'
+
+const Form = {
+ mixins: [BaseMixin],
+ props: {
+ form: Object,
+ },
+
+ data () {
+ return {
+ visible: false,
+ }
+ },
+ methods: {
+ onSubmit (e) {
+ e.preventDefault()
+ this.form.validateFieldsAndScroll((error, values) => {
+ if (!error) {
+ console.log('ok', values)
+ } else {
+ console.log('error', error, values)
+ }
+ })
+ },
+
+ onCancel () {
+ this.setState({
+ visible: false,
+ })
+ },
+
+ open () {
+ this.setState({
+ visible: true,
+ })
+ },
+ },
+
+ render () {
+ const { getFieldProps, getFieldError } = this.form
+ return (
+
modal
+
+
+
+
+
+
+
)
+ },
+}
+
+export default createDOMForm()(Form)
diff --git a/components/vc-form/demo/nested-field.js b/components/vc-form/demo/nested-field.js
new file mode 100644
index 000000000..a04bdb271
--- /dev/null
+++ b/components/vc-form/demo/nested-field.js
@@ -0,0 +1,194 @@
+/* eslint react/no-multi-comp:0, no-console:0 */
+
+import createForm from '../src/createDOMForm'
+
+const Form = {
+ props: {
+ form: Object,
+ },
+ methods: {
+ onSubmit (e) {
+ e.preventDefault()
+ console.log('Values of member[0].name.firstname and a[0][1].b.c[0]')
+ console.log(this.form.getFieldsValue(['member[0].name.firstname', 'a[0][1].b.c[0]']))
+ console.log('Values of all fields')
+ console.log(this.form.getFieldsValue())
+
+ this.form.validateFieldsAndScroll((error, values) => {
+ if (!error) {
+ console.log('ok', values)
+ } else {
+ console.log('error', error, values)
+ }
+ })
+ },
+
+ onChange (e) {
+ console.log(e.target.value)
+ },
+
+ setField () {
+ this.form.setFieldsValue({
+ member: [
+ {
+ name: {
+ firstname: 'm1 first',
+ lastname: 'm1 last',
+ },
+ },
+ {
+ name: {
+ firstname: 'm2 first',
+ lastname: 'm2 last',
+ },
+ },
+ ],
+ a: [
+ [undefined, {
+ b: {
+ c: ['Value of a[0][1].b.c[0]'],
+ },
+ }],
+ ],
+ w: {
+ x: {
+ y: {
+ z: ['Value of w.x.y.z[0]'],
+ },
+ },
+ },
+ })
+ },
+
+ resetFields () {
+ console.log('reset')
+ this.form.resetFields()
+ },
+ },
+
+ render () {
+ const { getFieldDecorator, getFieldError } = this.form
+
+ return (
+
+ )
+ },
+}
+
+const NewForm = createForm({
+ onFieldsChange (_, changedFields, allFields) {
+ console.log('onFieldsChange: ', changedFields, allFields)
+ },
+ onValuesChange (_, changedValues, allValues) {
+ console.log('onValuesChange: ', changedValues, allValues)
+ },
+})(Form)
+
+export default {
+ render () {
+ return (
+
setFieldsValue
+
+ )
+ },
+}
diff --git a/components/vc-form/demo/normalize.js b/components/vc-form/demo/normalize.js
new file mode 100644
index 000000000..4de51e37f
--- /dev/null
+++ b/components/vc-form/demo/normalize.js
@@ -0,0 +1,151 @@
+/* eslint react/no-multi-comp:0, no-console:0 */
+
+import { createForm } from '../index'
+import { regionStyle, errorStyle } from './styles'
+
+const CustomInput = {
+ props: {
+ form: Object,
+ },
+ data () {
+ return {
+ data: [],
+ }
+ },
+ methods: {
+ checkUpper (rule, value = '', callback) {
+ if (value !== value.toUpperCase()) {
+ callback(new Error('need to be upper!'))
+ } else {
+ callback()
+ }
+ },
+ toUpper (v, prev) {
+ if (v === prev) {
+ return v
+ }
+ return v.toUpperCase()
+ },
+ },
+
+ render () {
+ const { getFieldProps, getFieldError } = this.form
+ const errors = getFieldError('upper')
+ return (
+
upper normalize
+
+
+
+
+ {(errors) ? errors.join(',') : null}
+
+
)
+ },
+}
+
+const MaxMin = {
+ props: {
+ form: Object,
+ },
+ methods: {
+ normalizeMin (value, prevValue, allValues) {
+ console.log('normalizeMin', allValues.min, allValues.max)
+ const previousAllValues = this.form.getFieldsValue()
+ if (allValues.max !== previousAllValues.max) {
+ // max changed
+ if (value === '' || Number(allValues.max) < Number(value)) {
+ return allValues.max
+ }
+ }
+ return value
+ },
+ normalizeMax (value, prevValue, allValues) {
+ console.log('normalizeMax', allValues.min, allValues.max)
+ const previousAllValues = this.form.getFieldsValue()
+ if (allValues.min !== previousAllValues.min) {
+ // min changed
+ if (value === '' || Number(allValues.min) > Number(value)) {
+ return allValues.min
+ }
+ }
+ return value
+ },
+ },
+
+ render () {
+ const { getFieldProps } = this.form
+ return (
+
min:
+
+
max:
+
+
)
+ },
+}
+
+const Form = {
+ // props: {
+ // form: Object,
+ // },
+ methods: {
+ onSubmit (e) {
+ e.preventDefault()
+ this.form.validateFields((error, values) => {
+ if (!error) {
+ console.log('ok', values)
+ } else {
+ console.log('error', error, values)
+ }
+ })
+ },
+ },
+
+ render () {
+ const { form } = this
+ return ()
+ },
+}
+
+export default createForm()(Form)
+
diff --git a/components/vc-form/demo/overview.js b/components/vc-form/demo/overview.js
new file mode 100644
index 000000000..b4785c2a8
--- /dev/null
+++ b/components/vc-form/demo/overview.js
@@ -0,0 +1,259 @@
+/* eslint react/no-multi-comp:0, no-console:0 */
+
+import createDOMForm from '../src/createDOMForm'
+import { DatePicker, Select } from 'antd'
+import { regionStyle, errorStyle } from './styles'
+const { Option } = Select
+
+const Email = {
+ props: {
+ form: Object,
+ },
+ render () {
+ const { getFieldProps, getFieldError, isFieldValidating } = this.form
+ const errors = getFieldError('email')
+ return (
+
email sync validate
+
+ 错误的 email 格式,
+ },
+ ],
+ })}
+ />
+
+ {errors}
+
+
+ {isFieldValidating('email') ? 'validating' : null}
+
+
)
+ },
+
+}
+
+const User = {
+ props: {
+ form: Object,
+ },
+ methods: {
+ userExists (rule, value, callback) {
+ setTimeout(() => {
+ if (value === '1') {
+ callback([new Error('are you kidding?')])
+ } else if (value === 'yiminghe') {
+ callback([new Error('forbid yiminghe')])
+ } else {
+ callback()
+ }
+ }, 300)
+ },
+ },
+
+ render () {
+ const { getFieldProps, getFieldError, isFieldValidating } = this.form
+ const errors = getFieldError('user')
+ return (
+
* user async validate
+
+
+
+ {(errors) ? errors.join(',') : null}
+
+
+ {isFieldValidating('user') ? 'validating' : null}
+
+
)
+ },
+}
+
+const CustomInput = {
+ props: {
+ form: Object,
+ },
+ render () {
+ const { getFieldProps, getFieldError, isFieldValidating } = this.form
+ const errors = getFieldError('select')
+ return (
+
* custom select sync validate
+
+
+ {(errors) ? errors.join(',') : null}
+
+
+ {isFieldValidating('select') ? 'validating' : null}
+
+
)
+ },
+
+}
+
+const DateInput = {
+ props: {
+ form: Object,
+ },
+ render () {
+ const { getFieldProps, getFieldError } = this.form
+ const errors = getFieldError('date')
+ return (
+
* DateInput sync validate
+
+
+
+
+ {(errors) ? errors.join(',') : null}
+
+
)
+ },
+}
+
+function toNumber (v) {
+ if (v === undefined) {
+ return v
+ }
+ if (v === '') {
+ return undefined
+ }
+ if (v && v.trim() === '') {
+ return NaN
+ }
+ return Number(v)
+}
+
+const NumberInput = {
+ props: {
+ form: Object,
+ },
+ render () {
+ const { getFieldProps, getFieldError } = this.form
+ const errors = getFieldError('number')
+ return (
+
number input
+
+
+
+
+ {(errors) ? errors.join(',') : null}
+
+
)
+ },
+
+}
+
+const Form = {
+ methods: {
+ onSubmit (e) {
+ console.log('submit')
+ e.preventDefault()
+ this.form.validateFieldsAndScroll({ scroll: { offsetTop: 20 }}, (error, values) => {
+ if (!error) {
+ console.log('ok', values)
+ } else {
+ console.log('error', error, values)
+ }
+ })
+ },
+
+ reset (e) {
+ e.preventDefault()
+ this.form.resetFields()
+ },
+ },
+
+ render () {
+ const { form } = this
+ const { getFieldProps, getFieldError } = form
+ return ()
+ },
+}
+
+export default createDOMForm({
+ validateMessages: {
+ required (field) {
+ return `${field} 必填`
+ },
+ },
+})(Form)
diff --git a/components/vc-form/src/createBaseForm.jsx b/components/vc-form/src/createBaseForm.jsx
index 07a85baf7..dd482bf80 100644
--- a/components/vc-form/src/createBaseForm.jsx
+++ b/components/vc-form/src/createBaseForm.jsx
@@ -20,7 +20,7 @@ import {
flattenArray,
} from './utils'
-const DEFAULT_TRIGGER = 'input'
+const DEFAULT_TRIGGER = 'change'
function createBaseForm (option = {}, mixins = []) {
const {
@@ -534,15 +534,15 @@ function createBaseForm (option = {}, mixins = []) {
},
render () {
- const { $props, $listeners } = this
+ const { $listeners } = this
const formProps = {
[formPropName]: this.getForm(),
}
-
+ const props = getOptionProps(this)
const wrappedComponentProps = {
props: mapProps.call(this, {
...formProps,
- ...$props,
+ ...props,
}),
on: $listeners,
}
@@ -552,7 +552,12 @@ function createBaseForm (option = {}, mixins = []) {
return
},
}
-
+ if (!(WrappedComponent.props && formPropName in WrappedComponent.props)) {
+ WrappedComponent.props = {
+ ...WrappedComponent.props,
+ [formPropName]: Object,
+ }
+ }
return argumentContainer(Form, WrappedComponent)
}
}
diff --git a/components/vc-form/src/createDOMForm.jsx b/components/vc-form/src/createDOMForm.jsx
index 9fdc5dc12..ed4393017 100644
--- a/components/vc-form/src/createDOMForm.jsx
+++ b/components/vc-form/src/createDOMForm.jsx
@@ -52,7 +52,7 @@ const mixin = {
methods: {
getForm () {
return {
- ...formMixin.getForm.call(this),
+ ...formMixin.methods.getForm.call(this),
validateFieldsAndScroll: this.validateFieldsAndScroll,
}
},
@@ -69,7 +69,7 @@ const mixin = {
if (has(error, name)) {
const instance = this.getFieldInstance(name)
if (instance) {
- const node = instance.$el
+ const node = instance.$el || instance.elm
const top = node.getBoundingClientRect().top
if (firstTop === undefined || firstTop > top) {
firstTop = top
diff --git a/components/vc-form/src/index.jsx b/components/vc-form/src/index.jsx
index 4d3bdf6d8..344a848c6 100644
--- a/components/vc-form/src/index.jsx
+++ b/components/vc-form/src/index.jsx
@@ -3,14 +3,7 @@ import createForm from './createForm'
import createFormField from './createFormField'
import formShape from './propTypes'
import Vue from 'vue'
-
-Vue.directive('ant-ref', {
- bind: function (el, binding, vnode) {
- binding.value(vnode)
- },
- unbind: function (el, binding, vnode) {
- binding.value()
- },
-})
+import antRefDirective from '../../_util/antRefDirective'
+Vue.use(antRefDirective)
export { createForm, createFormField, formShape }
diff --git a/components/vc-form/src/utils.js b/components/vc-form/src/utils.js
index 7819380bc..626cae283 100644
--- a/components/vc-form/src/utils.js
+++ b/components/vc-form/src/utils.js
@@ -6,7 +6,7 @@ export function argumentContainer (Container, WrappedComponent) {
/* eslint no-param-reassign:0 */
Container.name = `Form_${getDisplayName(WrappedComponent)}`
Container.WrappedComponent = WrappedComponent
- Container.methods = { ...Container.methods, ...WrappedComponent.methods }
+ Container.props = { ...Container.props, ...WrappedComponent.props }
return Container
}
diff --git a/components/vc-notification/Notification.jsx b/components/vc-notification/Notification.jsx
index 81088375f..37199baff 100644
--- a/components/vc-notification/Notification.jsx
+++ b/components/vc-notification/Notification.jsx
@@ -7,6 +7,9 @@ import createChainedFunction from '../_util/createChainedFunction'
import getTransitionProps from '../_util/getTransitionProps'
import Notice from './Notice'
+import antRefDirective from '../_util/antRefDirective'
+Vue.use(antRefDirective)
+
let seed = 0
const now = Date.now()