UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

213 lines (212 loc) 7.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _isUndefined2 = _interopRequireDefault(require("lodash/isUndefined")); var _react = _interopRequireWildcard(require("react")); var _uuid = require("@douyinfe/semi-foundation/lib/cjs/utils/uuid"); var _context = require("./context"); var _warning = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/utils/warning")); var _fastCopy = _interopRequireDefault(require("fast-copy")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const filterArrayByIndex = (array, index) => array.filter((item, i) => i !== index); const getUuidByArray = array => array.map(() => (0, _uuid.getUuidv4)()); const getUpdateKey = arrayField => { if (!arrayField) { return undefined; } if (arrayField && arrayField.updateKey) { return arrayField.updateKey; } return undefined; }; const initValueAdapter = initValue => { const iv = []; if (Array.isArray(initValue)) { return initValue; } else { (0, _warning.default)(!(0, _isUndefined2.default)(initValue), '[Semi Form ArrayField] initValue of ArrayField must be an array. Please check the type of your props'); return iv; } }; /** * * @param {any[]} value * @param {string[]} oldKeys * @returns string[] */ const generateKeys = (value, oldKeys) => { const val = initValueAdapter(value); const newKeys = getUuidByArray(val); // return newKeys; const keys = newKeys.map((key, i) => oldKeys && oldKeys[i] ? oldKeys[i] : key); return keys; }; class ArrayFieldComponent extends _react.Component { constructor(props, context) { super(props, context); const initValueInProps = this.props.initValue; const { field } = this.props; const initValueInForm = context.getValue(field); const initValue = initValueInProps || initValueInForm; this.state = { keys: generateKeys(initValue) }; this.add = this.add.bind(this); this.addWithInitValue = this.addWithInitValue.bind(this); this.remove = this.remove.bind(this); this.cacheFieldValues = null; this.cacheUpdateKey = null; /* If updateKey exists, it means that the arrayField (usually a nested ArrayField not at the first level) is only re-mounted due to setValues, and the fields it contains do not need to consume initValue */ // whether the fields inside arrayField should use props.initValue in current render process this.shouldUseInitValue = !context.getArrayField(field); // Separate the arrays that reset and the usual add and remove modify, otherwise they will affect each other const initValueCopyForFormState = (0, _fastCopy.default)(initValue); const initValueCopyForReset = (0, _fastCopy.default)(initValue); context.registerArrayField(field, initValueCopyForReset); // register ArrayField will update state.updateKey to render, So there is no need to execute forceUpdate here context.updateStateValue(field, initValueCopyForFormState, { notNotify: true, notUpdate: true }); } componentWillUnmount() { const updater = this.context; const { field } = this.props; updater.unRegisterArrayField(field); } componentDidUpdate() { const updater = this.context; const { field } = this.props; const { keys } = this.state; const fieldValues = updater.getValue(field); const updateKey = getUpdateKey(updater.getArrayField(field)); // when update form outside, like use formApi.setValue('field', [{newItem1, newItem2}]), formApi.setValues // re generate keys to update arrayField; if (updateKey !== this.cacheUpdateKey) { const newKeys = generateKeys(fieldValues, keys); // eslint-disable-next-line this.setState({ keys: newKeys }); this.cacheUpdateKey = updateKey; if (this.cacheUpdateKey !== null) { this.shouldUseInitValue = false; } } } add() { const { keys } = this.state; const { field } = this.props; const updater = this.context; keys.push((0, _uuid.getUuidv4)()); this.shouldUseInitValue = true; this.setState({ keys }); let updateKey = new Date().valueOf(); updater.updateArrayField(field, { updateKey }); this.cacheUpdateKey = updateKey; } addWithInitValue(rowVal) { const updater = this.context; const { field } = this.props; const newArrayFieldVal = updater.getValue(field) ? updater.getValue(field).slice() : []; const cloneRowVal = (0, _fastCopy.default)(rowVal); newArrayFieldVal.push(cloneRowVal); updater.updateStateValue(field, newArrayFieldVal, {}); updater.updateArrayField(field, { updateKey: new Date().valueOf() }); } remove(i) { const updater = this.context; const { keys } = this.state; const { field } = this.props; const newKeys = filterArrayByIndex(keys, i); // Make sure that all the keys in the line are removed, because some keys are not taken over by the field, only set in the initValue let newArrayFieldError = updater.getError(field); const opts = { notNotify: true, notUpdate: true }; if (Array.isArray(newArrayFieldError)) { newArrayFieldError = newArrayFieldError.slice(); newArrayFieldError.splice(i, 1); updater.updateStateError(field, newArrayFieldError, opts); } // if (Array.isArray(newArrayFieldTouched)) { // newArrayFieldTouched = newArrayFieldTouched.slice(); // newArrayFieldTouched.splice(i, 1); // updater.updateStateTouched(field, newArrayFieldTouched, opts); // } let newArrayFieldValue = updater.getValue(field); if (Array.isArray(newArrayFieldValue)) { newArrayFieldValue = newArrayFieldValue.slice(); newArrayFieldValue.splice(i, 1); updater.updateStateValue(field, newArrayFieldValue); } this.setState({ keys: newKeys }); } render() { const { children, field } = this.props; const { keys } = this.state; const arrayFields = keys.map((key, i) => ({ // key: i, key, field: `${field}[${i}]`, remove: () => this.remove(i) })); const { add } = this; const { addWithInitValue } = this; const contextVal = { shouldUseInitValue: this.shouldUseInitValue }; return /*#__PURE__*/_react.default.createElement(_context.ArrayFieldContext.Provider, { value: contextVal }, children({ arrayFields, add, addWithInitValue })); } } ArrayFieldComponent.contextType = _context.FormUpdaterContext; var _default = exports.default = ArrayFieldComponent;