Files
icehrm/web/node_modules/rc-field-form/es/Field.js
2020-05-20 18:47:29 +02:00

479 lines
15 KiB
JavaScript

import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
import toChildrenArray from "rc-util/es/Children/toArray";
import warning from "rc-util/es/warning";
import * as React from 'react';
import FieldContext, { HOOK_MARK } from './FieldContext';
import { toArray } from './utils/typeUtil';
import { validateRules } from './utils/validateUtil';
import { containsNamePath, defaultGetValueFromEvent, getNamePath, getValue } from './utils/valueUtil';
function requireUpdate(shouldUpdate, prev, next, prevValue, nextValue, info) {
if (typeof shouldUpdate === 'function') {
return shouldUpdate(prev, next, 'source' in info ? {
source: info.source
} : {});
}
return prevValue !== nextValue;
} // We use Class instead of Hooks here since it will cost much code by using Hooks.
var Field = /*#__PURE__*/function (_React$Component) {
_inherits(Field, _React$Component);
function Field() {
var _this;
_classCallCheck(this, Field);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Field).apply(this, arguments));
_this.state = {
resetCount: 0
};
_this.cancelRegisterFunc = null;
_this.destroy = false;
/**
* Follow state should not management in State since it will async update by React.
* This makes first render of form can not get correct state value.
*/
_this.touched = false;
_this.validatePromise = null;
_this.errors = [];
_this.cancelRegister = function () {
if (_this.cancelRegisterFunc) {
_this.cancelRegisterFunc();
}
_this.cancelRegisterFunc = null;
}; // ================================== Utils ==================================
_this.getNamePath = function () {
var name = _this.props.name;
var _this$context$prefixN = _this.context.prefixName,
prefixName = _this$context$prefixN === void 0 ? [] : _this$context$prefixN;
return name !== undefined ? [].concat(_toConsumableArray(prefixName), _toConsumableArray(name)) : [];
};
_this.getRules = function () {
var _this$props$rules = _this.props.rules,
rules = _this$props$rules === void 0 ? [] : _this$props$rules;
return rules.map(function (rule) {
if (typeof rule === 'function') {
return rule(_this.context);
}
return rule;
});
};
_this.refresh = function () {
if (_this.destroy) return;
/**
* Clean up current node.
*/
_this.setState(function (_ref) {
var resetCount = _ref.resetCount;
return {
resetCount: resetCount + 1
};
});
}; // ========================= Field Entity Interfaces =========================
// Trigger by store update. Check if need update the component
_this.onStoreChange = function (prevStore, namePathList, info) {
var _this$props = _this.props,
shouldUpdate = _this$props.shouldUpdate,
_this$props$dependenc = _this$props.dependencies,
dependencies = _this$props$dependenc === void 0 ? [] : _this$props$dependenc,
onReset = _this$props.onReset;
var getFieldsValue = _this.context.getFieldsValue;
var values = getFieldsValue(true);
var namePath = _this.getNamePath();
var prevValue = _this.getValue(prevStore);
var curValue = _this.getValue();
var namePathMatch = namePathList && containsNamePath(namePathList, namePath); // `setFieldsValue` is a quick access to update related status
if (info.type === 'valueUpdate' && info.source === 'external' && prevValue !== curValue) {
_this.touched = true;
_this.validatePromise = null;
_this.errors = [];
}
switch (info.type) {
case 'reset':
if (!namePathList || namePathMatch) {
// Clean up state
_this.touched = false;
_this.validatePromise = null;
_this.errors = [];
if (onReset) {
onReset();
}
_this.refresh();
return;
}
break;
case 'setField':
{
if (namePathMatch) {
var data = info.data;
if ('touched' in data) {
_this.touched = data.touched;
}
if ('validating' in data && !('originRCField' in data)) {
_this.validatePromise = data.validating ? Promise.resolve([]) : null;
}
if ('errors' in data) {
_this.errors = data.errors || [];
}
_this.reRender();
return;
} // Handle update by `setField` with `shouldUpdate`
if (shouldUpdate && !namePath.length && requireUpdate(shouldUpdate, prevStore, values, prevValue, curValue, info)) {
_this.reRender();
return;
}
break;
}
case 'dependenciesUpdate':
{
/**
* Trigger when marked `dependencies` updated. Related fields will all update
*/
var dependencyList = dependencies.map(getNamePath);
if (namePathMatch || dependencyList.some(function (dependency) {
return containsNamePath(info.relatedFields, dependency);
})) {
_this.reRender();
return;
}
break;
}
default:
/**
* - If `namePath` exists in `namePathList`, means it's related value and should update.
* - If `dependencies` exists in `namePathList`, means upstream trigger update.
* - If `shouldUpdate` provided, use customize logic to update the field
* - else to check if value changed
*/
if (namePathMatch || dependencies.some(function (dependency) {
return containsNamePath(namePathList, getNamePath(dependency));
}) || requireUpdate(shouldUpdate, prevStore, values, prevValue, curValue, info)) {
_this.reRender();
return;
}
break;
}
if (shouldUpdate === true) {
_this.reRender();
}
};
_this.validateRules = function (options) {
var _this$props2 = _this.props,
_this$props2$validate = _this$props2.validateFirst,
validateFirst = _this$props2$validate === void 0 ? false : _this$props2$validate,
messageVariables = _this$props2.messageVariables;
var _ref2 = options || {},
triggerName = _ref2.triggerName;
var namePath = _this.getNamePath();
var filteredRules = _this.getRules();
if (triggerName) {
filteredRules = filteredRules.filter(function (rule) {
var validateTrigger = rule.validateTrigger;
if (!validateTrigger) {
return true;
}
var triggerList = toArray(validateTrigger);
return triggerList.includes(triggerName);
});
}
var promise = validateRules(namePath, _this.getValue(), filteredRules, options, validateFirst, messageVariables);
_this.validatePromise = promise;
_this.errors = [];
promise.catch(function (e) {
return e;
}).then(function () {
var errors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
if (_this.validatePromise === promise) {
_this.validatePromise = null;
_this.errors = errors;
_this.reRender();
}
});
return promise;
};
_this.isFieldValidating = function () {
return !!_this.validatePromise;
};
_this.isFieldTouched = function () {
return _this.touched;
};
_this.getErrors = function () {
return _this.errors;
}; // ============================= Child Component =============================
_this.getMeta = function () {
// Make error & validating in cache to save perf
_this.prevValidating = _this.isFieldValidating();
var meta = {
touched: _this.isFieldTouched(),
validating: _this.prevValidating,
errors: _this.errors,
name: _this.getNamePath()
};
return meta;
}; // Only return validate child node. If invalidate, will do nothing about field.
_this.getOnlyChild = function (children) {
// Support render props
if (typeof children === 'function') {
var meta = _this.getMeta();
return _objectSpread({}, _this.getOnlyChild(children(_this.getControlled(), meta, _this.context)), {
isFunction: true
});
} // Filed element only
var childList = toChildrenArray(children);
if (childList.length !== 1 || !React.isValidElement(childList[0])) {
return {
child: childList,
isFunction: false
};
}
return {
child: childList[0],
isFunction: false
};
}; // ============================== Field Control ==============================
_this.getValue = function (store) {
var getFieldsValue = _this.context.getFieldsValue;
var namePath = _this.getNamePath();
return getValue(store || getFieldsValue(true), namePath);
};
_this.getControlled = function () {
var childProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _this$props3 = _this.props,
trigger = _this$props3.trigger,
validateTrigger = _this$props3.validateTrigger,
getValueFromEvent = _this$props3.getValueFromEvent,
normalize = _this$props3.normalize,
valuePropName = _this$props3.valuePropName;
var namePath = _this.getNamePath();
var _this$context = _this.context,
getInternalHooks = _this$context.getInternalHooks,
getFieldsValue = _this$context.getFieldsValue;
var _getInternalHooks = getInternalHooks(HOOK_MARK),
dispatch = _getInternalHooks.dispatch;
var value = _this.getValue(); // eslint-disable-next-line @typescript-eslint/no-explicit-any
var originTriggerFunc = childProps[trigger];
var control = _objectSpread({}, childProps, _defineProperty({}, valuePropName, value)); // Add trigger
control[trigger] = function () {
// Mark as touched
_this.touched = true;
var newValue;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (getValueFromEvent) {
newValue = getValueFromEvent.apply(void 0, args);
} else {
newValue = defaultGetValueFromEvent.apply(void 0, [valuePropName].concat(args));
}
if (normalize) {
newValue = normalize(newValue, value, getFieldsValue(true));
}
dispatch({
type: 'updateValue',
namePath: namePath,
value: newValue
});
if (originTriggerFunc) {
originTriggerFunc.apply(void 0, args);
}
}; // Add validateTrigger
var validateTriggerList = toArray(validateTrigger || []);
validateTriggerList.forEach(function (triggerName) {
// Wrap additional function of component, so that we can get latest value from store
var originTrigger = control[triggerName];
control[triggerName] = function () {
if (originTrigger) {
originTrigger.apply(void 0, arguments);
} // Always use latest rules
var rules = _this.props.rules;
if (rules && rules.length) {
// We dispatch validate to root,
// since it will update related data with other field with same name
dispatch({
type: 'validateField',
namePath: namePath,
triggerName: triggerName
});
}
};
});
return control;
};
return _this;
} // ============================== Subscriptions ==============================
_createClass(Field, [{
key: "componentDidMount",
value: function componentDidMount() {
var getInternalHooks = this.context.getInternalHooks;
var _getInternalHooks2 = getInternalHooks(HOOK_MARK),
registerField = _getInternalHooks2.registerField;
this.cancelRegisterFunc = registerField(this);
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
this.cancelRegister();
this.destroy = true;
}
}, {
key: "reRender",
value: function reRender() {
if (this.destroy) return;
this.forceUpdate();
}
}, {
key: "render",
value: function render() {
var resetCount = this.state.resetCount;
var children = this.props.children;
var _this$getOnlyChild = this.getOnlyChild(children),
child = _this$getOnlyChild.child,
isFunction = _this$getOnlyChild.isFunction; // Not need to `cloneElement` since user can handle this in render function self
var returnChildNode;
if (isFunction) {
returnChildNode = child;
} else if (React.isValidElement(child)) {
returnChildNode = React.cloneElement(child, this.getControlled(child.props));
} else {
warning(!child, '`children` of Field is not validate ReactElement.');
returnChildNode = child;
}
return React.createElement(React.Fragment, {
key: resetCount
}, returnChildNode);
}
}]);
return Field;
}(React.Component);
Field.contextType = FieldContext;
Field.defaultProps = {
trigger: 'onChange',
validateTrigger: 'onChange',
valuePropName: 'value'
};
var WrapperField = function WrapperField(_ref3) {
var name = _ref3.name,
restProps = _objectWithoutProperties(_ref3, ["name"]);
var namePath = name !== undefined ? getNamePath(name) : undefined;
return React.createElement(Field, Object.assign({
key: "_".concat((namePath || []).join('_')),
name: namePath
}, restProps));
};
export default WrapperField;