UNPKG

nornj-react

Version:

React bindings for NornJ template engine.

317 lines (267 loc) 8.61 kB
import React, { Fragment, isValidElement, useMemo } from 'react'; import nj, { registerExtension, as } from 'nornj'; import { observable, runInAction, reaction, extendObservable, isComputedProp, observe } from 'mobx'; import schema from 'async-validator'; import extensionConfigs from '../../../mobx/formData/extensionConfig'; import moment from 'moment'; const createFormData = options => ({ _njMobxFormData: true, fieldDatas: new Map(), _operate(name, callback, callbackMulti, callbackMultiReturn) { if (typeof name === 'string') { return callback(name); } else { const names = Array.isArray(name) ? name : []; this.fieldDatas.forEach((fieldData, name) => { (!names.length || names.indexOf(name) > -1) && (callbackMulti || callback)(name); }); if (callbackMultiReturn) { return callbackMultiReturn(names); } } }, _validate(name) { const oFd = this.fieldDatas.get(name); const value = this[name]; return new Promise((resolve, reject) => { oFd.validatorSchema.validate({ [name]: value }, {}, (errors, fields) => { if (errors) { var _errors$; this.error(name, errors === null || errors === void 0 ? void 0 : (_errors$ = errors[0]) === null || _errors$ === void 0 ? void 0 : _errors$.message); reject({ values: { [name]: value }, errors, fields }); } else { this.clear(name, true); resolve({ [name]: value }); } }); }); }, validate(names) { const validators = []; return this._operate(names, name => this._validate(name), name => validators.push(this._validate(name)), () => new Promise((resolve, reject) => { Promise.all(validators).then(values => resolve(Object.assign({}, ...values))).catch(errorInfo => reject(errorInfo)); })); }, error(name, help) { const oFd = this.fieldDatas.get(name); oFd.validateStatus = 'error'; oFd.help = help; }, _clear(name, success) { const oFd = this.fieldDatas.get(name); oFd.validateStatus = success ? 'success' : null; oFd.help = null; }, clear(names, success) { return this._operate(names, name => this._clear(name, success)); }, _reset(name) { this.clear(name); const oFd = this.fieldDatas.get(name); oFd.reset(); }, reset(names) { return this._operate(names, name => this._reset(name)); }, add(fieldData) { const { name, value, trigger = 'valueChange', rules, ...ruleOptions } = fieldData; const fd = { name, value, trigger, rules, ...ruleOptions }; const _rules = rules ? rules : [ruleOptions]; fd.rules = _rules.map((rule, i) => { const oRule = observable(rule); observe(oRule, change => { const schemaRules = fd.validatorSchema.rules[name]; Object.assign(schemaRules[i], oRule); }); return oRule; }); fd.setDefaultRule = rule => { const schemaRules = fd.validatorSchema.rules[name]; _rules.forEach((r, i) => { if (r.type == null) { schemaRules[i].type = rule.type; } }); }; fd.validatorSchema = new schema({ [name]: _rules.map(({ type = 'string', required = false, transform: _transform, ...others }) => ({ type, required, transform(_value) { var _value2; switch (this.type) { case 'number': case 'integer': case 'float': _value = nj.isString(_value) && ((_value2 = _value) === null || _value2 === void 0 ? void 0 : _value2.trim()) !== '' && !isNaN(_value) ? +_value : _value; break; case 'date': if (moment.isMoment(_value)) { _value = _value.toDate(); } break; } return _transform ? _transform(_value) : _value; }, ...others })) }); fd.reset = function () { if (this.value !== value) { this._resetting = true; } this.value = value; }; const oFd = observable(fd); this.fieldDatas.set(name, oFd); if (options === null || options === void 0 ? void 0 : options.validateMessages) { const { validateMessages } = options; fd.validatorSchema.messages(typeof validateMessages === 'function' ? validateMessages(oFd) : validateMessages); } !isComputedProp(this, name) && extendObservable(this, Object.defineProperty({}, name, { get: function () { var _this$fieldDatas$get; return (_this$fieldDatas$get = this.fieldDatas.get(name)) === null || _this$fieldDatas$get === void 0 ? void 0 : _this$fieldDatas$get.value; }, set: function (value) { this.setValue(name, value); }, enumerable: true, configurable: true })); if (trigger === 'valueChange') { oFd._reactionDispose = reaction(() => Array.isArray(this[name]) ? this[name].map(item => item) : this[name], () => { if (!oFd._resetting) { this.validate(name).catch(nj.noop); } oFd._resetting = false; }); } }, delete(name) { const oFd = this.fieldDatas.get(name); oFd === null || oFd === void 0 ? void 0 : oFd._reactionDispose(); this.fieldDatas.delete(name); }, setValue(name, value) { runInAction(() => { if (typeof name === 'string') { const fieldData = this.fieldDatas.get(name); if (fieldData) { fieldData.value = value; } } else { this.fieldDatas.forEach((fieldData, fieldName) => { if (fieldName in name) { fieldData.value = name[fieldName]; } }); } }); }, get formData() { return this; } }); function getChildrenWithoutFragment(children) { const actualChildren = []; children.forEach(child => { if (!isValidElement(child) || child.type !== Fragment) { if (Array.isArray(child)) { var _getChildrenWithoutFr; (_getChildrenWithoutFr = getChildrenWithoutFragment(child)) === null || _getChildrenWithoutFr === void 0 ? void 0 : _getChildrenWithoutFr.forEach(child => actualChildren.push(child)); } else { actualChildren.push(child); } } else { var _getChildrenWithoutFr2, _ref; (_getChildrenWithoutFr2 = getChildrenWithoutFragment((_ref = child === null || child === void 0 ? void 0 : child.props) === null || _ref === void 0 ? void 0 : _ref.children)) === null || _getChildrenWithoutFr2 === void 0 ? void 0 : _getChildrenWithoutFr2.forEach(child => actualChildren.push(child)); } }); return actualChildren; } registerExtension('mobxFormData', options => { const { children } = options; const props = options.props; let _children = children(); if (!Array.isArray(_children)) { _children = [_children]; } const formData = createFormData(props); getChildrenWithoutFragment(_children).forEach(fieldData => { fieldData && formData.add(fieldData); }); return (props === null || props === void 0 ? void 0 : props.observable) ? observable(formData) : formData; }, extensionConfigs.mobxFormData); registerExtension('mobxFieldData', options => options.props, extensionConfigs.mobxFieldData); registerExtension('mobxField', options => { const { value, tagProps } = options; const _value = value(); const { prop, source } = _value; const fieldNames = Array.isArray(prop) ? prop : [prop]; let validateStatus = null; const help = []; fieldNames.forEach(fieldName => { const oFd = source.fieldDatas.get(fieldName); if (validateStatus == null && oFd.validateStatus != null) { validateStatus = oFd.validateStatus; } if (oFd.help != null) { help.push(React.createElement("div", { key: help.length }, oFd.help)); } if (tagProps.required == null) { tagProps.required = oFd.rules.find(rule => rule.required); } if (tagProps.label) { oFd.label = tagProps.label; } else if (oFd.label) { tagProps.label = oFd.label; } }); tagProps.validateStatus = validateStatus; if (help.length) { tagProps.help = React.createElement(React.Fragment, null, help); } }, extensionConfigs.mobxField); export function useFormData(formDataElement, deps = []) { return useMemo(() => as(observable(formDataElement())), deps); }