879 lines
32 KiB
JavaScript
879 lines
32 KiB
JavaScript
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
||
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
||
|
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
|
||
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
||
|
import _typeof from "@babel/runtime/helpers/esm/typeof";
|
||
|
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
||
|
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
||
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
||
|
var _excluded = ["name"];
|
||
|
import warning from "rc-util/es/warning";
|
||
|
import * as React from 'react';
|
||
|
import { HOOK_MARK } from "./FieldContext";
|
||
|
import { allPromiseFinish } from "./utils/asyncUtil";
|
||
|
import { merge } from "rc-util/es/utils/set";
|
||
|
import { defaultValidateMessages } from "./utils/messages";
|
||
|
import NameMap from "./utils/NameMap";
|
||
|
import { cloneByNamePathList, containsNamePath, getNamePath, getValue, matchNamePath, setValue } from "./utils/valueUtil";
|
||
|
export var FormStore = /*#__PURE__*/_createClass(function FormStore(forceRootUpdate) {
|
||
|
var _this = this;
|
||
|
_classCallCheck(this, FormStore);
|
||
|
_defineProperty(this, "formHooked", false);
|
||
|
_defineProperty(this, "forceRootUpdate", void 0);
|
||
|
_defineProperty(this, "subscribable", true);
|
||
|
_defineProperty(this, "store", {});
|
||
|
_defineProperty(this, "fieldEntities", []);
|
||
|
_defineProperty(this, "initialValues", {});
|
||
|
_defineProperty(this, "callbacks", {});
|
||
|
_defineProperty(this, "validateMessages", null);
|
||
|
_defineProperty(this, "preserve", null);
|
||
|
_defineProperty(this, "lastValidatePromise", null);
|
||
|
_defineProperty(this, "getForm", function () {
|
||
|
return {
|
||
|
getFieldValue: _this.getFieldValue,
|
||
|
getFieldsValue: _this.getFieldsValue,
|
||
|
getFieldError: _this.getFieldError,
|
||
|
getFieldWarning: _this.getFieldWarning,
|
||
|
getFieldsError: _this.getFieldsError,
|
||
|
isFieldsTouched: _this.isFieldsTouched,
|
||
|
isFieldTouched: _this.isFieldTouched,
|
||
|
isFieldValidating: _this.isFieldValidating,
|
||
|
isFieldsValidating: _this.isFieldsValidating,
|
||
|
resetFields: _this.resetFields,
|
||
|
setFields: _this.setFields,
|
||
|
setFieldValue: _this.setFieldValue,
|
||
|
setFieldsValue: _this.setFieldsValue,
|
||
|
validateFields: _this.validateFields,
|
||
|
submit: _this.submit,
|
||
|
_init: true,
|
||
|
getInternalHooks: _this.getInternalHooks
|
||
|
};
|
||
|
});
|
||
|
// ======================== Internal Hooks ========================
|
||
|
_defineProperty(this, "getInternalHooks", function (key) {
|
||
|
if (key === HOOK_MARK) {
|
||
|
_this.formHooked = true;
|
||
|
return {
|
||
|
dispatch: _this.dispatch,
|
||
|
initEntityValue: _this.initEntityValue,
|
||
|
registerField: _this.registerField,
|
||
|
useSubscribe: _this.useSubscribe,
|
||
|
setInitialValues: _this.setInitialValues,
|
||
|
destroyForm: _this.destroyForm,
|
||
|
setCallbacks: _this.setCallbacks,
|
||
|
setValidateMessages: _this.setValidateMessages,
|
||
|
getFields: _this.getFields,
|
||
|
setPreserve: _this.setPreserve,
|
||
|
getInitialValue: _this.getInitialValue,
|
||
|
registerWatch: _this.registerWatch
|
||
|
};
|
||
|
}
|
||
|
warning(false, '`getInternalHooks` is internal usage. Should not call directly.');
|
||
|
return null;
|
||
|
});
|
||
|
_defineProperty(this, "useSubscribe", function (subscribable) {
|
||
|
_this.subscribable = subscribable;
|
||
|
});
|
||
|
/**
|
||
|
* Record prev Form unmount fieldEntities which config preserve false.
|
||
|
* This need to be refill with initialValues instead of store value.
|
||
|
*/
|
||
|
_defineProperty(this, "prevWithoutPreserves", null);
|
||
|
/**
|
||
|
* First time `setInitialValues` should update store with initial value
|
||
|
*/
|
||
|
_defineProperty(this, "setInitialValues", function (initialValues, init) {
|
||
|
_this.initialValues = initialValues || {};
|
||
|
if (init) {
|
||
|
var _this$prevWithoutPres;
|
||
|
var nextStore = merge(initialValues, _this.store);
|
||
|
|
||
|
// We will take consider prev form unmount fields.
|
||
|
// When the field is not `preserve`, we need fill this with initialValues instead of store.
|
||
|
// eslint-disable-next-line array-callback-return
|
||
|
(_this$prevWithoutPres = _this.prevWithoutPreserves) === null || _this$prevWithoutPres === void 0 ? void 0 : _this$prevWithoutPres.map(function (_ref) {
|
||
|
var namePath = _ref.key;
|
||
|
nextStore = setValue(nextStore, namePath, getValue(initialValues, namePath));
|
||
|
});
|
||
|
_this.prevWithoutPreserves = null;
|
||
|
_this.updateStore(nextStore);
|
||
|
}
|
||
|
});
|
||
|
_defineProperty(this, "destroyForm", function () {
|
||
|
var prevWithoutPreserves = new NameMap();
|
||
|
_this.getFieldEntities(true).forEach(function (entity) {
|
||
|
if (!_this.isMergedPreserve(entity.isPreserve())) {
|
||
|
prevWithoutPreserves.set(entity.getNamePath(), true);
|
||
|
}
|
||
|
});
|
||
|
_this.prevWithoutPreserves = prevWithoutPreserves;
|
||
|
});
|
||
|
_defineProperty(this, "getInitialValue", function (namePath) {
|
||
|
var initValue = getValue(_this.initialValues, namePath);
|
||
|
|
||
|
// Not cloneDeep when without `namePath`
|
||
|
return namePath.length ? merge(initValue) : initValue;
|
||
|
});
|
||
|
_defineProperty(this, "setCallbacks", function (callbacks) {
|
||
|
_this.callbacks = callbacks;
|
||
|
});
|
||
|
_defineProperty(this, "setValidateMessages", function (validateMessages) {
|
||
|
_this.validateMessages = validateMessages;
|
||
|
});
|
||
|
_defineProperty(this, "setPreserve", function (preserve) {
|
||
|
_this.preserve = preserve;
|
||
|
});
|
||
|
// ============================= Watch ============================
|
||
|
_defineProperty(this, "watchList", []);
|
||
|
_defineProperty(this, "registerWatch", function (callback) {
|
||
|
_this.watchList.push(callback);
|
||
|
return function () {
|
||
|
_this.watchList = _this.watchList.filter(function (fn) {
|
||
|
return fn !== callback;
|
||
|
});
|
||
|
};
|
||
|
});
|
||
|
_defineProperty(this, "notifyWatch", function () {
|
||
|
var namePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
||
|
// No need to cost perf when nothing need to watch
|
||
|
if (_this.watchList.length) {
|
||
|
var values = _this.getFieldsValue();
|
||
|
var allValues = _this.getFieldsValue(true);
|
||
|
_this.watchList.forEach(function (callback) {
|
||
|
callback(values, allValues, namePath);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
// ========================== Dev Warning =========================
|
||
|
_defineProperty(this, "timeoutId", null);
|
||
|
_defineProperty(this, "warningUnhooked", function () {
|
||
|
if (process.env.NODE_ENV !== 'production' && !_this.timeoutId && typeof window !== 'undefined') {
|
||
|
_this.timeoutId = setTimeout(function () {
|
||
|
_this.timeoutId = null;
|
||
|
if (!_this.formHooked) {
|
||
|
warning(false, 'Instance created by `useForm` is not connected to any Form element. Forget to pass `form` prop?');
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
// ============================ Store =============================
|
||
|
_defineProperty(this, "updateStore", function (nextStore) {
|
||
|
_this.store = nextStore;
|
||
|
});
|
||
|
// ============================ Fields ============================
|
||
|
/**
|
||
|
* Get registered field entities.
|
||
|
* @param pure Only return field which has a `name`. Default: false
|
||
|
*/
|
||
|
_defineProperty(this, "getFieldEntities", function () {
|
||
|
var pure = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||
|
if (!pure) {
|
||
|
return _this.fieldEntities;
|
||
|
}
|
||
|
return _this.fieldEntities.filter(function (field) {
|
||
|
return field.getNamePath().length;
|
||
|
});
|
||
|
});
|
||
|
_defineProperty(this, "getFieldsMap", function () {
|
||
|
var pure = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||
|
var cache = new NameMap();
|
||
|
_this.getFieldEntities(pure).forEach(function (field) {
|
||
|
var namePath = field.getNamePath();
|
||
|
cache.set(namePath, field);
|
||
|
});
|
||
|
return cache;
|
||
|
});
|
||
|
_defineProperty(this, "getFieldEntitiesForNamePathList", function (nameList) {
|
||
|
if (!nameList) {
|
||
|
return _this.getFieldEntities(true);
|
||
|
}
|
||
|
var cache = _this.getFieldsMap(true);
|
||
|
return nameList.map(function (name) {
|
||
|
var namePath = getNamePath(name);
|
||
|
return cache.get(namePath) || {
|
||
|
INVALIDATE_NAME_PATH: getNamePath(name)
|
||
|
};
|
||
|
});
|
||
|
});
|
||
|
_defineProperty(this, "getFieldsValue", function (nameList, filterFunc) {
|
||
|
_this.warningUnhooked();
|
||
|
|
||
|
// Fill args
|
||
|
var mergedNameList;
|
||
|
var mergedFilterFunc;
|
||
|
var mergedStrict;
|
||
|
if (nameList === true || Array.isArray(nameList)) {
|
||
|
mergedNameList = nameList;
|
||
|
mergedFilterFunc = filterFunc;
|
||
|
} else if (nameList && _typeof(nameList) === 'object') {
|
||
|
mergedStrict = nameList.strict;
|
||
|
mergedFilterFunc = nameList.filter;
|
||
|
}
|
||
|
if (mergedNameList === true && !mergedFilterFunc) {
|
||
|
return _this.store;
|
||
|
}
|
||
|
var fieldEntities = _this.getFieldEntitiesForNamePathList(Array.isArray(mergedNameList) ? mergedNameList : null);
|
||
|
var filteredNameList = [];
|
||
|
fieldEntities.forEach(function (entity) {
|
||
|
var _isListField, _ref3;
|
||
|
var namePath = 'INVALIDATE_NAME_PATH' in entity ? entity.INVALIDATE_NAME_PATH : entity.getNamePath();
|
||
|
|
||
|
// Ignore when it's a list item and not specific the namePath,
|
||
|
// since parent field is already take in count
|
||
|
if (mergedStrict) {
|
||
|
var _isList, _ref2;
|
||
|
if ((_isList = (_ref2 = entity).isList) !== null && _isList !== void 0 && _isList.call(_ref2)) {
|
||
|
return;
|
||
|
}
|
||
|
} else if (!mergedNameList && (_isListField = (_ref3 = entity).isListField) !== null && _isListField !== void 0 && _isListField.call(_ref3)) {
|
||
|
return;
|
||
|
}
|
||
|
if (!mergedFilterFunc) {
|
||
|
filteredNameList.push(namePath);
|
||
|
} else {
|
||
|
var meta = 'getMeta' in entity ? entity.getMeta() : null;
|
||
|
if (mergedFilterFunc(meta)) {
|
||
|
filteredNameList.push(namePath);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return cloneByNamePathList(_this.store, filteredNameList.map(getNamePath));
|
||
|
});
|
||
|
_defineProperty(this, "getFieldValue", function (name) {
|
||
|
_this.warningUnhooked();
|
||
|
var namePath = getNamePath(name);
|
||
|
return getValue(_this.store, namePath);
|
||
|
});
|
||
|
_defineProperty(this, "getFieldsError", function (nameList) {
|
||
|
_this.warningUnhooked();
|
||
|
var fieldEntities = _this.getFieldEntitiesForNamePathList(nameList);
|
||
|
return fieldEntities.map(function (entity, index) {
|
||
|
if (entity && !('INVALIDATE_NAME_PATH' in entity)) {
|
||
|
return {
|
||
|
name: entity.getNamePath(),
|
||
|
errors: entity.getErrors(),
|
||
|
warnings: entity.getWarnings()
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
name: getNamePath(nameList[index]),
|
||
|
errors: [],
|
||
|
warnings: []
|
||
|
};
|
||
|
});
|
||
|
});
|
||
|
_defineProperty(this, "getFieldError", function (name) {
|
||
|
_this.warningUnhooked();
|
||
|
var namePath = getNamePath(name);
|
||
|
var fieldError = _this.getFieldsError([namePath])[0];
|
||
|
return fieldError.errors;
|
||
|
});
|
||
|
_defineProperty(this, "getFieldWarning", function (name) {
|
||
|
_this.warningUnhooked();
|
||
|
var namePath = getNamePath(name);
|
||
|
var fieldError = _this.getFieldsError([namePath])[0];
|
||
|
return fieldError.warnings;
|
||
|
});
|
||
|
_defineProperty(this, "isFieldsTouched", function () {
|
||
|
_this.warningUnhooked();
|
||
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
||
|
args[_key] = arguments[_key];
|
||
|
}
|
||
|
var arg0 = args[0],
|
||
|
arg1 = args[1];
|
||
|
var namePathList;
|
||
|
var isAllFieldsTouched = false;
|
||
|
if (args.length === 0) {
|
||
|
namePathList = null;
|
||
|
} else if (args.length === 1) {
|
||
|
if (Array.isArray(arg0)) {
|
||
|
namePathList = arg0.map(getNamePath);
|
||
|
isAllFieldsTouched = false;
|
||
|
} else {
|
||
|
namePathList = null;
|
||
|
isAllFieldsTouched = arg0;
|
||
|
}
|
||
|
} else {
|
||
|
namePathList = arg0.map(getNamePath);
|
||
|
isAllFieldsTouched = arg1;
|
||
|
}
|
||
|
var fieldEntities = _this.getFieldEntities(true);
|
||
|
var isFieldTouched = function isFieldTouched(field) {
|
||
|
return field.isFieldTouched();
|
||
|
};
|
||
|
|
||
|
// ===== Will get fully compare when not config namePathList =====
|
||
|
if (!namePathList) {
|
||
|
return isAllFieldsTouched ? fieldEntities.every(isFieldTouched) : fieldEntities.some(isFieldTouched);
|
||
|
}
|
||
|
|
||
|
// Generate a nest tree for validate
|
||
|
var map = new NameMap();
|
||
|
namePathList.forEach(function (shortNamePath) {
|
||
|
map.set(shortNamePath, []);
|
||
|
});
|
||
|
fieldEntities.forEach(function (field) {
|
||
|
var fieldNamePath = field.getNamePath();
|
||
|
|
||
|
// Find matched entity and put into list
|
||
|
namePathList.forEach(function (shortNamePath) {
|
||
|
if (shortNamePath.every(function (nameUnit, i) {
|
||
|
return fieldNamePath[i] === nameUnit;
|
||
|
})) {
|
||
|
map.update(shortNamePath, function (list) {
|
||
|
return [].concat(_toConsumableArray(list), [field]);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// Check if NameMap value is touched
|
||
|
var isNamePathListTouched = function isNamePathListTouched(entities) {
|
||
|
return entities.some(isFieldTouched);
|
||
|
};
|
||
|
var namePathListEntities = map.map(function (_ref4) {
|
||
|
var value = _ref4.value;
|
||
|
return value;
|
||
|
});
|
||
|
return isAllFieldsTouched ? namePathListEntities.every(isNamePathListTouched) : namePathListEntities.some(isNamePathListTouched);
|
||
|
});
|
||
|
_defineProperty(this, "isFieldTouched", function (name) {
|
||
|
_this.warningUnhooked();
|
||
|
return _this.isFieldsTouched([name]);
|
||
|
});
|
||
|
_defineProperty(this, "isFieldsValidating", function (nameList) {
|
||
|
_this.warningUnhooked();
|
||
|
var fieldEntities = _this.getFieldEntities();
|
||
|
if (!nameList) {
|
||
|
return fieldEntities.some(function (testField) {
|
||
|
return testField.isFieldValidating();
|
||
|
});
|
||
|
}
|
||
|
var namePathList = nameList.map(getNamePath);
|
||
|
return fieldEntities.some(function (testField) {
|
||
|
var fieldNamePath = testField.getNamePath();
|
||
|
return containsNamePath(namePathList, fieldNamePath) && testField.isFieldValidating();
|
||
|
});
|
||
|
});
|
||
|
_defineProperty(this, "isFieldValidating", function (name) {
|
||
|
_this.warningUnhooked();
|
||
|
return _this.isFieldsValidating([name]);
|
||
|
});
|
||
|
/**
|
||
|
* Reset Field with field `initialValue` prop.
|
||
|
* Can pass `entities` or `namePathList` or just nothing.
|
||
|
*/
|
||
|
_defineProperty(this, "resetWithFieldInitialValue", function () {
|
||
|
var info = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||
|
// Create cache
|
||
|
var cache = new NameMap();
|
||
|
var fieldEntities = _this.getFieldEntities(true);
|
||
|
fieldEntities.forEach(function (field) {
|
||
|
var initialValue = field.props.initialValue;
|
||
|
var namePath = field.getNamePath();
|
||
|
|
||
|
// Record only if has `initialValue`
|
||
|
if (initialValue !== undefined) {
|
||
|
var records = cache.get(namePath) || new Set();
|
||
|
records.add({
|
||
|
entity: field,
|
||
|
value: initialValue
|
||
|
});
|
||
|
cache.set(namePath, records);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Reset
|
||
|
var resetWithFields = function resetWithFields(entities) {
|
||
|
entities.forEach(function (field) {
|
||
|
var initialValue = field.props.initialValue;
|
||
|
if (initialValue !== undefined) {
|
||
|
var namePath = field.getNamePath();
|
||
|
var formInitialValue = _this.getInitialValue(namePath);
|
||
|
if (formInitialValue !== undefined) {
|
||
|
// Warning if conflict with form initialValues and do not modify value
|
||
|
warning(false, "Form already set 'initialValues' with path '".concat(namePath.join('.'), "'. Field can not overwrite it."));
|
||
|
} else {
|
||
|
var records = cache.get(namePath);
|
||
|
if (records && records.size > 1) {
|
||
|
// Warning if multiple field set `initialValue`and do not modify value
|
||
|
warning(false, "Multiple Field with path '".concat(namePath.join('.'), "' set 'initialValue'. Can not decide which one to pick."));
|
||
|
} else if (records) {
|
||
|
var originValue = _this.getFieldValue(namePath);
|
||
|
// Set `initialValue`
|
||
|
if (!info.skipExist || originValue === undefined) {
|
||
|
_this.updateStore(setValue(_this.store, namePath, _toConsumableArray(records)[0].value));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
var requiredFieldEntities;
|
||
|
if (info.entities) {
|
||
|
requiredFieldEntities = info.entities;
|
||
|
} else if (info.namePathList) {
|
||
|
requiredFieldEntities = [];
|
||
|
info.namePathList.forEach(function (namePath) {
|
||
|
var records = cache.get(namePath);
|
||
|
if (records) {
|
||
|
var _requiredFieldEntitie;
|
||
|
(_requiredFieldEntitie = requiredFieldEntities).push.apply(_requiredFieldEntitie, _toConsumableArray(_toConsumableArray(records).map(function (r) {
|
||
|
return r.entity;
|
||
|
})));
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
requiredFieldEntities = fieldEntities;
|
||
|
}
|
||
|
resetWithFields(requiredFieldEntities);
|
||
|
});
|
||
|
_defineProperty(this, "resetFields", function (nameList) {
|
||
|
_this.warningUnhooked();
|
||
|
var prevStore = _this.store;
|
||
|
if (!nameList) {
|
||
|
_this.updateStore(merge(_this.initialValues));
|
||
|
_this.resetWithFieldInitialValue();
|
||
|
_this.notifyObservers(prevStore, null, {
|
||
|
type: 'reset'
|
||
|
});
|
||
|
_this.notifyWatch();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Reset by `nameList`
|
||
|
var namePathList = nameList.map(getNamePath);
|
||
|
namePathList.forEach(function (namePath) {
|
||
|
var initialValue = _this.getInitialValue(namePath);
|
||
|
_this.updateStore(setValue(_this.store, namePath, initialValue));
|
||
|
});
|
||
|
_this.resetWithFieldInitialValue({
|
||
|
namePathList: namePathList
|
||
|
});
|
||
|
_this.notifyObservers(prevStore, namePathList, {
|
||
|
type: 'reset'
|
||
|
});
|
||
|
_this.notifyWatch(namePathList);
|
||
|
});
|
||
|
_defineProperty(this, "setFields", function (fields) {
|
||
|
_this.warningUnhooked();
|
||
|
var prevStore = _this.store;
|
||
|
var namePathList = [];
|
||
|
fields.forEach(function (fieldData) {
|
||
|
var name = fieldData.name,
|
||
|
data = _objectWithoutProperties(fieldData, _excluded);
|
||
|
var namePath = getNamePath(name);
|
||
|
namePathList.push(namePath);
|
||
|
|
||
|
// Value
|
||
|
if ('value' in data) {
|
||
|
_this.updateStore(setValue(_this.store, namePath, data.value));
|
||
|
}
|
||
|
_this.notifyObservers(prevStore, [namePath], {
|
||
|
type: 'setField',
|
||
|
data: fieldData
|
||
|
});
|
||
|
});
|
||
|
_this.notifyWatch(namePathList);
|
||
|
});
|
||
|
_defineProperty(this, "getFields", function () {
|
||
|
var entities = _this.getFieldEntities(true);
|
||
|
var fields = entities.map(function (field) {
|
||
|
var namePath = field.getNamePath();
|
||
|
var meta = field.getMeta();
|
||
|
var fieldData = _objectSpread(_objectSpread({}, meta), {}, {
|
||
|
name: namePath,
|
||
|
value: _this.getFieldValue(namePath)
|
||
|
});
|
||
|
Object.defineProperty(fieldData, 'originRCField', {
|
||
|
value: true
|
||
|
});
|
||
|
return fieldData;
|
||
|
});
|
||
|
return fields;
|
||
|
});
|
||
|
// =========================== Observer ===========================
|
||
|
/**
|
||
|
* This only trigger when a field is on constructor to avoid we get initialValue too late
|
||
|
*/
|
||
|
_defineProperty(this, "initEntityValue", function (entity) {
|
||
|
var initialValue = entity.props.initialValue;
|
||
|
if (initialValue !== undefined) {
|
||
|
var namePath = entity.getNamePath();
|
||
|
var prevValue = getValue(_this.store, namePath);
|
||
|
if (prevValue === undefined) {
|
||
|
_this.updateStore(setValue(_this.store, namePath, initialValue));
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
_defineProperty(this, "isMergedPreserve", function (fieldPreserve) {
|
||
|
var mergedPreserve = fieldPreserve !== undefined ? fieldPreserve : _this.preserve;
|
||
|
return mergedPreserve !== null && mergedPreserve !== void 0 ? mergedPreserve : true;
|
||
|
});
|
||
|
_defineProperty(this, "registerField", function (entity) {
|
||
|
_this.fieldEntities.push(entity);
|
||
|
var namePath = entity.getNamePath();
|
||
|
_this.notifyWatch([namePath]);
|
||
|
|
||
|
// Set initial values
|
||
|
if (entity.props.initialValue !== undefined) {
|
||
|
var prevStore = _this.store;
|
||
|
_this.resetWithFieldInitialValue({
|
||
|
entities: [entity],
|
||
|
skipExist: true
|
||
|
});
|
||
|
_this.notifyObservers(prevStore, [entity.getNamePath()], {
|
||
|
type: 'valueUpdate',
|
||
|
source: 'internal'
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// un-register field callback
|
||
|
return function (isListField, preserve) {
|
||
|
var subNamePath = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
||
|
_this.fieldEntities = _this.fieldEntities.filter(function (item) {
|
||
|
return item !== entity;
|
||
|
});
|
||
|
|
||
|
// Clean up store value if not preserve
|
||
|
if (!_this.isMergedPreserve(preserve) && (!isListField || subNamePath.length > 1)) {
|
||
|
var defaultValue = isListField ? undefined : _this.getInitialValue(namePath);
|
||
|
if (namePath.length && _this.getFieldValue(namePath) !== defaultValue && _this.fieldEntities.every(function (field) {
|
||
|
return (
|
||
|
// Only reset when no namePath exist
|
||
|
!matchNamePath(field.getNamePath(), namePath)
|
||
|
);
|
||
|
})) {
|
||
|
var _prevStore = _this.store;
|
||
|
_this.updateStore(setValue(_prevStore, namePath, defaultValue, true));
|
||
|
|
||
|
// Notify that field is unmount
|
||
|
_this.notifyObservers(_prevStore, [namePath], {
|
||
|
type: 'remove'
|
||
|
});
|
||
|
|
||
|
// Dependencies update
|
||
|
_this.triggerDependenciesUpdate(_prevStore, namePath);
|
||
|
}
|
||
|
}
|
||
|
_this.notifyWatch([namePath]);
|
||
|
};
|
||
|
});
|
||
|
_defineProperty(this, "dispatch", function (action) {
|
||
|
switch (action.type) {
|
||
|
case 'updateValue':
|
||
|
{
|
||
|
var namePath = action.namePath,
|
||
|
value = action.value;
|
||
|
_this.updateValue(namePath, value);
|
||
|
break;
|
||
|
}
|
||
|
case 'validateField':
|
||
|
{
|
||
|
var _namePath = action.namePath,
|
||
|
triggerName = action.triggerName;
|
||
|
_this.validateFields([_namePath], {
|
||
|
triggerName: triggerName
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
// Currently we don't have other action. Do nothing.
|
||
|
}
|
||
|
});
|
||
|
_defineProperty(this, "notifyObservers", function (prevStore, namePathList, info) {
|
||
|
if (_this.subscribable) {
|
||
|
var mergedInfo = _objectSpread(_objectSpread({}, info), {}, {
|
||
|
store: _this.getFieldsValue(true)
|
||
|
});
|
||
|
_this.getFieldEntities().forEach(function (_ref5) {
|
||
|
var onStoreChange = _ref5.onStoreChange;
|
||
|
onStoreChange(prevStore, namePathList, mergedInfo);
|
||
|
});
|
||
|
} else {
|
||
|
_this.forceRootUpdate();
|
||
|
}
|
||
|
});
|
||
|
/**
|
||
|
* Notify dependencies children with parent update
|
||
|
* We need delay to trigger validate in case Field is under render props
|
||
|
*/
|
||
|
_defineProperty(this, "triggerDependenciesUpdate", function (prevStore, namePath) {
|
||
|
var childrenFields = _this.getDependencyChildrenFields(namePath);
|
||
|
if (childrenFields.length) {
|
||
|
_this.validateFields(childrenFields);
|
||
|
}
|
||
|
_this.notifyObservers(prevStore, childrenFields, {
|
||
|
type: 'dependenciesUpdate',
|
||
|
relatedFields: [namePath].concat(_toConsumableArray(childrenFields))
|
||
|
});
|
||
|
return childrenFields;
|
||
|
});
|
||
|
_defineProperty(this, "updateValue", function (name, value) {
|
||
|
var namePath = getNamePath(name);
|
||
|
var prevStore = _this.store;
|
||
|
_this.updateStore(setValue(_this.store, namePath, value));
|
||
|
_this.notifyObservers(prevStore, [namePath], {
|
||
|
type: 'valueUpdate',
|
||
|
source: 'internal'
|
||
|
});
|
||
|
_this.notifyWatch([namePath]);
|
||
|
|
||
|
// Dependencies update
|
||
|
var childrenFields = _this.triggerDependenciesUpdate(prevStore, namePath);
|
||
|
|
||
|
// trigger callback function
|
||
|
var onValuesChange = _this.callbacks.onValuesChange;
|
||
|
if (onValuesChange) {
|
||
|
var changedValues = cloneByNamePathList(_this.store, [namePath]);
|
||
|
onValuesChange(changedValues, _this.getFieldsValue());
|
||
|
}
|
||
|
_this.triggerOnFieldsChange([namePath].concat(_toConsumableArray(childrenFields)));
|
||
|
});
|
||
|
// Let all child Field get update.
|
||
|
_defineProperty(this, "setFieldsValue", function (store) {
|
||
|
_this.warningUnhooked();
|
||
|
var prevStore = _this.store;
|
||
|
if (store) {
|
||
|
var nextStore = merge(_this.store, store);
|
||
|
_this.updateStore(nextStore);
|
||
|
}
|
||
|
_this.notifyObservers(prevStore, null, {
|
||
|
type: 'valueUpdate',
|
||
|
source: 'external'
|
||
|
});
|
||
|
_this.notifyWatch();
|
||
|
});
|
||
|
_defineProperty(this, "setFieldValue", function (name, value) {
|
||
|
_this.setFields([{
|
||
|
name: name,
|
||
|
value: value
|
||
|
}]);
|
||
|
});
|
||
|
_defineProperty(this, "getDependencyChildrenFields", function (rootNamePath) {
|
||
|
var children = new Set();
|
||
|
var childrenFields = [];
|
||
|
var dependencies2fields = new NameMap();
|
||
|
|
||
|
/**
|
||
|
* Generate maps
|
||
|
* Can use cache to save perf if user report performance issue with this
|
||
|
*/
|
||
|
_this.getFieldEntities().forEach(function (field) {
|
||
|
var dependencies = field.props.dependencies;
|
||
|
(dependencies || []).forEach(function (dependency) {
|
||
|
var dependencyNamePath = getNamePath(dependency);
|
||
|
dependencies2fields.update(dependencyNamePath, function () {
|
||
|
var fields = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Set();
|
||
|
fields.add(field);
|
||
|
return fields;
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
var fillChildren = function fillChildren(namePath) {
|
||
|
var fields = dependencies2fields.get(namePath) || new Set();
|
||
|
fields.forEach(function (field) {
|
||
|
if (!children.has(field)) {
|
||
|
children.add(field);
|
||
|
var fieldNamePath = field.getNamePath();
|
||
|
if (field.isFieldDirty() && fieldNamePath.length) {
|
||
|
childrenFields.push(fieldNamePath);
|
||
|
fillChildren(fieldNamePath);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
fillChildren(rootNamePath);
|
||
|
return childrenFields;
|
||
|
});
|
||
|
_defineProperty(this, "triggerOnFieldsChange", function (namePathList, filedErrors) {
|
||
|
var onFieldsChange = _this.callbacks.onFieldsChange;
|
||
|
if (onFieldsChange) {
|
||
|
var fields = _this.getFields();
|
||
|
|
||
|
/**
|
||
|
* Fill errors since `fields` may be replaced by controlled fields
|
||
|
*/
|
||
|
if (filedErrors) {
|
||
|
var cache = new NameMap();
|
||
|
filedErrors.forEach(function (_ref6) {
|
||
|
var name = _ref6.name,
|
||
|
errors = _ref6.errors;
|
||
|
cache.set(name, errors);
|
||
|
});
|
||
|
fields.forEach(function (field) {
|
||
|
// eslint-disable-next-line no-param-reassign
|
||
|
field.errors = cache.get(field.name) || field.errors;
|
||
|
});
|
||
|
}
|
||
|
var changedFields = fields.filter(function (_ref7) {
|
||
|
var fieldName = _ref7.name;
|
||
|
return containsNamePath(namePathList, fieldName);
|
||
|
});
|
||
|
if (changedFields.length) {
|
||
|
onFieldsChange(changedFields, fields);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
// =========================== Validate ===========================
|
||
|
_defineProperty(this, "validateFields", function (arg1, arg2) {
|
||
|
var _options;
|
||
|
_this.warningUnhooked();
|
||
|
var nameList;
|
||
|
var options;
|
||
|
if (Array.isArray(arg1) || typeof arg1 === 'string' || typeof arg2 === 'string') {
|
||
|
nameList = arg1;
|
||
|
options = arg2;
|
||
|
} else {
|
||
|
options = arg1;
|
||
|
}
|
||
|
var provideNameList = !!nameList;
|
||
|
var namePathList = provideNameList ? nameList.map(getNamePath) : [];
|
||
|
|
||
|
// Collect result in promise list
|
||
|
var promiseList = [];
|
||
|
|
||
|
// We temp save the path which need trigger for `onFieldsChange`
|
||
|
var TMP_SPLIT = String(Date.now());
|
||
|
var validateNamePathList = new Set();
|
||
|
var recursive = (_options = options) === null || _options === void 0 ? void 0 : _options.recursive;
|
||
|
_this.getFieldEntities(true).forEach(function (field) {
|
||
|
// Add field if not provide `nameList`
|
||
|
if (!provideNameList) {
|
||
|
namePathList.push(field.getNamePath());
|
||
|
}
|
||
|
|
||
|
// Skip if without rule
|
||
|
if (!field.props.rules || !field.props.rules.length) {
|
||
|
return;
|
||
|
}
|
||
|
var fieldNamePath = field.getNamePath();
|
||
|
validateNamePathList.add(fieldNamePath.join(TMP_SPLIT));
|
||
|
|
||
|
// Add field validate rule in to promise list
|
||
|
if (!provideNameList || containsNamePath(namePathList, fieldNamePath, recursive)) {
|
||
|
var promise = field.validateRules(_objectSpread({
|
||
|
validateMessages: _objectSpread(_objectSpread({}, defaultValidateMessages), _this.validateMessages)
|
||
|
}, options));
|
||
|
|
||
|
// Wrap promise with field
|
||
|
promiseList.push(promise.then(function () {
|
||
|
return {
|
||
|
name: fieldNamePath,
|
||
|
errors: [],
|
||
|
warnings: []
|
||
|
};
|
||
|
}).catch(function (ruleErrors) {
|
||
|
var _ruleErrors$forEach;
|
||
|
var mergedErrors = [];
|
||
|
var mergedWarnings = [];
|
||
|
(_ruleErrors$forEach = ruleErrors.forEach) === null || _ruleErrors$forEach === void 0 ? void 0 : _ruleErrors$forEach.call(ruleErrors, function (_ref8) {
|
||
|
var warningOnly = _ref8.rule.warningOnly,
|
||
|
errors = _ref8.errors;
|
||
|
if (warningOnly) {
|
||
|
mergedWarnings.push.apply(mergedWarnings, _toConsumableArray(errors));
|
||
|
} else {
|
||
|
mergedErrors.push.apply(mergedErrors, _toConsumableArray(errors));
|
||
|
}
|
||
|
});
|
||
|
if (mergedErrors.length) {
|
||
|
return Promise.reject({
|
||
|
name: fieldNamePath,
|
||
|
errors: mergedErrors,
|
||
|
warnings: mergedWarnings
|
||
|
});
|
||
|
}
|
||
|
return {
|
||
|
name: fieldNamePath,
|
||
|
errors: mergedErrors,
|
||
|
warnings: mergedWarnings
|
||
|
};
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
var summaryPromise = allPromiseFinish(promiseList);
|
||
|
_this.lastValidatePromise = summaryPromise;
|
||
|
|
||
|
// Notify fields with rule that validate has finished and need update
|
||
|
summaryPromise.catch(function (results) {
|
||
|
return results;
|
||
|
}).then(function (results) {
|
||
|
var resultNamePathList = results.map(function (_ref9) {
|
||
|
var name = _ref9.name;
|
||
|
return name;
|
||
|
});
|
||
|
_this.notifyObservers(_this.store, resultNamePathList, {
|
||
|
type: 'validateFinish'
|
||
|
});
|
||
|
_this.triggerOnFieldsChange(resultNamePathList, results);
|
||
|
});
|
||
|
var returnPromise = summaryPromise.then(function () {
|
||
|
if (_this.lastValidatePromise === summaryPromise) {
|
||
|
return Promise.resolve(_this.getFieldsValue(namePathList));
|
||
|
}
|
||
|
return Promise.reject([]);
|
||
|
}).catch(function (results) {
|
||
|
var errorList = results.filter(function (result) {
|
||
|
return result && result.errors.length;
|
||
|
});
|
||
|
return Promise.reject({
|
||
|
values: _this.getFieldsValue(namePathList),
|
||
|
errorFields: errorList,
|
||
|
outOfDate: _this.lastValidatePromise !== summaryPromise
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// Do not throw in console
|
||
|
returnPromise.catch(function (e) {
|
||
|
return e;
|
||
|
});
|
||
|
|
||
|
// `validating` changed. Trigger `onFieldsChange`
|
||
|
var triggerNamePathList = namePathList.filter(function (namePath) {
|
||
|
return validateNamePathList.has(namePath.join(TMP_SPLIT));
|
||
|
});
|
||
|
_this.triggerOnFieldsChange(triggerNamePathList);
|
||
|
return returnPromise;
|
||
|
});
|
||
|
// ============================ Submit ============================
|
||
|
_defineProperty(this, "submit", function () {
|
||
|
_this.warningUnhooked();
|
||
|
_this.validateFields().then(function (values) {
|
||
|
var onFinish = _this.callbacks.onFinish;
|
||
|
if (onFinish) {
|
||
|
try {
|
||
|
onFinish(values);
|
||
|
} catch (err) {
|
||
|
// Should print error if user `onFinish` callback failed
|
||
|
console.error(err);
|
||
|
}
|
||
|
}
|
||
|
}).catch(function (e) {
|
||
|
var onFinishFailed = _this.callbacks.onFinishFailed;
|
||
|
if (onFinishFailed) {
|
||
|
onFinishFailed(e);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
this.forceRootUpdate = forceRootUpdate;
|
||
|
});
|
||
|
function useForm(form) {
|
||
|
var formRef = React.useRef();
|
||
|
var _React$useState = React.useState({}),
|
||
|
_React$useState2 = _slicedToArray(_React$useState, 2),
|
||
|
forceUpdate = _React$useState2[1];
|
||
|
if (!formRef.current) {
|
||
|
if (form) {
|
||
|
formRef.current = form;
|
||
|
} else {
|
||
|
// Create a new FormStore if not provided
|
||
|
var forceReRender = function forceReRender() {
|
||
|
forceUpdate({});
|
||
|
};
|
||
|
var formStore = new FormStore(forceReRender);
|
||
|
formRef.current = formStore.getForm();
|
||
|
}
|
||
|
}
|
||
|
return [formRef.current];
|
||
|
}
|
||
|
export default useForm;
|