"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _regeneratorRuntime2 = _interopRequireDefault(require("@babel/runtime/helpers/regeneratorRuntime")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); 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 _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _createSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/createSuper")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toArray = _interopRequireDefault(require("rc-util/lib/Children/toArray")); var _isEqual = _interopRequireDefault(require("rc-util/lib/isEqual")); var _warning = _interopRequireDefault(require("rc-util/lib/warning")); var React = _interopRequireWildcard(require("react")); var _FieldContext = _interopRequireWildcard(require("./FieldContext")); var _ListContext = _interopRequireDefault(require("./ListContext")); var _typeUtil = require("./utils/typeUtil"); var _validateUtil = require("./utils/validateUtil"); var _valueUtil = require("./utils/valueUtil"); var _excluded = ["name"]; var EMPTY_ERRORS = []; 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; } // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style // 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 = (0, _createSuper2.default)(Field); // ============================== Subscriptions ============================== function Field(props) { var _this; (0, _classCallCheck2.default)(this, Field); _this = _super.call(this, props); // Register on init (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "state", { resetCount: 0 }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "cancelRegisterFunc", null); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "mounted", 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. */ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "touched", false); /** * Mark when touched & validated. Currently only used for `dependencies`. * Note that we do not think field with `initialValue` is dirty * but this will be by `isFieldDirty` func. */ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "dirty", false); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "validatePromise", void 0); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "prevValidating", void 0); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "errors", EMPTY_ERRORS); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "warnings", EMPTY_ERRORS); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "cancelRegister", function () { var _this$props = _this.props, preserve = _this$props.preserve, isListField = _this$props.isListField, name = _this$props.name; if (_this.cancelRegisterFunc) { _this.cancelRegisterFunc(isListField, preserve, (0, _valueUtil.getNamePath)(name)); } _this.cancelRegisterFunc = null; }); // ================================== Utils ================================== (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getNamePath", function () { var _this$props2 = _this.props, name = _this$props2.name, fieldContext = _this$props2.fieldContext; var _fieldContext$prefixN = fieldContext.prefixName, prefixName = _fieldContext$prefixN === void 0 ? [] : _fieldContext$prefixN; return name !== undefined ? [].concat((0, _toConsumableArray2.default)(prefixName), (0, _toConsumableArray2.default)(name)) : []; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getRules", function () { var _this$props3 = _this.props, _this$props3$rules = _this$props3.rules, rules = _this$props3$rules === void 0 ? [] : _this$props3$rules, fieldContext = _this$props3.fieldContext; return rules.map(function (rule) { if (typeof rule === 'function') { return rule(fieldContext); } return rule; }); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "refresh", function () { if (!_this.mounted) return; /** * Clean up current node. */ _this.setState(function (_ref) { var resetCount = _ref.resetCount; return { resetCount: resetCount + 1 }; }); }); // Event should only trigger when meta changed (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "metaCache", null); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "triggerMetaEvent", function (destroy) { var onMetaChange = _this.props.onMetaChange; if (onMetaChange) { var _meta = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _this.getMeta()), {}, { destroy: destroy }); if (!(0, _isEqual.default)(_this.metaCache, _meta)) { onMetaChange(_meta); } _this.metaCache = _meta; } else { _this.metaCache = null; } }); // ========================= Field Entity Interfaces ========================= // Trigger by store update. Check if need update the component (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onStoreChange", function (prevStore, namePathList, info) { var _this$props4 = _this.props, shouldUpdate = _this$props4.shouldUpdate, _this$props4$dependen = _this$props4.dependencies, dependencies = _this$props4$dependen === void 0 ? [] : _this$props4$dependen, onReset = _this$props4.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 = EMPTY_ERRORS; _this.warnings = EMPTY_ERRORS; _this.triggerMetaEvent(); } switch (info.type) { case 'reset': if (!namePathList || namePathMatch) { // Clean up state _this.touched = false; _this.dirty = false; _this.validatePromise = undefined; _this.errors = EMPTY_ERRORS; _this.warnings = EMPTY_ERRORS; _this.triggerMetaEvent(); onReset === null || onReset === void 0 ? void 0 : onReset(); _this.refresh(); return; } break; /** * In case field with `preserve = false` nest deps like: * - A = 1 => show B * - B = 1 => show C * - Reset A, need clean B, C */ case 'remove': { if (shouldUpdate) { _this.reRender(); return; } break; } case 'setField': { var data = info.data; if (namePathMatch) { 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 || EMPTY_ERRORS; } if ('warnings' in data) { _this.warnings = data.warnings || EMPTY_ERRORS; } _this.dirty = true; _this.triggerMetaEvent(); _this.reRender(); return; } else if ('value' in data && (0, _valueUtil.containsNamePath)(namePathList, namePath, true)) { // Contains path with value should also check _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(); } }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "validateRules", function (options) { // We should fixed namePath & value to avoid developer change then by form function var namePath = _this.getNamePath(); var currentValue = _this.getValue(); var _ref2 = options || {}, triggerName = _ref2.triggerName, _ref2$validateOnly = _ref2.validateOnly, validateOnly = _ref2$validateOnly === void 0 ? false : _ref2$validateOnly; // Force change to async to avoid rule OOD under renderProps field var rootPromise = Promise.resolve().then( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/(0, _regeneratorRuntime2.default)().mark(function _callee() { var _this$props5, _this$props5$validate, validateFirst, messageVariables, validateDebounce, filteredRules, promise; return (0, _regeneratorRuntime2.default)().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: if (_this.mounted) { _context.next = 2; break; } return _context.abrupt("return", []); case 2: _this$props5 = _this.props, _this$props5$validate = _this$props5.validateFirst, validateFirst = _this$props5$validate === void 0 ? false : _this$props5$validate, messageVariables = _this$props5.messageVariables, validateDebounce = _this$props5.validateDebounce; // Start validate filteredRules = _this.getRules(); if (triggerName) { filteredRules = filteredRules.filter(function (rule) { return rule; }).filter(function (rule) { var validateTrigger = rule.validateTrigger; if (!validateTrigger) { return true; } var triggerList = (0, _typeUtil.toArray)(validateTrigger); return triggerList.includes(triggerName); }); } // Wait for debounce. Skip if no `triggerName` since its from `validateFields / submit` if (!(validateDebounce && triggerName)) { _context.next = 10; break; } _context.next = 8; return new Promise(function (resolve) { setTimeout(resolve, validateDebounce); }); case 8: if (!(_this.validatePromise !== rootPromise)) { _context.next = 10; break; } return _context.abrupt("return", []); case 10: promise = (0, _validateUtil.validateRules)(namePath, currentValue, filteredRules, options, validateFirst, messageVariables); promise.catch(function (e) { return e; }).then(function () { var ruleErrors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : EMPTY_ERRORS; if (_this.validatePromise === rootPromise) { var _ruleErrors$forEach; _this.validatePromise = null; // Get errors & warnings var nextErrors = []; var nextWarnings = []; (_ruleErrors$forEach = ruleErrors.forEach) === null || _ruleErrors$forEach === void 0 ? void 0 : _ruleErrors$forEach.call(ruleErrors, function (_ref4) { var warningOnly = _ref4.rule.warningOnly, _ref4$errors = _ref4.errors, errors = _ref4$errors === void 0 ? EMPTY_ERRORS : _ref4$errors; if (warningOnly) { nextWarnings.push.apply(nextWarnings, (0, _toConsumableArray2.default)(errors)); } else { nextErrors.push.apply(nextErrors, (0, _toConsumableArray2.default)(errors)); } }); _this.errors = nextErrors; _this.warnings = nextWarnings; _this.triggerMetaEvent(); _this.reRender(); } }); return _context.abrupt("return", promise); case 13: case "end": return _context.stop(); } }, _callee); }))); if (validateOnly) { return rootPromise; } _this.validatePromise = rootPromise; _this.dirty = true; _this.errors = EMPTY_ERRORS; _this.warnings = EMPTY_ERRORS; _this.triggerMetaEvent(); // Force trigger re-render since we need sync renderProps with new meta _this.reRender(); return rootPromise; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isFieldValidating", function () { return !!_this.validatePromise; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isFieldTouched", function () { return _this.touched; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isFieldDirty", function () { // Touched or validate or has initialValue if (_this.dirty || _this.props.initialValue !== undefined) { return true; } // Form set initialValue var fieldContext = _this.props.fieldContext; var _fieldContext$getInte = fieldContext.getInternalHooks(_FieldContext.HOOK_MARK), getInitialValue = _fieldContext$getInte.getInitialValue; if (getInitialValue(_this.getNamePath()) !== undefined) { return true; } return false; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getErrors", function () { return _this.errors; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getWarnings", function () { return _this.warnings; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isListField", function () { return _this.props.isListField; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isList", function () { return _this.props.isList; }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isPreserve", function () { return _this.props.preserve; }); // ============================= Child Component ============================= (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_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, warnings: _this.warnings, name: _this.getNamePath(), validated: _this.validatePromise === null }; return meta; }); // Only return validate child node. If invalidate, will do nothing about field. (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getOnlyChild", function (children) { // Support render props if (typeof children === 'function') { var _meta2 = _this.getMeta(); return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _this.getOnlyChild(children(_this.getControlled(), _meta2, _this.props.fieldContext))), {}, { isFunction: true }); } // Filed element only var childList = (0, _toArray.default)(children); if (childList.length !== 1 || ! /*#__PURE__*/React.isValidElement(childList[0])) { return { child: childList, isFunction: false }; } return { child: childList[0], isFunction: false }; }); // ============================== Field Control ============================== (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getValue", function (store) { var getFieldsValue = _this.props.fieldContext.getFieldsValue; var namePath = _this.getNamePath(); return (0, _valueUtil.getValue)(store || getFieldsValue(true), namePath); }); (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getControlled", function () { var childProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _this$props6 = _this.props, trigger = _this$props6.trigger, validateTrigger = _this$props6.validateTrigger, getValueFromEvent = _this$props6.getValueFromEvent, normalize = _this$props6.normalize, valuePropName = _this$props6.valuePropName, getValueProps = _this$props6.getValueProps, fieldContext = _this$props6.fieldContext; var mergedValidateTrigger = validateTrigger !== undefined ? validateTrigger : fieldContext.validateTrigger; var namePath = _this.getNamePath(); var getInternalHooks = fieldContext.getInternalHooks, getFieldsValue = fieldContext.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 = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, childProps), mergedGetValueProps(value)); // Add trigger control[trigger] = function () { // Mark as touched _this.touched = true; _this.dirty = true; _this.triggerMetaEvent(); 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; }); if (props.fieldContext) { var getInternalHooks = props.fieldContext.getInternalHooks; var _getInternalHooks2 = getInternalHooks(_FieldContext.HOOK_MARK), initEntityValue = _getInternalHooks2.initEntityValue; initEntityValue((0, _assertThisInitialized2.default)(_this)); } return _this; } (0, _createClass2.default)(Field, [{ key: "componentDidMount", value: function componentDidMount() { var _this$props7 = this.props, shouldUpdate = _this$props7.shouldUpdate, fieldContext = _this$props7.fieldContext; this.mounted = true; // Register on init if (fieldContext) { var getInternalHooks = fieldContext.getInternalHooks; var _getInternalHooks3 = getInternalHooks(_FieldContext.HOOK_MARK), registerField = _getInternalHooks3.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.triggerMetaEvent(true); this.mounted = false; } }, { key: "reRender", value: function reRender() { if (!this.mounted) 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 ( /*#__PURE__*/React.isValidElement(child)) { returnChildNode = /*#__PURE__*/React.cloneElement(child, this.getControlled(child.props)); } else { (0, _warning.default)(!child, '`children` of Field is not validate ReactElement.'); returnChildNode = child; } return /*#__PURE__*/React.createElement(React.Fragment, { key: resetCount }, returnChildNode); } }]); return Field; }(React.Component); (0, _defineProperty2.default)(Field, "contextType", _FieldContext.default); (0, _defineProperty2.default)(Field, "defaultProps", { trigger: 'onChange', valuePropName: 'value' }); function WrapperField(_ref6) { var name = _ref6.name, restProps = (0, _objectWithoutProperties2.default)(_ref6, _excluded); var fieldContext = React.useContext(_FieldContext.default); var listContext = React.useContext(_ListContext.default); var namePath = name !== undefined ? (0, _valueUtil.getNamePath)(name) : undefined; var key = 'keep'; if (!restProps.isListField) { key = "_".concat((namePath || []).join('_')); } // Warning if it's a directly list field. // We can still support multiple level field preserve. if (process.env.NODE_ENV !== 'production' && restProps.preserve === false && restProps.isListField && namePath.length <= 1) { (0, _warning.default)(false, '`preserve` should not apply on Form.List fields.'); } return /*#__PURE__*/React.createElement(Field, (0, _extends2.default)({ key: key, name: namePath, isListField: !!listContext }, restProps, { fieldContext: fieldContext })); } var _default = WrapperField; exports.default = _default;