"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _toArray = _interopRequireDefault(require("rc-util/lib/Children/toArray")); var _warning = _interopRequireDefault(require("rc-util/lib/warning")); var React = _interopRequireWildcard(require("react")); var _FieldContext = _interopRequireWildcard(require("./FieldContext")); var _typeUtil = require("./utils/typeUtil"); var _validateUtil = require("./utils/validateUtil"); var _valueUtil = require("./utils/valueUtil"); 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) { (0, _defineProperty2.default)(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; } function _createSuper(Derived) { return function () { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } 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) { (0, _inherits2.default)(Field, _React$Component); var _super = _createSuper(Field); function Field() { var _this; (0, _classCallCheck2.default)(this, Field); _this = _super.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; /** Mark when touched & validated. Currently only used for `dependencies` */ _this.dirty = false; _this.validatePromise = null; _this.errors = []; _this.cancelRegister = function () { var preserve = _this.props.preserve; if (_this.cancelRegisterFunc) { _this.cancelRegisterFunc(preserve); } _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((0, _toConsumableArray2.default)(prefixName), (0, _toConsumableArray2.default)(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 store = info.store; var namePath = _this.getNamePath(); var prevValue = _this.getValue(prevStore); var curValue = _this.getValue(store); var namePathMatch = namePathList && (0, _valueUtil.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.dirty = true; _this.validatePromise = null; _this.errors = []; } switch (info.type) { case 'reset': if (!namePathList || namePathMatch) { // Clean up state _this.touched = false; _this.dirty = 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.dirty = true; _this.reRender(); return; } // Handle update by `setField` with `shouldUpdate` if (shouldUpdate && !namePath.length && requireUpdate(shouldUpdate, prevStore, store, prevValue, curValue, info)) { _this.reRender(); return; } break; } case 'dependenciesUpdate': { /** * Trigger when marked `dependencies` updated. Related fields will all update */ var dependencyList = dependencies.map(_valueUtil.getNamePath); // No need for `namePathMath` check and `shouldUpdate` check, since `valueUpdate` will be // emitted earlier and they will work there // If set it may cause unnecessary twice rerendering if (dependencyList.some(function (dependency) { return (0, _valueUtil.containsNamePath)(info.relatedFields, dependency); })) { _this.reRender(); return; } break; } default: // 1. If `namePath` exists in `namePathList`, means it's related value and should update // For example // If `namePathList` is [['list']] (List value update), Field should be updated // If `namePathList` is [['list', 0]] (Field value update), List shouldn't be updated // 2. // 2.1 If `dependencies` is set, `name` is not set and `shouldUpdate` is not set, // don't use `shouldUpdate`. `dependencies` is view as a shortcut if `shouldUpdate` // is not provided // 2.2 If `shouldUpdate` provided, use customize logic to update the field // else to check if value changed if (namePathMatch || (!dependencies.length || namePath.length || shouldUpdate) && requireUpdate(shouldUpdate, prevStore, store, 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 = (0, _typeUtil.toArray)(validateTrigger); return triggerList.includes(triggerName); }); } var promise = (0, _validateUtil.validateRules)(namePath, _this.getValue(), filteredRules, options, validateFirst, messageVariables); _this.dirty = true; _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.isFieldDirty = function () { return _this.dirty; }; _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 = (0, _toArray.default)(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 (0, _valueUtil.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, getValueProps = _this$props3.getValueProps; var mergedValidateTrigger = validateTrigger !== undefined ? validateTrigger : _this.context.validateTrigger; var namePath = _this.getNamePath(); var _this$context = _this.context, getInternalHooks = _this$context.getInternalHooks, getFieldsValue = _this$context.getFieldsValue; var _getInternalHooks = getInternalHooks(_FieldContext.HOOK_MARK), dispatch = _getInternalHooks.dispatch; var value = _this.getValue(); var mergedGetValueProps = getValueProps || function (val) { return (0, _defineProperty2.default)({}, valuePropName, val); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any var originTriggerFunc = childProps[trigger]; var control = _objectSpread({}, childProps, {}, mergedGetValueProps(value)); // Add trigger control[trigger] = function () { // Mark as touched _this.touched = true; _this.dirty = 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 = _valueUtil.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 = (0, _typeUtil.toArray)(mergedValidateTrigger || []); 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 ============================== (0, _createClass2.default)(Field, [{ key: "componentDidMount", value: function componentDidMount() { var shouldUpdate = this.props.shouldUpdate; var getInternalHooks = this.context.getInternalHooks; var _getInternalHooks2 = getInternalHooks(_FieldContext.HOOK_MARK), registerField = _getInternalHooks2.registerField; this.cancelRegisterFunc = registerField(this); // One more render for component in case fields not ready if (shouldUpdate === true) { this.reRender(); } } }, { 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 { (0, _warning.default)(!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.default; Field.defaultProps = { trigger: 'onChange', valuePropName: 'value' }; var WrapperField = function WrapperField(_ref4) { var name = _ref4.name, isListField = _ref4.isListField, restProps = (0, _objectWithoutProperties2.default)(_ref4, ["name", "isListField"]); var namePath = name !== undefined ? (0, _valueUtil.getNamePath)(name) : undefined; var key = 'keep'; if (!isListField) { key = "_".concat((namePath || []).join('_')); } return React.createElement(Field, Object.assign({ key: key, name: namePath }, restProps)); }; var _default = WrapperField; exports.default = _default;