@uform/core
Advanced tools
Comparing version 1.0.1 to 1.0.2
1167
lib/index.js
@@ -1,1166 +0,1 @@ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var shared_1 = require("@uform/shared"); | ||
exports.FormPath = shared_1.FormPath; | ||
var validator_1 = require("@uform/validator"); | ||
exports.setValidationLanguage = validator_1.setValidationLanguage; | ||
exports.setValidationLocale = validator_1.setValidationLocale; | ||
var lifecycle_1 = require("./shared/lifecycle"); | ||
var graph_1 = require("./shared/graph"); | ||
exports.FormGraph = graph_1.FormGraph; | ||
var form_1 = require("./state/form"); | ||
var virtual_field_1 = require("./state/virtual-field"); | ||
var field_1 = require("./state/field"); | ||
var types_1 = require("./types"); | ||
__export(require("./shared/lifecycle")); | ||
__export(require("./types")); | ||
function createForm(options) { | ||
if (options === void 0) { options = {}; } | ||
function onGraphChange(_a) { | ||
var type = _a.type, payload = _a.payload; | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_GRAPH_CHANGE, graph); | ||
if (type === 'GRAPH_NODE_WILL_UNMOUNT') { | ||
validator.unregister(payload.path.toString()); | ||
} | ||
} | ||
function syncFieldValues(state) { | ||
var dataPath = shared_1.FormPath.parse(state.name); | ||
var parent = graph.getLatestParent(state.path); | ||
var parentValue = getFormValuesIn(parent.path); | ||
var value = getFormValuesIn(state.name); | ||
var removed = false; | ||
if (shared_1.isArr(parentValue) && !dataPath.existIn(parentValue, parent.path)) { | ||
if (!parent.path | ||
.getNearestChildPathBy(state.path) | ||
.existIn(parentValue, parent.path)) { | ||
graph.remove(state.path); | ||
removed = true; | ||
} | ||
} | ||
else { | ||
shared_1.each(env.removeNodes, function (_, name) { | ||
if (dataPath.includes(name)) { | ||
graph.remove(state.path); | ||
delete env.removeNodes[name]; | ||
removed = true; | ||
} | ||
}); | ||
} | ||
if (removed) | ||
return; | ||
if (!shared_1.isEqual(value, state.value)) { | ||
state.value = value; | ||
} | ||
} | ||
function syncFieldIntialValues(state) { | ||
var initialValue = getFormInitialValuesIn(state.name); | ||
if (!shared_1.isEqual(initialValue, state.initialValue)) { | ||
state.initialValue = initialValue; | ||
if (!shared_1.isValid(state.value)) { | ||
state.value = initialValue; | ||
} | ||
else if (/array/gi.test(state.dataType) && | ||
state.value && | ||
state.value.length === 0) { | ||
state.value = initialValue; | ||
} | ||
} | ||
} | ||
function onFormChange(published) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_CHANGE, state); | ||
var valuesChanged = state.isDirty('values'); | ||
var initialValuesChanged = state.isDirty('initialValues'); | ||
var unmountedChanged = state.isDirty('unmounted'); | ||
var mountedChanged = state.isDirty('mounted'); | ||
var initializedChanged = state.isDirty('initialized'); | ||
var editableChanged = state.isDirty('editable'); | ||
if (valuesChanged || initialValuesChanged) { | ||
var updateFields = function (field) { | ||
if (types_1.isField(field)) { | ||
field.setState(function (state) { | ||
if (state.visible || state.unmounted) { | ||
if (valuesChanged) { | ||
syncFieldValues(state); | ||
} | ||
if (initialValuesChanged) { | ||
syncFieldIntialValues(state); | ||
} | ||
} | ||
else { | ||
if (valuesChanged) { | ||
env.hiddenPendingFields[state.name] = | ||
env.hiddenPendingFields[state.name] || {}; | ||
env.hiddenPendingFields[state.name].values = true; | ||
} | ||
if (initialValuesChanged) { | ||
env.hiddenPendingFields[state.name] = | ||
env.hiddenPendingFields[state.name] || {}; | ||
env.hiddenPendingFields[state.name].initialValues = true; | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
if (valuesChanged || initialValuesChanged) { | ||
if (!env.leadingStage) { | ||
var userUpdateFieldPath = env.userUpdateFields[env.userUpdateFields.length - 1]; | ||
if (userUpdateFieldPath && graph.get(userUpdateFieldPath)) { | ||
graph.eachParentAndChildren(userUpdateFieldPath, updateFields); | ||
} | ||
else { | ||
graph.eachChildren(updateFields); | ||
} | ||
} | ||
else { | ||
graph.eachChildren(updateFields); | ||
} | ||
} | ||
if (valuesChanged) { | ||
if (shared_1.isFn(options.onChange)) { | ||
options.onChange(shared_1.clone(published.values)); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_VALUES_CHANGE, state); | ||
} | ||
if (initialValuesChanged) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_INITIAL_VALUES_CHANGE, state); | ||
} | ||
} | ||
if (editableChanged) { | ||
graph.eachChildren(function (field) { | ||
if (types_1.isField(field)) { | ||
field.setState(function (state) { | ||
state.formEditable = published.editable; | ||
}); | ||
} | ||
}); | ||
} | ||
if (unmountedChanged && published.unmounted) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_UNMOUNT, state); | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_MOUNT, state); | ||
} | ||
if (initializedChanged) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_INIT, state); | ||
} | ||
} | ||
function updateRecoverableShownState(parentState, childState, name) { | ||
var lastShownState = env.lastShownStates[childState.path]; | ||
var lastStateValue = childState[name]; | ||
if (parentState[name] && lastShownState && lastShownState[name] === false) { | ||
childState[name] = false; | ||
delete lastShownState[name]; | ||
if (!lastShownState.hasOwnProperty('visible') && | ||
!lastShownState.hasOwnProperty('display')) { | ||
delete env.lastShownStates[childState.path]; | ||
} | ||
} | ||
else { | ||
childState[name] = parentState[name]; | ||
} | ||
if (!parentState[name] && !lastStateValue) { | ||
if (!lastShownState) { | ||
env.lastShownStates[childState.path] = {}; | ||
} | ||
env.lastShownStates[childState.path][name] = false; | ||
} | ||
} | ||
function onFieldChange(_a) { | ||
var field = _a.field, path = _a.path; | ||
return function (published) { | ||
var valueChanged = field.isDirty('value'); | ||
var initialValueChanged = field.isDirty('initialValue'); | ||
var visibleChanged = field.isDirty('visible'); | ||
var displayChanged = field.isDirty('display'); | ||
var unmountedChanged = field.isDirty('unmounted'); | ||
var mountedChanged = field.isDirty('mounted'); | ||
var initializedChanged = field.isDirty('initialized'); | ||
var warningsChanged = field.isDirty('warnings'); | ||
var errorsChanged = field.isDirty('errors'); | ||
var userUpdateFieldPath = env.userUpdateFields[env.userUpdateFields.length - 1]; | ||
var syncField = function () { | ||
if (env.hiddenPendingFields[published.name]) { | ||
field.setState(function (state) { | ||
if (env.hiddenPendingFields[state.name].values) { | ||
syncFieldValues(state); | ||
} | ||
if (env.hiddenPendingFields[state.name].initialValues) { | ||
syncFieldIntialValues(state); | ||
} | ||
delete env.hiddenPendingFields[state.name]; | ||
}); | ||
} | ||
}; | ||
var notifyFormValuesChange = function () { | ||
if (shared_1.isFn(options.onChange)) { | ||
options.onChange(state.getSourceState(function (state) { return shared_1.clone(state.values); })); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_VALUES_CHANGE, state); | ||
}; | ||
if (initializedChanged) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_INIT, field); | ||
var isEmptyValue_1 = !shared_1.isValid(published.value); | ||
var isEmptyInitialValue_1 = !shared_1.isValid(published.initialValue); | ||
if (isEmptyValue_1 || isEmptyInitialValue_1) { | ||
field.setSourceState(function (state) { | ||
if (isEmptyValue_1) | ||
state.value = getFormValuesIn(state.name); | ||
if (isEmptyInitialValue_1) | ||
state.initialValue = getFormInitialValuesIn(state.name); | ||
}); | ||
} | ||
} | ||
var wasHidden = published.visible == false || published.unmounted === true; | ||
if (valueChanged) { | ||
if (!wasHidden) { | ||
userUpdating(field, function () { | ||
setFormValuesIn(path, published.value); | ||
}); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_VALUE_CHANGE, field); | ||
} | ||
if (initialValueChanged) { | ||
if (!wasHidden) { | ||
setFormInitialValuesIn(path, published.initialValue); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_INITIAL_VALUE_CHANGE, field); | ||
} | ||
if (displayChanged || visibleChanged) { | ||
if (visibleChanged) { | ||
userUpdating(field, function () { | ||
if (!published.visible) { | ||
deleteFormValuesIn(path, true); | ||
notifyFormValuesChange(); | ||
} | ||
else { | ||
setFormValuesIn(path, published.value); | ||
syncField(); | ||
} | ||
}); | ||
} | ||
graph.eachChildren(path, function (childState) { | ||
childState.setState(function (state) { | ||
if (visibleChanged) { | ||
updateRecoverableShownState(published, state, 'visible'); | ||
} | ||
if (displayChanged) { | ||
updateRecoverableShownState(published, state, 'display'); | ||
} | ||
}, true); | ||
}); | ||
} | ||
if (unmountedChanged && | ||
(published.display !== false || published.visible === false)) { | ||
userUpdating(field, function () { | ||
if (published.unmounted) { | ||
deleteFormValuesIn(path, true); | ||
notifyFormValuesChange(); | ||
} | ||
else { | ||
setFormValuesIn(path, published.value); | ||
syncField(); | ||
} | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_UNMOUNT, field); | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_MOUNT, field); | ||
} | ||
if (errorsChanged) { | ||
syncFormMessages('errors', published); | ||
} | ||
if (warningsChanged) { | ||
syncFormMessages('warnings', published); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_CHANGE, field); | ||
if (userUpdateFieldPath && !env.leadingStage) { | ||
if (shared_1.FormPath.parse(path).match(userUpdateFieldPath)) { | ||
return; | ||
} | ||
if (shared_1.FormPath.parse(userUpdateFieldPath).includes(path)) { | ||
return false; | ||
} | ||
} | ||
}; | ||
} | ||
function onVirtualFieldChange(_a) { | ||
var field = _a.field, path = _a.path; | ||
return function (published) { | ||
var visibleChanged = field.isDirty('visible'); | ||
var displayChanged = field.isDirty('display'); | ||
var mountedChanged = field.isDirty('mounted'); | ||
var initializedChanged = field.isDirty('initialized'); | ||
if (initializedChanged) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_INIT, field); | ||
} | ||
if (visibleChanged || displayChanged) { | ||
graph.eachChildren(path, function (childState) { | ||
childState.setState(function (state) { | ||
if (visibleChanged) { | ||
updateRecoverableShownState(published, state, 'visible'); | ||
} | ||
if (displayChanged) { | ||
updateRecoverableShownState(published, state, 'display'); | ||
} | ||
}, true); | ||
}); | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_MOUNT, field); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_CHANGE, field); | ||
}; | ||
} | ||
function registerVirtualField(_a) { | ||
var name = _a.name, path = _a.path, props = _a.props, display = _a.display, visible = _a.visible, computeState = _a.computeState, useDirty = _a.useDirty; | ||
var nodePath = shared_1.FormPath.parse(path || name); | ||
var dataPath = transformDataPath(nodePath); | ||
var field; | ||
var createField = function (field) { | ||
var alreadyHaveField = !!field; | ||
field = | ||
field || | ||
new virtual_field_1.VirtualFieldState({ | ||
nodePath: nodePath, | ||
dataPath: dataPath, | ||
computeState: computeState, | ||
useDirty: shared_1.isValid(useDirty) ? useDirty : options.useDirty | ||
}); | ||
field.subscription = { | ||
notify: onVirtualFieldChange({ field: field, path: nodePath }) | ||
}; | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_WILL_INIT, field); | ||
if (!alreadyHaveField) { | ||
graph.appendNode(nodePath, field); | ||
} | ||
field.batch(function () { | ||
field.setState(function (state) { | ||
state.initialized = true; | ||
state.props = props; | ||
if (shared_1.isValid(visible)) { | ||
state.visible = visible; | ||
} | ||
if (shared_1.isValid(display)) { | ||
state.display = display; | ||
} | ||
}); | ||
batchRunTaskQueue(field, nodePath); | ||
}); | ||
return field; | ||
}; | ||
if (graph.exist(nodePath)) { | ||
field = graph.get(nodePath); | ||
if (types_1.isField(field)) { | ||
graph.replace(nodePath, field); | ||
} | ||
} | ||
else { | ||
field = createField(); | ||
} | ||
return field; | ||
} | ||
function registerField(_a) { | ||
var path = _a.path, name = _a.name, value = _a.value, initialValue = _a.initialValue, required = _a.required, rules = _a.rules, editable = _a.editable, visible = _a.visible, display = _a.display, computeState = _a.computeState, dataType = _a.dataType, useDirty = _a.useDirty, props = _a.props; | ||
var field; | ||
var nodePath = shared_1.FormPath.parse(path || name); | ||
var dataPath = transformDataPath(nodePath); | ||
var createField = function (field) { | ||
var alreadyHaveField = !!field; | ||
field = | ||
field || | ||
new field_1.FieldState({ | ||
nodePath: nodePath, | ||
dataPath: dataPath, | ||
computeState: computeState, | ||
dataType: dataType, | ||
useDirty: shared_1.isValid(useDirty) ? useDirty : options.useDirty | ||
}); | ||
field.subscription = { | ||
notify: onFieldChange({ field: field, path: nodePath }) | ||
}; | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_WILL_INIT, field); | ||
if (!alreadyHaveField) { | ||
graph.appendNode(nodePath, field); | ||
} | ||
field.batch(function () { | ||
field.setState(function (state) { | ||
var formValue = getFormValuesIn(dataPath); | ||
var formInitialValue = getFormInitialValuesIn(dataPath); | ||
if (shared_1.isValid(value)) { | ||
state.value = value; | ||
} | ||
else { | ||
state.value = existFormValuesIn(dataPath) ? formValue : initialValue; | ||
} | ||
state.initialValue = shared_1.isValid(initialValue) | ||
? initialValue | ||
: formInitialValue; | ||
if (shared_1.isValid(visible)) { | ||
state.visible = visible; | ||
} | ||
if (shared_1.isValid(display)) { | ||
state.display = display; | ||
} | ||
if (shared_1.isValid(props)) { | ||
state.props = props; | ||
} | ||
if (shared_1.isValid(required)) { | ||
state.required = required; | ||
} | ||
if (shared_1.isValid(rules)) { | ||
state.rules = rules; | ||
} | ||
if (shared_1.isValid(editable)) { | ||
state.selfEditable = editable; | ||
} | ||
if (shared_1.isValid(options.editable)) { | ||
state.formEditable = options.editable; | ||
} | ||
state.initialized = true; | ||
}); | ||
batchRunTaskQueue(field, nodePath); | ||
}); | ||
validator.register(nodePath, function (validate) { | ||
var _a = field.getState(), value = _a.value, rules = _a.rules, editable = _a.editable, visible = _a.visible, unmounted = _a.unmounted, display = _a.display; | ||
if (editable === false || | ||
visible === false || | ||
unmounted === true || | ||
display === false) | ||
return validate(value, []); | ||
clearTimeout(field.validateTimer); | ||
field.validateTimer = setTimeout(function () { | ||
field.setState(function (state) { | ||
state.validating = true; | ||
}); | ||
}, 60); | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_VALIDATE_START, field); | ||
return validate(value, rules).then(function (_a) { | ||
var errors = _a.errors, warnings = _a.warnings; | ||
clearTimeout(field.validateTimer); | ||
return new Promise(function (resolve) { | ||
var syncState = function () { | ||
field.setState(function (state) { | ||
state.validating = false; | ||
state.ruleErrors = errors; | ||
state.ruleWarnings = warnings; | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_VALIDATE_END, field); | ||
resolve({ errors: errors, warnings: warnings }); | ||
}; | ||
if (graph.size < 100) { | ||
syncState(); | ||
} | ||
else { | ||
applyWithScheduler(syncState); | ||
} | ||
}); | ||
}); | ||
}); | ||
return field; | ||
}; | ||
if (graph.exist(nodePath)) { | ||
field = graph.get(nodePath); | ||
if (types_1.isVirtualField(field)) { | ||
graph.replace(nodePath, field); | ||
} | ||
} | ||
else { | ||
field = createField(); | ||
} | ||
return field; | ||
} | ||
function syncFormMessages(type, fieldState) { | ||
var name = fieldState.name, path = fieldState.path; | ||
var messages = fieldState[type]; | ||
state.setSourceState(function (state) { | ||
var foundField = false; | ||
state[type] = state[type] || []; | ||
state[type] = state[type].reduce(function (buf, item) { | ||
if (item.path === path) { | ||
foundField = true; | ||
return messages.length ? buf.concat({ path: path, messages: messages }) : buf; | ||
} | ||
else { | ||
return buf.concat(item); | ||
} | ||
}, []); | ||
if (!foundField && messages.length) { | ||
state[type].push({ | ||
name: name, | ||
path: path, | ||
messages: messages | ||
}); | ||
} | ||
if (state.errors.length) { | ||
state.invalid = true; | ||
state.valid = false; | ||
} | ||
else { | ||
state.invalid = false; | ||
state.valid = true; | ||
} | ||
}); | ||
} | ||
function transformDataPath(path) { | ||
var newPath = shared_1.FormPath.getPath(path); | ||
return newPath.reduce(function (path, key, index) { | ||
if (index >= newPath.length - 1) | ||
return path.concat([key]); | ||
var realPath = newPath.slice(0, index + 1); | ||
var dataPath = path.concat([key]); | ||
var selected = graph.get(realPath); | ||
if (types_1.isVirtualField(selected)) { | ||
return path; | ||
} | ||
return dataPath; | ||
}, shared_1.FormPath.getPath('')); | ||
} | ||
function setFormIn(path, key, value, silent) { | ||
state.setState(function (state) { | ||
shared_1.FormPath.setIn(state[key], transformDataPath(path), value); | ||
}, silent); | ||
} | ||
function deleteFormIn(path, key, silent) { | ||
state.setState(function (state) { | ||
shared_1.FormPath.deleteIn(state[key], transformDataPath(path)); | ||
}, silent); | ||
} | ||
function deleteFormValuesIn(path, silent) { | ||
deleteFormIn(path, 'values', silent); | ||
} | ||
function setFormValuesIn(path, value, silent) { | ||
return setFormIn(path, 'values', value, silent); | ||
} | ||
function setFormInitialValuesIn(path, value, silent) { | ||
return setFormIn(path, 'initialValues', value, silent); | ||
} | ||
function getFormIn(path, key) { | ||
return state.getState(function (state) { | ||
return shared_1.FormPath.getIn(state[key], transformDataPath(path)); | ||
}); | ||
} | ||
function getFormValuesIn(path) { | ||
return getFormIn(path, 'values'); | ||
} | ||
function existFormValuesIn(path) { | ||
return state.getState(function (state) { | ||
return shared_1.FormPath.existIn(state.values, transformDataPath(path)); | ||
}); | ||
} | ||
function getFormInitialValuesIn(path) { | ||
return getFormIn(path, 'initialValues'); | ||
} | ||
function createMutators(field) { | ||
if (!types_1.isField(field)) { | ||
throw new Error('The `createMutators` can only accept FieldState instance.'); | ||
} | ||
function setValue() { | ||
var values = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
values[_i] = arguments[_i]; | ||
} | ||
field.setState(function (state) { | ||
state.value = values[0]; | ||
state.values = values; | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_INPUT_CHANGE, field); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_INPUT_CHANGE, state); | ||
} | ||
function removeValue(key) { | ||
var nodePath = field.getSourceState(function (state) { return state.path; }); | ||
if (shared_1.isValid(key)) { | ||
var childNodePath = shared_1.FormPath.parse(nodePath).concat(key); | ||
env.userUpdateFields.push(nodePath); | ||
env.removeNodes[childNodePath.toString()] = true; | ||
deleteFormValuesIn(childNodePath); | ||
field.notify(field.getState()); | ||
env.userUpdateFields.pop(); | ||
} | ||
else { | ||
var parent_1 = graph.selectParent(nodePath); | ||
env.removeNodes[nodePath.toString()] = true; | ||
var parentNodePath = parent_1 && parent_1.getSourceState(function (state) { return state.path; }); | ||
if (parentNodePath) { | ||
env.userUpdateFields.push(parentNodePath); | ||
} | ||
else { | ||
env.userUpdateFields.push(nodePath); | ||
} | ||
deleteFormValuesIn(nodePath); | ||
if (parent_1) { | ||
parent_1.notify(parent_1.getState()); | ||
} | ||
env.userUpdateFields.pop(); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_VALUE_CHANGE, field); | ||
heart.publish(types_1.LifeCycleTypes.ON_FIELD_INPUT_CHANGE, field); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_INPUT_CHANGE, state); | ||
} | ||
function getValue() { | ||
return field.getSourceState(function (state) { return state.value; }); | ||
} | ||
return { | ||
change: function () { | ||
var values = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
values[_i] = arguments[_i]; | ||
} | ||
setValue.apply(void 0, values); | ||
return values[0]; | ||
}, | ||
focus: function () { | ||
field.setState(function (state) { | ||
state.active = true; | ||
}); | ||
}, | ||
blur: function () { | ||
field.setState(function (state) { | ||
state.active = false; | ||
state.visited = true; | ||
}); | ||
}, | ||
push: function (value) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
arr.push(value); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
pop: function () { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
arr.pop(); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
insert: function (index, value) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
arr.splice(index, 0, value); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
remove: function (index) { | ||
var val = getValue(); | ||
if (shared_1.isNum(index) && shared_1.isArr(val)) { | ||
val = [].concat(val); | ||
val.splice(index, 1); | ||
setValue(val); | ||
} | ||
else { | ||
removeValue(index); | ||
} | ||
}, | ||
exist: function (index) { | ||
var newPath = field.getSourceState(function (state) { | ||
return shared_1.FormPath.parse(state.path); | ||
}); | ||
var val = getValue(); | ||
return (shared_1.isValid(index) ? newPath.concat(index) : newPath).existIn(val, newPath); | ||
}, | ||
unshift: function (value) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
arr.unshift(value); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
shift: function () { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
arr.shift(); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
move: function ($from, $to) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
var item = arr[$from]; | ||
arr.splice($from, 1); | ||
arr.splice($to, 0, item); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
moveUp: function (index) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
var item = arr[index]; | ||
var len = arr.length; | ||
arr.splice(index, 1); | ||
arr.splice(index - 1 < 0 ? len - 1 : index - 1, 0, item); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
moveDown: function (index) { | ||
var arr = shared_1.toArr(getValue()).slice(); | ||
var item = arr[index]; | ||
var len = arr.length; | ||
arr.splice(index, 1); | ||
arr.splice(index + 1 > len ? 0 : index + 1, 0, item); | ||
setValue(arr); | ||
return arr; | ||
}, | ||
validate: function (opts) { | ||
return validate(field.getSourceState(function (state) { return state.path; }), opts); | ||
} | ||
}; | ||
} | ||
function clearErrors(pattern) { | ||
if (pattern === void 0) { pattern = '*'; } | ||
graph.eachChildren('', pattern, function (field) { | ||
if (types_1.isField(field)) { | ||
field.setState(function (state) { | ||
state.ruleErrors = []; | ||
state.ruleWarnings = []; | ||
state.effectErrors = []; | ||
state.effectWarnings = []; | ||
}); | ||
} | ||
}); | ||
} | ||
function reset(_a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.selector, selector = _c === void 0 ? '*' : _c, _d = _b.forceClear, forceClear = _d === void 0 ? false : _d, _e = _b.validate, validate = _e === void 0 ? true : _e, _f = _b.clearInitialValue, clearInitialValue = _f === void 0 ? false : _f; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var validateResult; | ||
return __generator(this, function (_g) { | ||
switch (_g.label) { | ||
case 0: | ||
graph.eachChildren('', selector, function (field) { | ||
field.setState(function (state) { | ||
state.modified = false; | ||
state.ruleErrors = []; | ||
state.ruleWarnings = []; | ||
state.effectErrors = []; | ||
state.effectWarnings = []; | ||
if (clearInitialValue) { | ||
state.initialValue = undefined; | ||
} | ||
if (forceClear || !shared_1.isValid(state.initialValue)) { | ||
if (shared_1.isArr(state.value)) { | ||
state.value = []; | ||
} | ||
else if (!shared_1.isObj(state.value)) { | ||
state.value = undefined; | ||
} | ||
} | ||
else { | ||
var value = shared_1.clone(state.initialValue); | ||
if (shared_1.isArr(state.value)) { | ||
if (shared_1.isArr(value)) { | ||
state.value = value; | ||
} | ||
else { | ||
state.value = []; | ||
} | ||
} | ||
else if (shared_1.isObj(state.value)) { | ||
if (shared_1.isObj(value)) { | ||
state.value = value; | ||
} | ||
else { | ||
state.value = {}; | ||
} | ||
} | ||
else { | ||
state.value = value; | ||
} | ||
} | ||
}); | ||
}); | ||
if (shared_1.isFn(options.onReset)) { | ||
options.onReset(); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_RESET, state); | ||
if (!validate) return [3, 2]; | ||
return [4, formApi.validate(selector, { throwErrors: false })]; | ||
case 1: | ||
validateResult = _g.sent(); | ||
_g.label = 2; | ||
case 2: return [2, validateResult]; | ||
} | ||
}); | ||
}); | ||
} | ||
function submit(onSubmit) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
if (state.getState(function (state) { return state.submitting; })) | ||
return [2, env.submittingTask]; | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_START, state); | ||
onSubmit = onSubmit || options.onSubmit; | ||
state.setState(function (state) { | ||
state.submitting = true; | ||
}); | ||
env.submittingTask = function () { return __awaiter(_this, void 0, void 0, function () { | ||
var validated, errors, payload, values, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_START, state); | ||
return [4, validate('', { throwErrors: false })]; | ||
case 1: | ||
_a.sent(); | ||
validated = state.getState(function (state) { return ({ | ||
errors: state.errors, | ||
warnings: state.warnings | ||
}); }); | ||
errors = validated.errors; | ||
if (errors.length) { | ||
state.setState(function (state) { | ||
state.submitting = false; | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_FAILED, state); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_END, state); | ||
if (shared_1.isFn(options.onValidateFailed)) { | ||
options.onValidateFailed(validated); | ||
} | ||
throw errors; | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_SUCCESS, state); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT, state); | ||
values = state.getState(function (state) { return shared_1.clone(state.values); }); | ||
if (!shared_1.isFn(onSubmit)) return [3, 5]; | ||
_a.label = 2; | ||
case 2: | ||
_a.trys.push([2, 4, , 5]); | ||
return [4, Promise.resolve(onSubmit(values))]; | ||
case 3: | ||
payload = _a.sent(); | ||
return [3, 5]; | ||
case 4: | ||
e_1 = _a.sent(); | ||
new Promise(function () { | ||
throw e_1; | ||
}); | ||
return [3, 5]; | ||
case 5: | ||
state.setState(function (state) { | ||
state.submitting = false; | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_SUBMIT_END, state); | ||
return [2, { | ||
values: values, | ||
validated: validated, | ||
payload: payload | ||
}]; | ||
} | ||
}); | ||
}); }; | ||
return [2, env.submittingTask()]; | ||
}); | ||
}); | ||
} | ||
function validate(path, opts) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _a, throwErrors, payload, result, errors, warnings; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_a = (opts || {}).throwErrors, throwErrors = _a === void 0 ? true : _a; | ||
if (!state.getState(function (state) { return state.validating; })) { | ||
state.setSourceState(function (state) { | ||
state.validating = true; | ||
}); | ||
clearTimeout(env.validateTimer); | ||
env.validateTimer = setTimeout(function () { | ||
state.notify(); | ||
}, 60); | ||
} | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_VALIDATE_START, state); | ||
return [4, validator.validate(path, opts)]; | ||
case 1: | ||
payload = _b.sent(); | ||
clearTimeout(env.validateTimer); | ||
state.setState(function (state) { | ||
state.validating = false; | ||
}); | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_VALIDATE_END, state); | ||
result = { | ||
errors: payload.errors.map(function (item) { return (__assign(__assign({}, item), { name: getFieldState(item.path).name })); }), | ||
warnings: payload.warnings.map(function (item) { return (__assign(__assign({}, item), { name: getFieldState(item.path).name })); }) | ||
}; | ||
errors = result.errors, warnings = result.warnings; | ||
if (warnings.length) { | ||
console.warn(warnings); | ||
} | ||
if (errors.length > 0) { | ||
if (throwErrors) { | ||
throw result; | ||
} | ||
else { | ||
return [2, result]; | ||
} | ||
} | ||
else { | ||
return [2, result]; | ||
} | ||
return [2]; | ||
} | ||
}); | ||
}); | ||
} | ||
function setFormState(callback, silent) { | ||
env.leadingStage = true; | ||
state.setState(callback, silent); | ||
env.leadingStage = false; | ||
} | ||
function getFormState(callback) { | ||
return state.getState(callback); | ||
} | ||
function batchRunTaskQueue(field, nodePath) { | ||
for (var index = 0; index < env.taskQueue.length; index++) { | ||
var _a = env.taskQueue[index], pattern = _a.pattern, callbacks = _a.callbacks; | ||
var removed = false; | ||
if (matchStrategy(pattern, nodePath)) { | ||
callbacks.forEach(function (callback) { | ||
field.setState(callback); | ||
}); | ||
if (!pattern.isWildMatchPattern && !pattern.isMatchPattern) { | ||
env.taskQueue.splice(index--, 1); | ||
removed = true; | ||
} | ||
} | ||
if (!removed) { | ||
env.taskIndexes[pattern.toString()] = index; | ||
} | ||
else { | ||
delete env.taskIndexes[pattern.toString()]; | ||
} | ||
} | ||
} | ||
function setFieldState(path, callback, silent) { | ||
if (!shared_1.isFn(callback)) | ||
return; | ||
var matchCount = 0; | ||
var pattern = shared_1.FormPath.getPath(path); | ||
graph.select(pattern, function (field) { | ||
field.setState(callback, silent); | ||
matchCount++; | ||
}); | ||
if (matchCount === 0 || pattern.isWildMatchPattern) { | ||
var taskIndex = env.taskIndexes[pattern.toString()]; | ||
if (shared_1.isValid(taskIndex)) { | ||
if (env.taskQueue[taskIndex] && | ||
!env.taskQueue[taskIndex].callbacks.some(function (fn) { return shared_1.isEqual(fn, callback); })) { | ||
env.taskQueue[taskIndex].callbacks.push(callback); | ||
} | ||
} | ||
else { | ||
env.taskIndexes[pattern.toString()] = env.taskQueue.length; | ||
env.taskQueue.push({ | ||
pattern: pattern, | ||
callbacks: [callback] | ||
}); | ||
} | ||
} | ||
} | ||
function userUpdating(field, fn) { | ||
if (!field) | ||
return; | ||
var nodePath = field.state.path; | ||
if (nodePath) | ||
env.userUpdateFields.push(nodePath); | ||
if (shared_1.isFn(fn)) { | ||
fn(); | ||
} | ||
env.userUpdateFields.pop(); | ||
} | ||
function setFieldValue(path, value, silent) { | ||
setFieldState(path, function (state) { | ||
state.value = value; | ||
}, silent); | ||
} | ||
function getFieldValue(path) { | ||
return getFieldState(path, function (state) { | ||
return state.value; | ||
}); | ||
} | ||
function setFieldInitialValue(path, value, silent) { | ||
setFieldState(path, function (state) { | ||
state.initialValue = value; | ||
}, silent); | ||
} | ||
function getFieldInitialValue(path) { | ||
return getFieldState(path, function (state) { | ||
return state.initialValue; | ||
}); | ||
} | ||
function getFieldState(path, callback) { | ||
var field = graph.select(path); | ||
return field && field.getState(callback); | ||
} | ||
function getFormGraph() { | ||
return graph.map(function (node) { | ||
return node.getState(); | ||
}); | ||
} | ||
function setFormGraph(nodes) { | ||
shared_1.each(nodes, function (node, key) { | ||
var nodeState; | ||
if (graph.exist(key)) { | ||
nodeState = graph.get(key); | ||
nodeState.setSourceState(function (state) { | ||
Object.assign(state, node); | ||
}); | ||
} | ||
else { | ||
if (node.displayName === 'VirtualFieldState') { | ||
nodeState = registerVirtualField({ | ||
path: key | ||
}); | ||
nodeState.setSourceState(function (state) { | ||
Object.assign(state, node); | ||
}); | ||
} | ||
else if (node.displayName === 'FieldState') { | ||
nodeState = registerField({ | ||
path: key | ||
}); | ||
nodeState.setSourceState(function (state) { | ||
Object.assign(state, node); | ||
}); | ||
} | ||
} | ||
if (nodeState) { | ||
nodeState.notify(state.getState()); | ||
} | ||
}); | ||
} | ||
function matchStrategy(pattern, nodePath) { | ||
var matchPattern = shared_1.FormPath.parse(pattern); | ||
var node = graph.get(nodePath); | ||
if (!node) | ||
return false; | ||
return node.getSourceState(function (state) { | ||
return matchPattern.matchAliasGroup(state.name, state.path); | ||
}); | ||
} | ||
function hasChanged(target, path) { | ||
if (env.publishing[target ? target.path : ''] === false) { | ||
throw new Error('The watch function must be used synchronously in the subscribe callback.'); | ||
} | ||
if (types_1.isFormState(target)) { | ||
return state.hasChanged(path); | ||
} | ||
else if (types_1.isFieldState(target) || types_1.isVirtualFieldState(target)) { | ||
var node = graph.get(target.path); | ||
return node && node.hasChanged(path); | ||
} | ||
else { | ||
throw new Error('Illegal parameter,You must pass the correct state object(FormState/FieldState/VirtualFieldState).'); | ||
} | ||
} | ||
var state = new form_1.FormState(options); | ||
var validator = new validator_1.FormValidator(__assign(__assign({}, options), { matchStrategy: matchStrategy })); | ||
var graph = new graph_1.FormGraph({ | ||
matchStrategy: matchStrategy | ||
}); | ||
var applyWithScheduler = shared_1.scheduler(options.validateConcurrentTimeMS); | ||
var formApi = { | ||
submit: submit, | ||
reset: reset, | ||
hasChanged: hasChanged, | ||
clearErrors: clearErrors, | ||
validate: validate, | ||
setFormState: setFormState, | ||
getFormState: getFormState, | ||
setFieldState: setFieldState, | ||
getFieldState: getFieldState, | ||
registerField: registerField, | ||
registerVirtualField: registerVirtualField, | ||
createMutators: createMutators, | ||
getFormGraph: getFormGraph, | ||
setFormGraph: setFormGraph, | ||
setFieldValue: setFieldValue, | ||
unsafe_do_not_use_transform_data_path: transformDataPath, | ||
getFieldValue: getFieldValue, | ||
setFieldInitialValue: setFieldInitialValue, | ||
getFieldInitialValue: getFieldInitialValue, | ||
subscribe: function (callback) { | ||
return heart.subscribe(callback); | ||
}, | ||
unsubscribe: function (id) { | ||
heart.unsubscribe(id); | ||
}, | ||
notify: function (type, payload) { | ||
heart.publish(type, payload); | ||
} | ||
}; | ||
var heart = new lifecycle_1.FormHeart(__assign(__assign({}, options), { context: formApi, beforeNotify: function (payload) { | ||
env.publishing[payload.path || ''] = true; | ||
}, afterNotify: function (payload) { | ||
env.publishing[payload.path || ''] = false; | ||
} })); | ||
var env = { | ||
validateTimer: null, | ||
graphChangeTimer: null, | ||
leadingStage: false, | ||
publishing: {}, | ||
taskQueue: [], | ||
userUpdateFields: [], | ||
taskIndexes: {}, | ||
removeNodes: {}, | ||
hiddenPendingFields: {}, | ||
lastShownStates: {}, | ||
submittingTask: undefined | ||
}; | ||
heart.publish(types_1.LifeCycleTypes.ON_FORM_WILL_INIT, state); | ||
state.subscription = { | ||
notify: onFormChange | ||
}; | ||
graph.appendNode('', state); | ||
state.setState(function (state) { | ||
state.initialized = true; | ||
}); | ||
graph.subscribe(onGraphChange); | ||
return formApi; | ||
} | ||
exports.createForm = createForm; | ||
exports.registerValidationFormats = validator_1.FormValidator.registerFormats; | ||
exports.registerValidationRules = validator_1.FormValidator.registerRules; | ||
exports.registerValidationMTEngine = validator_1.FormValidator.registerMTEngine; | ||
exports.default = createForm; | ||
module.exports = require('@formily/core'); |
{ | ||
"name": "@uform/core", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"license": "MIT", | ||
@@ -29,5 +29,3 @@ "main": "lib", | ||
"dependencies": { | ||
"@uform/shared": "^1.0.1", | ||
"@uform/validator": "^1.0.1", | ||
"immer": "^3.2.0" | ||
"@formily/core": "^1.0.0" | ||
}, | ||
@@ -37,3 +35,3 @@ "publishConfig": { | ||
}, | ||
"gitHead": "46762a5ba39888e079cf6382c26a66bcc3810d5d" | ||
"gitHead": "2ab41cefdf4ff449bb597d5c540c1e053a5f6fb1" | ||
} |
1297
src/index.ts
@@ -1,1296 +0,1 @@ | ||
import { | ||
isFn, | ||
isEqual, | ||
toArr, | ||
isNum, | ||
isArr, | ||
clone, | ||
isValid, | ||
FormPath, | ||
FormPathPattern, | ||
each, | ||
isObj, | ||
scheduler | ||
} from '@uform/shared' | ||
import { | ||
FormValidator, | ||
setValidationLanguage, | ||
setValidationLocale | ||
} from '@uform/validator' | ||
import { FormHeart } from './shared/lifecycle' | ||
import { FormGraph } from './shared/graph' | ||
import { FormState } from './state/form' | ||
import { VirtualFieldState } from './state/virtual-field' | ||
import { FieldState } from './state/field' | ||
import { | ||
IFormState, | ||
IFieldState, | ||
IVirtualFieldState, | ||
IFormCreatorOptions, | ||
IFieldStateProps, | ||
IVirtualFieldStateProps, | ||
IForm, | ||
IFormSubmitResult, | ||
IFormValidateResult, | ||
IFormResetOptions, | ||
IField, | ||
IVirtualField, | ||
isField, | ||
FormHeartSubscriber, | ||
LifeCycleTypes, | ||
isVirtualField, | ||
isFormState, | ||
isFieldState, | ||
isVirtualFieldState, | ||
IFormExtendedValidateFieldOptions | ||
} from './types' | ||
export * from './shared/lifecycle' | ||
export * from './types' | ||
export function createForm<FieldProps, VirtualFieldProps>( | ||
options: IFormCreatorOptions = {} | ||
): IForm { | ||
function onGraphChange({ type, payload }) { | ||
heart.publish(LifeCycleTypes.ON_FORM_GRAPH_CHANGE, graph) | ||
if (type === 'GRAPH_NODE_WILL_UNMOUNT') { | ||
validator.unregister(payload.path.toString()) | ||
} | ||
} | ||
function syncFieldValues(state: IFieldState) { | ||
const dataPath = FormPath.parse(state.name) | ||
const parent = graph.getLatestParent(state.path) | ||
const parentValue = getFormValuesIn(parent.path) | ||
const value = getFormValuesIn(state.name) | ||
/** | ||
* https://github.com/alibaba/uform/issues/267 dynamic remove node | ||
*/ | ||
let removed = false | ||
if (isArr(parentValue) && !dataPath.existIn(parentValue, parent.path)) { | ||
if ( | ||
!parent.path | ||
.getNearestChildPathBy(state.path) | ||
.existIn(parentValue, parent.path) | ||
) { | ||
graph.remove(state.path) | ||
removed = true | ||
} | ||
} else { | ||
each(env.removeNodes, (_, name) => { | ||
if (dataPath.includes(name)) { | ||
graph.remove(state.path) | ||
delete env.removeNodes[name] | ||
removed = true | ||
} | ||
}) | ||
} | ||
if (removed) return | ||
if (!isEqual(value, state.value)) { | ||
state.value = value | ||
} | ||
} | ||
function syncFieldIntialValues(state: IFieldState) { | ||
const initialValue = getFormInitialValuesIn(state.name) | ||
if (!isEqual(initialValue, state.initialValue)) { | ||
state.initialValue = initialValue | ||
if (!isValid(state.value)) { | ||
state.value = initialValue | ||
} else if ( | ||
/array/gi.test(state.dataType) && | ||
state.value && | ||
state.value.length === 0 | ||
) { | ||
state.value = initialValue | ||
} | ||
} | ||
} | ||
function onFormChange(published: IFormState) { | ||
heart.publish(LifeCycleTypes.ON_FORM_CHANGE, state) | ||
const valuesChanged = state.isDirty('values') | ||
const initialValuesChanged = state.isDirty('initialValues') | ||
const unmountedChanged = state.isDirty('unmounted') | ||
const mountedChanged = state.isDirty('mounted') | ||
const initializedChanged = state.isDirty('initialized') | ||
const editableChanged = state.isDirty('editable') | ||
if (valuesChanged || initialValuesChanged) { | ||
const updateFields = (field: IField | IVirtualField) => { | ||
if (isField(field)) { | ||
field.setState(state => { | ||
if (state.visible || state.unmounted) { | ||
if (valuesChanged) { | ||
syncFieldValues(state) | ||
} | ||
if (initialValuesChanged) { | ||
syncFieldIntialValues(state) | ||
} | ||
} else { | ||
//缓存变化,等字段重新显示的时候再执行 | ||
if (valuesChanged) { | ||
env.hiddenPendingFields[state.name] = | ||
env.hiddenPendingFields[state.name] || {} | ||
env.hiddenPendingFields[state.name].values = true | ||
} | ||
if (initialValuesChanged) { | ||
env.hiddenPendingFields[state.name] = | ||
env.hiddenPendingFields[state.name] || {} | ||
env.hiddenPendingFields[state.name].initialValues = true | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
if (valuesChanged || initialValuesChanged) { | ||
if (!env.leadingStage) { | ||
const userUpdateFieldPath = | ||
env.userUpdateFields[env.userUpdateFields.length - 1] | ||
/* | ||
* 考虑初始化的时候还没生成节点树 | ||
* 两种数据同步策略, | ||
* 1. 精确更新的时候(mutators/setFieldState),只遍历父节点与子节点,同时父节点静默处理,子节点通知渲染 | ||
* 2. setFormState批量更新的时候,是会遍历所有节点,同时所有节点只要有变化就会被通知 | ||
*/ | ||
if (userUpdateFieldPath && graph.get(userUpdateFieldPath)) { | ||
graph.eachParentAndChildren(userUpdateFieldPath, updateFields) | ||
} else { | ||
graph.eachChildren(updateFields) | ||
} | ||
} else { | ||
graph.eachChildren(updateFields) | ||
} | ||
} | ||
if (valuesChanged) { | ||
if (isFn(options.onChange)) { | ||
options.onChange(clone(published.values)) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FORM_VALUES_CHANGE, state) | ||
} | ||
if (initialValuesChanged) { | ||
heart.publish(LifeCycleTypes.ON_FORM_INITIAL_VALUES_CHANGE, state) | ||
} | ||
} | ||
if (editableChanged) { | ||
graph.eachChildren((field: IField | IVirtualField) => { | ||
if (isField(field)) { | ||
field.setState(state => { | ||
state.formEditable = published.editable | ||
}) | ||
} | ||
}) | ||
} | ||
if (unmountedChanged && published.unmounted) { | ||
heart.publish(LifeCycleTypes.ON_FORM_UNMOUNT, state) | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(LifeCycleTypes.ON_FORM_MOUNT, state) | ||
} | ||
if (initializedChanged) { | ||
heart.publish(LifeCycleTypes.ON_FORM_INIT, state) | ||
} | ||
} | ||
function updateRecoverableShownState( | ||
parentState: | ||
| IVirtualFieldState<VirtualFieldProps> | ||
| IFieldState<FieldProps>, | ||
childState: IVirtualFieldState<VirtualFieldProps> | IFieldState<FieldProps>, | ||
name: 'visible' | 'display' | ||
) { | ||
const lastShownState = env.lastShownStates[childState.path] | ||
const lastStateValue = childState[name] | ||
if (parentState[name] && lastShownState && lastShownState[name] === false) { | ||
childState[name] = false | ||
delete lastShownState[name] | ||
if ( | ||
!lastShownState.hasOwnProperty('visible') && | ||
!lastShownState.hasOwnProperty('display') | ||
) { | ||
delete env.lastShownStates[childState.path] | ||
} | ||
} else { | ||
childState[name] = parentState[name] | ||
} | ||
if (!parentState[name] && !lastStateValue) { | ||
if (!lastShownState) { | ||
env.lastShownStates[childState.path] = {} | ||
} | ||
env.lastShownStates[childState.path][name] = false | ||
} | ||
} | ||
function onFieldChange({ field, path }) { | ||
return (published: IFieldState<FieldProps>) => { | ||
const valueChanged = field.isDirty('value') | ||
const initialValueChanged = field.isDirty('initialValue') | ||
const visibleChanged = field.isDirty('visible') | ||
const displayChanged = field.isDirty('display') | ||
const unmountedChanged = field.isDirty('unmounted') | ||
const mountedChanged = field.isDirty('mounted') | ||
const initializedChanged = field.isDirty('initialized') | ||
const warningsChanged = field.isDirty('warnings') | ||
const errorsChanged = field.isDirty('errors') | ||
const userUpdateFieldPath = | ||
env.userUpdateFields[env.userUpdateFields.length - 1] | ||
const syncField = () => { | ||
if (env.hiddenPendingFields[published.name]) { | ||
field.setState((state: IFieldState) => { | ||
if (env.hiddenPendingFields[state.name].values) { | ||
syncFieldValues(state) | ||
} | ||
if (env.hiddenPendingFields[state.name].initialValues) { | ||
syncFieldIntialValues(state) | ||
} | ||
delete env.hiddenPendingFields[state.name] | ||
}) | ||
} | ||
} | ||
const notifyFormValuesChange = () => { | ||
if (isFn(options.onChange)) { | ||
options.onChange(state.getSourceState(state => clone(state.values))) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FORM_VALUES_CHANGE, state) | ||
} | ||
if (initializedChanged) { | ||
heart.publish(LifeCycleTypes.ON_FIELD_INIT, field) | ||
const isEmptyValue = !isValid(published.value) | ||
const isEmptyInitialValue = !isValid(published.initialValue) | ||
if (isEmptyValue || isEmptyInitialValue) { | ||
field.setSourceState((state: IFieldState<FieldProps>) => { | ||
if (isEmptyValue) state.value = getFormValuesIn(state.name) | ||
if (isEmptyInitialValue) | ||
state.initialValue = getFormInitialValuesIn(state.name) | ||
}) | ||
} | ||
} | ||
const wasHidden = | ||
published.visible == false || published.unmounted === true | ||
if (valueChanged) { | ||
if (!wasHidden) { | ||
userUpdating(field, () => { | ||
setFormValuesIn(path, published.value) | ||
}) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_VALUE_CHANGE, field) | ||
} | ||
if (initialValueChanged) { | ||
if (!wasHidden) { | ||
setFormInitialValuesIn(path, published.initialValue) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_INITIAL_VALUE_CHANGE, field) | ||
} | ||
if (displayChanged || visibleChanged) { | ||
if (visibleChanged) { | ||
userUpdating(field, () => { | ||
if (!published.visible) { | ||
deleteFormValuesIn(path, true) | ||
//考虑到隐藏删值,不应该同步子树,但是需要触发表单变化事件 | ||
notifyFormValuesChange() | ||
} else { | ||
setFormValuesIn(path, published.value) | ||
syncField() | ||
} | ||
}) | ||
} | ||
graph.eachChildren(path, childState => { | ||
childState.setState((state: IFieldState<FieldProps>) => { | ||
if (visibleChanged) { | ||
updateRecoverableShownState(published, state, 'visible') | ||
} | ||
if (displayChanged) { | ||
updateRecoverableShownState(published, state, 'display') | ||
} | ||
}, true) | ||
}) | ||
} | ||
if ( | ||
unmountedChanged && | ||
(published.display !== false || published.visible === false) | ||
) { | ||
userUpdating(field, () => { | ||
if (published.unmounted) { | ||
deleteFormValuesIn(path, true) | ||
//考虑到隐藏删值,不应该同步子树,但是需要触发表单变化事件 | ||
notifyFormValuesChange() | ||
} else { | ||
setFormValuesIn(path, published.value) | ||
syncField() | ||
} | ||
}) | ||
heart.publish(LifeCycleTypes.ON_FIELD_UNMOUNT, field) | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(LifeCycleTypes.ON_FIELD_MOUNT, field) | ||
} | ||
if (errorsChanged) { | ||
syncFormMessages('errors', published) | ||
} | ||
if (warningsChanged) { | ||
syncFormMessages('warnings', published) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_CHANGE, field) | ||
if (userUpdateFieldPath && !env.leadingStage) { | ||
if (FormPath.parse(path).match(userUpdateFieldPath)) { | ||
return | ||
} | ||
if (FormPath.parse(userUpdateFieldPath).includes(path)) { | ||
return false | ||
} | ||
} | ||
} | ||
} | ||
function onVirtualFieldChange({ field, path }) { | ||
return (published: IVirtualFieldState<VirtualFieldProps>) => { | ||
const visibleChanged = field.isDirty('visible') | ||
const displayChanged = field.isDirty('display') | ||
const mountedChanged = field.isDirty('mounted') | ||
const initializedChanged = field.isDirty('initialized') | ||
if (initializedChanged) { | ||
heart.publish(LifeCycleTypes.ON_FIELD_INIT, field) | ||
} | ||
if (visibleChanged || displayChanged) { | ||
graph.eachChildren(path, childState => { | ||
childState.setState( | ||
(state: IVirtualFieldState<VirtualFieldProps>) => { | ||
if (visibleChanged) { | ||
updateRecoverableShownState(published, state, 'visible') | ||
} | ||
if (displayChanged) { | ||
updateRecoverableShownState(published, state, 'display') | ||
} | ||
}, | ||
true | ||
) | ||
}) | ||
} | ||
if (mountedChanged && published.mounted) { | ||
heart.publish(LifeCycleTypes.ON_FIELD_MOUNT, field) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_CHANGE, field) | ||
} | ||
} | ||
function registerVirtualField({ | ||
name, | ||
path, | ||
props, | ||
display, | ||
visible, | ||
computeState, | ||
useDirty | ||
}: IVirtualFieldStateProps): IVirtualField { | ||
let nodePath = FormPath.parse(path || name) | ||
let dataPath = transformDataPath(nodePath) | ||
let field: IVirtualField | ||
const createField = (field?: IVirtualField) => { | ||
const alreadyHaveField = !!field | ||
field = | ||
field || | ||
new VirtualFieldState({ | ||
nodePath, | ||
dataPath, | ||
computeState, | ||
useDirty: isValid(useDirty) ? useDirty : options.useDirty | ||
}) | ||
field.subscription = { | ||
notify: onVirtualFieldChange({ field, path: nodePath }) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_WILL_INIT, field) | ||
if (!alreadyHaveField) { | ||
graph.appendNode(nodePath, field) | ||
} | ||
field.batch(() => { | ||
field.setState((state: IVirtualFieldState<VirtualFieldProps>) => { | ||
state.initialized = true | ||
state.props = props | ||
if (isValid(visible)) { | ||
state.visible = visible | ||
} | ||
if (isValid(display)) { | ||
state.display = display | ||
} | ||
}) | ||
batchRunTaskQueue(field, nodePath) | ||
}) | ||
return field | ||
} | ||
if (graph.exist(nodePath)) { | ||
field = graph.get(nodePath) | ||
//field = createField(field) 如果重置会导致#565的问题,目前还没想清楚不重置会有啥问题 | ||
if (isField(field)) { | ||
graph.replace(nodePath, field) | ||
} | ||
} else { | ||
field = createField() | ||
} | ||
return field | ||
} | ||
function registerField({ | ||
path, | ||
name, | ||
value, | ||
initialValue, | ||
required, | ||
rules, | ||
editable, | ||
visible, | ||
display, | ||
computeState, | ||
dataType, | ||
useDirty, | ||
props | ||
}: Exclude<IFieldStateProps, 'dataPath' | 'nodePath'>): IField { | ||
let field: IField | ||
let nodePath = FormPath.parse(path || name) | ||
let dataPath = transformDataPath(nodePath) | ||
const createField = (field?: IField) => { | ||
const alreadyHaveField = !!field | ||
field = | ||
field || | ||
new FieldState({ | ||
nodePath, | ||
dataPath, | ||
computeState, | ||
dataType, | ||
useDirty: isValid(useDirty) ? useDirty : options.useDirty | ||
}) | ||
field.subscription = { | ||
notify: onFieldChange({ field, path: nodePath }) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_WILL_INIT, field) | ||
if (!alreadyHaveField) { | ||
graph.appendNode(nodePath, field) | ||
} | ||
field.batch(() => { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
const formValue = getFormValuesIn(dataPath) | ||
const formInitialValue = getFormInitialValuesIn(dataPath) | ||
if (isValid(value)) { | ||
// value > formValue > initialValue | ||
state.value = value | ||
} else { | ||
state.value = existFormValuesIn(dataPath) ? formValue : initialValue | ||
} | ||
// initialValue > formInitialValue | ||
state.initialValue = isValid(initialValue) | ||
? initialValue | ||
: formInitialValue | ||
if (isValid(visible)) { | ||
state.visible = visible | ||
} | ||
if (isValid(display)) { | ||
state.display = display | ||
} | ||
if (isValid(props)) { | ||
state.props = props | ||
} | ||
if (isValid(required)) { | ||
state.required = required | ||
} | ||
if (isValid(rules)) { | ||
state.rules = rules | ||
} | ||
if (isValid(editable)) { | ||
state.selfEditable = editable | ||
} | ||
if (isValid(options.editable)) { | ||
state.formEditable = options.editable | ||
} | ||
state.initialized = true | ||
}) | ||
batchRunTaskQueue(field, nodePath) | ||
}) | ||
validator.register(nodePath, validate => { | ||
const { | ||
value, | ||
rules, | ||
editable, | ||
visible, | ||
unmounted, | ||
display | ||
} = field.getState() | ||
// 不需要校验的情况有: 非编辑态(editable),已销毁(unmounted), 逻辑上不可见(visible) | ||
if ( | ||
editable === false || | ||
visible === false || | ||
unmounted === true || | ||
display === false | ||
) | ||
return validate(value, []) | ||
clearTimeout((field as any).validateTimer) | ||
;(field as any).validateTimer = setTimeout(() => { | ||
field.setState(state => { | ||
state.validating = true | ||
}) | ||
}, 60) | ||
heart.publish(LifeCycleTypes.ON_FIELD_VALIDATE_START, field) | ||
return validate(value, rules).then(({ errors, warnings }) => { | ||
clearTimeout((field as any).validateTimer) | ||
return new Promise(resolve => { | ||
const syncState = () => { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
state.validating = false | ||
state.ruleErrors = errors | ||
state.ruleWarnings = warnings | ||
}) | ||
heart.publish(LifeCycleTypes.ON_FIELD_VALIDATE_END, field) | ||
resolve({ errors, warnings }) | ||
} | ||
if (graph.size < 100) { | ||
syncState() | ||
} else { | ||
applyWithScheduler(syncState) | ||
} | ||
}) | ||
}) | ||
}) | ||
return field | ||
} | ||
if (graph.exist(nodePath)) { | ||
field = graph.get(nodePath) | ||
//field = createField(field) 如果重置会导致#565的问题,目前还没想清楚不重置会有啥问题 | ||
if (isVirtualField(field)) { | ||
graph.replace(nodePath, field) | ||
} | ||
} else { | ||
field = createField() | ||
} | ||
return field | ||
} | ||
//实时同步Form Messages | ||
function syncFormMessages(type: string, fieldState: IFieldState) { | ||
const { name, path } = fieldState | ||
const messages = fieldState[type] | ||
state.setSourceState(state => { | ||
let foundField = false | ||
state[type] = state[type] || [] | ||
state[type] = state[type].reduce((buf: any, item: any) => { | ||
if (item.path === path) { | ||
foundField = true | ||
return messages.length ? buf.concat({ path, messages }) : buf | ||
} else { | ||
return buf.concat(item) | ||
} | ||
}, []) | ||
if (!foundField && messages.length) { | ||
state[type].push({ | ||
name, | ||
path, | ||
messages | ||
}) | ||
} | ||
if (state.errors.length) { | ||
state.invalid = true | ||
state.valid = false | ||
} else { | ||
state.invalid = false | ||
state.valid = true | ||
} | ||
}) | ||
} | ||
function transformDataPath(path: FormPathPattern) { | ||
const newPath = FormPath.getPath(path) | ||
return newPath.reduce((path: FormPath, key: string, index: number) => { | ||
if (index >= newPath.length - 1) return path.concat([key]) | ||
const realPath = newPath.slice(0, index + 1) | ||
const dataPath = path.concat([key]) | ||
const selected = graph.get(realPath) | ||
if (isVirtualField(selected)) { | ||
return path | ||
} | ||
return dataPath | ||
}, FormPath.getPath('')) | ||
} | ||
function setFormIn( | ||
path: FormPathPattern, | ||
key: string, | ||
value: any, | ||
silent?: boolean | ||
) { | ||
state.setState(state => { | ||
FormPath.setIn(state[key], transformDataPath(path), value) | ||
}, silent) | ||
} | ||
function deleteFormIn(path: FormPathPattern, key: string, silent?: boolean) { | ||
state.setState(state => { | ||
FormPath.deleteIn(state[key], transformDataPath(path)) | ||
}, silent) | ||
} | ||
function deleteFormValuesIn(path: FormPathPattern, silent?: boolean) { | ||
deleteFormIn(path, 'values', silent) | ||
} | ||
function setFormValuesIn( | ||
path: FormPathPattern, | ||
value?: any, | ||
silent?: boolean | ||
) { | ||
return setFormIn(path, 'values', value, silent) | ||
} | ||
function setFormInitialValuesIn( | ||
path: FormPathPattern, | ||
value?: any, | ||
silent?: boolean | ||
) { | ||
return setFormIn(path, 'initialValues', value, silent) | ||
} | ||
function getFormIn(path: FormPathPattern, key?: string) { | ||
return state.getState(state => | ||
FormPath.getIn(state[key], transformDataPath(path)) | ||
) | ||
} | ||
function getFormValuesIn(path: FormPathPattern) { | ||
return getFormIn(path, 'values') | ||
} | ||
function existFormValuesIn(path: FormPathPattern) { | ||
return state.getState(state => | ||
FormPath.existIn(state.values, transformDataPath(path)) | ||
) | ||
} | ||
function getFormInitialValuesIn(path: FormPathPattern) { | ||
return getFormIn(path, 'initialValues') | ||
} | ||
function createMutators(field: IField) { | ||
if (!isField(field)) { | ||
throw new Error( | ||
'The `createMutators` can only accept FieldState instance.' | ||
) | ||
} | ||
function setValue(...values: any[]) { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
state.value = values[0] | ||
state.values = values | ||
}) | ||
heart.publish(LifeCycleTypes.ON_FIELD_INPUT_CHANGE, field) | ||
heart.publish(LifeCycleTypes.ON_FORM_INPUT_CHANGE, state) | ||
} | ||
function removeValue(key: string | number) { | ||
const nodePath = field.getSourceState(state => state.path) | ||
if (isValid(key)) { | ||
const childNodePath = FormPath.parse(nodePath).concat(key) | ||
env.userUpdateFields.push(nodePath) | ||
env.removeNodes[childNodePath.toString()] = true | ||
deleteFormValuesIn(childNodePath) | ||
field.notify(field.getState()) | ||
env.userUpdateFields.pop() | ||
} else { | ||
const parent = graph.selectParent(nodePath) | ||
env.removeNodes[nodePath.toString()] = true | ||
const parentNodePath = | ||
parent && parent.getSourceState(state => state.path) | ||
if (parentNodePath) { | ||
env.userUpdateFields.push(parentNodePath) | ||
} else { | ||
env.userUpdateFields.push(nodePath) | ||
} | ||
deleteFormValuesIn(nodePath) | ||
if (parent) { | ||
parent.notify(parent.getState()) | ||
} | ||
env.userUpdateFields.pop() | ||
} | ||
heart.publish(LifeCycleTypes.ON_FIELD_VALUE_CHANGE, field) | ||
heart.publish(LifeCycleTypes.ON_FIELD_INPUT_CHANGE, field) | ||
heart.publish(LifeCycleTypes.ON_FORM_INPUT_CHANGE, state) | ||
} | ||
function getValue() { | ||
return field.getSourceState(state => state.value) | ||
} | ||
return { | ||
change(...values: any[]) { | ||
setValue(...values) | ||
return values[0] | ||
}, | ||
focus() { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
state.active = true | ||
}) | ||
}, | ||
blur() { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
state.active = false | ||
state.visited = true | ||
}) | ||
}, | ||
push(value?: any) { | ||
const arr = toArr(getValue()).slice() | ||
arr.push(value) | ||
setValue(arr) | ||
return arr | ||
}, | ||
pop() { | ||
const arr = toArr(getValue()).slice() | ||
arr.pop() | ||
setValue(arr) | ||
return arr | ||
}, | ||
insert(index: number, value: any) { | ||
const arr = toArr(getValue()).slice() | ||
arr.splice(index, 0, value) | ||
setValue(arr) | ||
return arr | ||
}, | ||
remove(index?: number | string) { | ||
let val = getValue() | ||
if (isNum(index) && isArr(val)) { | ||
val = [].concat(val) | ||
val.splice(index, 1) | ||
setValue(val) | ||
} else { | ||
removeValue(index) | ||
} | ||
}, | ||
exist(index?: number | string) { | ||
const newPath = field.getSourceState(state => | ||
FormPath.parse(state.path) | ||
) | ||
let val = getValue() | ||
return (isValid(index) ? newPath.concat(index) : newPath).existIn( | ||
val, | ||
newPath | ||
) | ||
}, | ||
unshift(value: any) { | ||
const arr = toArr(getValue()).slice() | ||
arr.unshift(value) | ||
setValue(arr) | ||
return arr | ||
}, | ||
shift() { | ||
const arr = toArr(getValue()).slice() | ||
arr.shift() | ||
setValue(arr) | ||
return arr | ||
}, | ||
move($from: number, $to: number) { | ||
const arr = toArr(getValue()).slice() | ||
const item = arr[$from] | ||
arr.splice($from, 1) | ||
arr.splice($to, 0, item) | ||
setValue(arr) | ||
return arr | ||
}, | ||
moveUp(index: number) { | ||
const arr = toArr(getValue()).slice() | ||
const item = arr[index] | ||
const len = arr.length | ||
arr.splice(index, 1) | ||
arr.splice(index - 1 < 0 ? len - 1 : index - 1, 0, item) | ||
setValue(arr) | ||
return arr | ||
}, | ||
moveDown(index: number) { | ||
const arr = toArr(getValue()).slice() | ||
const item = arr[index] | ||
const len = arr.length | ||
arr.splice(index, 1) | ||
arr.splice(index + 1 > len ? 0 : index + 1, 0, item) | ||
setValue(arr) | ||
return arr | ||
}, | ||
validate(opts?: IFormExtendedValidateFieldOptions) { | ||
return validate( | ||
field.getSourceState(state => state.path), | ||
opts | ||
) | ||
} | ||
} | ||
} | ||
function clearErrors(pattern: FormPathPattern = '*') { | ||
// 1. 指定路径或全部子路径清理 | ||
graph.eachChildren('', pattern, field => { | ||
if (isField(field)) { | ||
field.setState(state => { | ||
state.ruleErrors = [] | ||
state.ruleWarnings = [] | ||
state.effectErrors = [] | ||
state.effectWarnings = [] | ||
}) | ||
} | ||
}) | ||
} | ||
async function reset({ | ||
selector = '*', | ||
forceClear = false, | ||
validate = true, | ||
clearInitialValue = false | ||
}: IFormResetOptions = {}): Promise<void | IFormValidateResult> { | ||
graph.eachChildren('', selector, field => { | ||
field.setState((state: IFieldState<FieldProps>) => { | ||
state.modified = false | ||
state.ruleErrors = [] | ||
state.ruleWarnings = [] | ||
state.effectErrors = [] | ||
state.effectWarnings = [] | ||
if (clearInitialValue) { | ||
state.initialValue = undefined | ||
} | ||
// forceClear仅对设置initialValues的情况下有意义 | ||
if (forceClear || !isValid(state.initialValue)) { | ||
if (isArr(state.value)) { | ||
state.value = [] | ||
} else if (!isObj(state.value)) { | ||
state.value = undefined | ||
} | ||
} else { | ||
const value = clone(state.initialValue) | ||
if (isArr(state.value)) { | ||
if (isArr(value)) { | ||
state.value = value | ||
} else { | ||
state.value = [] | ||
} | ||
} else if (isObj(state.value)) { | ||
if (isObj(value)) { | ||
state.value = value | ||
} else { | ||
state.value = {} | ||
} | ||
} else { | ||
state.value = value | ||
} | ||
} | ||
}) | ||
}) | ||
if (isFn(options.onReset)) { | ||
options.onReset() | ||
} | ||
heart.publish(LifeCycleTypes.ON_FORM_RESET, state) | ||
let validateResult: void | IFormValidateResult | ||
if (validate) { | ||
validateResult = await formApi.validate(selector, { throwErrors: false }) | ||
} | ||
return validateResult | ||
} | ||
async function submit( | ||
onSubmit?: (values: IFormState['values']) => any | Promise<any> | ||
): Promise<IFormSubmitResult> { | ||
// 重复提交,返回前一次的promise | ||
if (state.getState(state => state.submitting)) return env.submittingTask | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_START, state) | ||
onSubmit = onSubmit || options.onSubmit | ||
state.setState(state => { | ||
state.submitting = true | ||
}) | ||
env.submittingTask = async () => { | ||
// 增加onFormSubmitValidateStart来明确submit引起的校验开始了 | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_START, state) | ||
await validate('', { throwErrors: false }) | ||
const validated: IFormValidateResult = state.getState(state => ({ | ||
errors: state.errors, | ||
warnings: state.warnings | ||
})) | ||
const { errors } = validated | ||
// 校验失败 | ||
if (errors.length) { | ||
// 由于校验失败导致submit退出 | ||
state.setState(state => { | ||
state.submitting = false | ||
}) | ||
// 增加onFormSubmitValidateFailed来明确结束submit的类型 | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_FAILED, state) | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_END, state) | ||
if (isFn(options.onValidateFailed)) { | ||
options.onValidateFailed(validated) | ||
} | ||
throw errors | ||
} | ||
// 增加onFormSubmitValidateSucces来明确submit引起的校验最终的结果 | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_VALIDATE_SUCCESS, state) | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT, state) | ||
let payload, | ||
values = state.getState(state => clone(state.values)) | ||
if (isFn(onSubmit)) { | ||
try { | ||
payload = await Promise.resolve(onSubmit(values)) | ||
} catch (e) { | ||
new Promise(() => { | ||
throw e | ||
}) | ||
} | ||
} | ||
state.setState(state => { | ||
state.submitting = false | ||
}) | ||
heart.publish(LifeCycleTypes.ON_FORM_SUBMIT_END, state) | ||
return { | ||
values, | ||
validated, | ||
payload | ||
} | ||
} | ||
return env.submittingTask() | ||
} | ||
async function validate( | ||
path?: FormPathPattern, | ||
opts?: IFormExtendedValidateFieldOptions | ||
): Promise<IFormValidateResult> { | ||
const { throwErrors = true } = opts || {} | ||
if (!state.getState(state => state.validating)) { | ||
state.setSourceState(state => { | ||
state.validating = true | ||
}) | ||
// 渲染优化 | ||
clearTimeout(env.validateTimer) | ||
env.validateTimer = setTimeout(() => { | ||
state.notify() | ||
}, 60) | ||
} | ||
heart.publish(LifeCycleTypes.ON_FORM_VALIDATE_START, state) | ||
const payload = await validator.validate(path, opts) | ||
clearTimeout(env.validateTimer) | ||
state.setState(state => { | ||
state.validating = false | ||
}) | ||
heart.publish(LifeCycleTypes.ON_FORM_VALIDATE_END, state) | ||
// 增加name透出真实路径,和0.x保持一致 | ||
const result = { | ||
errors: payload.errors.map(item => ({ | ||
...item, | ||
name: getFieldState(item.path).name | ||
})), | ||
warnings: payload.warnings.map(item => ({ | ||
...item, | ||
name: getFieldState(item.path).name | ||
})) | ||
} | ||
const { errors, warnings } = result | ||
// 打印warnings日志从submit挪到这里 | ||
if (warnings.length) { | ||
console.warn(warnings) | ||
} | ||
if (errors.length > 0) { | ||
if (throwErrors) { | ||
throw result | ||
} else { | ||
return result | ||
} | ||
} else { | ||
return result | ||
} | ||
} | ||
function setFormState( | ||
callback?: (state: IFormState) => any, | ||
silent?: boolean | ||
) { | ||
env.leadingStage = true | ||
state.setState(callback, silent) | ||
env.leadingStage = false | ||
} | ||
function getFormState(callback?: (state: IFormState) => any) { | ||
return state.getState(callback) | ||
} | ||
function batchRunTaskQueue( | ||
field: IField | IVirtualField, | ||
nodePath: FormPath | ||
) { | ||
for (let index = 0; index < env.taskQueue.length; index++) { | ||
const { pattern, callbacks } = env.taskQueue[index] | ||
let removed = false | ||
if (matchStrategy(pattern, nodePath)) { | ||
callbacks.forEach(callback => { | ||
field.setState(callback) | ||
}) | ||
if (!pattern.isWildMatchPattern && !pattern.isMatchPattern) { | ||
env.taskQueue.splice(index--, 1) | ||
removed = true | ||
} | ||
} | ||
if (!removed) { | ||
env.taskIndexes[pattern.toString()] = index | ||
} else { | ||
delete env.taskIndexes[pattern.toString()] | ||
} | ||
} | ||
} | ||
function setFieldState( | ||
path: FormPathPattern, | ||
callback?: (state: IFieldState<FieldProps>) => void, | ||
silent?: boolean | ||
) { | ||
if (!isFn(callback)) return | ||
let matchCount = 0 | ||
let pattern = FormPath.getPath(path) | ||
graph.select(pattern, field => { | ||
field.setState(callback, silent) | ||
matchCount++ | ||
}) | ||
if (matchCount === 0 || pattern.isWildMatchPattern) { | ||
let taskIndex = env.taskIndexes[pattern.toString()] | ||
if (isValid(taskIndex)) { | ||
if ( | ||
env.taskQueue[taskIndex] && | ||
!env.taskQueue[taskIndex].callbacks.some(fn => isEqual(fn, callback)) | ||
) { | ||
env.taskQueue[taskIndex].callbacks.push(callback) | ||
} | ||
} else { | ||
env.taskIndexes[pattern.toString()] = env.taskQueue.length | ||
env.taskQueue.push({ | ||
pattern, | ||
callbacks: [callback] | ||
}) | ||
} | ||
} | ||
} | ||
function userUpdating(field: IField | IVirtualField, fn?: () => void) { | ||
if (!field) return | ||
const nodePath = field.state.path | ||
if (nodePath) env.userUpdateFields.push(nodePath) | ||
if (isFn(fn)) { | ||
fn() | ||
} | ||
env.userUpdateFields.pop() | ||
} | ||
function setFieldValue(path: FormPathPattern, value?: any, silent?: boolean) { | ||
setFieldState( | ||
path, | ||
state => { | ||
state.value = value | ||
}, | ||
silent | ||
) | ||
} | ||
function getFieldValue(path?: FormPathPattern) { | ||
return getFieldState(path, state => { | ||
return state.value | ||
}) | ||
} | ||
function setFieldInitialValue( | ||
path?: FormPathPattern, | ||
value?: any, | ||
silent?: boolean | ||
) { | ||
setFieldState( | ||
path, | ||
state => { | ||
state.initialValue = value | ||
}, | ||
silent | ||
) | ||
} | ||
function getFieldInitialValue(path?: FormPathPattern) { | ||
return getFieldState(path, state => { | ||
return state.initialValue | ||
}) | ||
} | ||
function getFieldState( | ||
path: FormPathPattern, | ||
callback?: (state: IFieldState<FieldProps>) => any | ||
) { | ||
const field = graph.select(path) | ||
return field && field.getState(callback) | ||
} | ||
function getFormGraph() { | ||
return graph.map(node => { | ||
return node.getState() | ||
}) | ||
} | ||
function setFormGraph(nodes: {}) { | ||
each( | ||
nodes, | ||
( | ||
node: IFieldState<FieldProps> | IVirtualFieldState<VirtualFieldProps>, | ||
key | ||
) => { | ||
let nodeState: any | ||
if (graph.exist(key)) { | ||
nodeState = graph.get(key) | ||
nodeState.setSourceState(state => { | ||
Object.assign(state, node) | ||
}) | ||
} else { | ||
if (node.displayName === 'VirtualFieldState') { | ||
nodeState = registerVirtualField({ | ||
path: key | ||
}) | ||
nodeState.setSourceState(state => { | ||
Object.assign(state, node) | ||
}) | ||
} else if (node.displayName === 'FieldState') { | ||
nodeState = registerField({ | ||
path: key | ||
}) | ||
nodeState.setSourceState(state => { | ||
Object.assign(state, node) | ||
}) | ||
} | ||
} | ||
if (nodeState) { | ||
nodeState.notify(state.getState()) | ||
} | ||
} | ||
) | ||
} | ||
function matchStrategy(pattern: FormPathPattern, nodePath: FormPathPattern) { | ||
const matchPattern = FormPath.parse(pattern) | ||
const node = graph.get(nodePath) | ||
if (!node) return false | ||
return node.getSourceState(state => | ||
matchPattern.matchAliasGroup(state.name, state.path) | ||
) | ||
} | ||
//在subscribe中必须同步使用,否则会监听不到变化 | ||
function hasChanged(target: any, path: FormPathPattern): boolean { | ||
if (env.publishing[target ? target.path : ''] === false) { | ||
throw new Error( | ||
'The watch function must be used synchronously in the subscribe callback.' | ||
) | ||
} | ||
if (isFormState(target)) { | ||
return state.hasChanged(path) | ||
} else if (isFieldState(target) || isVirtualFieldState(target)) { | ||
const node = graph.get(target.path) | ||
return node && node.hasChanged(path) | ||
} else { | ||
throw new Error( | ||
'Illegal parameter,You must pass the correct state object(FormState/FieldState/VirtualFieldState).' | ||
) | ||
} | ||
} | ||
const state = new FormState(options) | ||
const validator = new FormValidator({ | ||
...options, | ||
matchStrategy | ||
}) | ||
const graph = new FormGraph({ | ||
matchStrategy | ||
}) | ||
const applyWithScheduler = scheduler(options.validateConcurrentTimeMS) | ||
const formApi = { | ||
submit, | ||
reset, | ||
hasChanged, | ||
clearErrors, | ||
validate, | ||
setFormState, | ||
getFormState, | ||
setFieldState, | ||
getFieldState, | ||
registerField, | ||
registerVirtualField, | ||
createMutators, | ||
getFormGraph, | ||
setFormGraph, | ||
setFieldValue, | ||
unsafe_do_not_use_transform_data_path: transformDataPath, //eslint-disable-line | ||
getFieldValue, | ||
setFieldInitialValue, | ||
getFieldInitialValue, | ||
subscribe: (callback?: FormHeartSubscriber) => { | ||
return heart.subscribe(callback) | ||
}, | ||
unsubscribe: (id: number) => { | ||
heart.unsubscribe(id) | ||
}, | ||
notify: <T>(type: string, payload: T) => { | ||
heart.publish(type, payload) | ||
} | ||
} | ||
const heart = new FormHeart({ | ||
...options, | ||
context: formApi, | ||
beforeNotify: payload => { | ||
env.publishing[payload.path || ''] = true | ||
}, | ||
afterNotify: payload => { | ||
env.publishing[payload.path || ''] = false | ||
} | ||
}) | ||
const env = { | ||
validateTimer: null, | ||
graphChangeTimer: null, | ||
leadingStage: false, | ||
publishing: {}, | ||
taskQueue: [], | ||
userUpdateFields: [], | ||
taskIndexes: {}, | ||
removeNodes: {}, | ||
hiddenPendingFields: {}, | ||
lastShownStates: {}, | ||
submittingTask: undefined | ||
} | ||
heart.publish(LifeCycleTypes.ON_FORM_WILL_INIT, state) | ||
state.subscription = { | ||
notify: onFormChange | ||
} | ||
graph.appendNode('', state) | ||
state.setState((state: IFormState) => { | ||
state.initialized = true | ||
}) | ||
graph.subscribe(onGraphChange) | ||
return formApi | ||
} | ||
export const registerValidationFormats = FormValidator.registerFormats | ||
export const registerValidationRules = FormValidator.registerRules | ||
export const registerValidationMTEngine = FormValidator.registerMTEngine | ||
export { | ||
setValidationLanguage, | ||
setValidationLocale, | ||
FormPath, | ||
FormPathPattern, | ||
FormGraph | ||
} | ||
export default createForm | ||
module.exports = require('@formily/core') |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3
53937
8
15
1
+ Added@formily/core@^1.0.0
+ Added@formily/core@1.3.17(transitive)
+ Addedimmer@8.0.4(transitive)
- Removed@uform/shared@^1.0.1
- Removed@uform/validator@^1.0.1
- Removedimmer@^3.2.0
- Removed@uform/shared@1.0.5(transitive)
- Removed@uform/validator@1.0.5(transitive)
- Removedimmer@3.3.0(transitive)