@ant-design/pro-form
Version:
572 lines (559 loc) • 26.1 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
var _excluded = ["children", "contentRender", "submitter", "fieldProps", "formItemProps", "groupProps", "transformKey", "formRef", "onInit", "form", "loading", "formComponentType", "extraUrlParams", "syncToUrl", "onUrlSearchChange", "onReset", "omitNil", "isKeyPressSubmit", "autoFocusFirstInput", "grid", "rowProps", "colProps"],
_excluded2 = ["extraUrlParams", "syncToUrl", "isKeyPressSubmit", "syncToUrlAsImportant", "syncToInitialValues", "children", "contentRender", "submitter", "fieldProps", "proFieldProps", "formItemProps", "groupProps", "dateFormatter", "formRef", "onInit", "form", "formComponentType", "onReset", "grid", "rowProps", "colProps", "omitNil", "request", "params", "initialValues", "formKey", "readonly", "onLoadingChange", "loading"];
/* eslint-disable react-hooks/exhaustive-deps */
import { ProConfigProvider } from '@ant-design/pro-provider';
import { ProFormContext, conversionMomentValue, isDeepEqualReact, nanoid, runFunction, transformKeySubmitValue, useFetchData, useMountMergeState, usePrevious, useRefFunction, useStyle } from '@ant-design/pro-utils';
import { useUrlSearchParams } from '@umijs/use-params';
import { ConfigProvider, Form, Spin } from 'antd';
import classNames from 'classnames';
import omit from "rc-util/es/omit";
import get from "rc-util/es/utils/get";
import { default as namePathSet, default as set } from "rc-util/es/utils/set";
import { noteOnce } from "rc-util/es/warning";
import React, { useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import FieldContext from "../FieldContext";
import { Submitter } from "../components";
import { FormListContext } from "../components/List";
import { GridContext, useGridHelpers } from "../helpers";
import { EditOrReadOnlyContext } from "./EditOrReadOnlyContext";
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
var genParams = function genParams(syncUrl, params, type) {
if (syncUrl === true) {
return params;
}
return runFunction(syncUrl, params, type);
};
/**
* It takes a name path and converts it to an array.
* @param {NamePath} name - The name of the form.
* @returns string[]
*
* a-> [a]
* [a] -> [a]
*/
var covertFormName = function covertFormName(name) {
if (!name) return name;
if (Array.isArray(name)) return name;
return [name];
};
function BaseFormComponents(props) {
var _ConfigProvider$useCo;
var children = props.children,
contentRender = props.contentRender,
submitter = props.submitter,
fieldProps = props.fieldProps,
formItemProps = props.formItemProps,
groupProps = props.groupProps,
transformKey = props.transformKey,
propsFormRef = props.formRef,
onInit = props.onInit,
form = props.form,
loading = props.loading,
formComponentType = props.formComponentType,
_props$extraUrlParams = props.extraUrlParams,
extraUrlParams = _props$extraUrlParams === void 0 ? {} : _props$extraUrlParams,
syncToUrl = props.syncToUrl,
onUrlSearchChange = props.onUrlSearchChange,
_onReset = props.onReset,
_props$omitNil = props.omitNil,
omitNil = _props$omitNil === void 0 ? true : _props$omitNil,
isKeyPressSubmit = props.isKeyPressSubmit,
_props$autoFocusFirst = props.autoFocusFirstInput,
autoFocusFirstInput = _props$autoFocusFirst === void 0 ? true : _props$autoFocusFirst,
grid = props.grid,
rowProps = props.rowProps,
colProps = props.colProps,
rest = _objectWithoutProperties(props, _excluded);
/**
* 获取 form 实例
*/
var formInstance = Form.useFormInstance();
var _ref = (ConfigProvider === null || ConfigProvider === void 0 || (_ConfigProvider$useCo = ConfigProvider.useConfig) === null || _ConfigProvider$useCo === void 0 ? void 0 : _ConfigProvider$useCo.call(ConfigProvider)) || {
componentSize: 'middle'
},
componentSize = _ref.componentSize;
/** 同步 url 上的参数 */
var formRef = useRef(form || formInstance);
/**
* 获取布局
*/
var _useGridHelpers = useGridHelpers({
grid: grid,
rowProps: rowProps
}),
RowWrapper = _useGridHelpers.RowWrapper;
var getFormInstance = useRefFunction(function () {
return formInstance;
});
var formatValues = useMemo(function () {
return {
/**
* 获取被 ProForm 格式化后的所有数据
* @param allData boolean
* @returns T
*
* @example getFieldsFormatValue(true) ->返回所有数据,即使没有被 form 托管的
*/
getFieldsFormatValue: function getFieldsFormatValue(allData) {
var _getFormInstance;
return transformKey((_getFormInstance = getFormInstance()) === null || _getFormInstance === void 0 ? void 0 : _getFormInstance.getFieldsValue(allData), omitNil);
},
/**
* 获取被 ProForm 格式化后的单个数据
* @param nameList (string|number)[]
* @returns T
*
* @example {a:{b:value}} -> getFieldFormatValue(['a', 'b']) -> value
*/
/** 获取格式化之后的单个数据 */
getFieldFormatValue: function getFieldFormatValue() {
var _getFormInstance2;
var paramsNameList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var nameList = covertFormName(paramsNameList);
if (!nameList) throw new Error('nameList is require');
var value = (_getFormInstance2 = getFormInstance()) === null || _getFormInstance2 === void 0 ? void 0 : _getFormInstance2.getFieldValue(nameList);
var obj = nameList ? set({}, nameList, value) : value;
//transformKey会将keys重新和nameList拼接,所以这里要将nameList的首个元素弹出
var newNameList = _toConsumableArray(nameList);
newNameList.shift();
return get(transformKey(obj, omitNil, newNameList), nameList);
},
/**
* 获取被 ProForm 格式化后的单个数据, 包含他的 name
* @param nameList (string|number)[]
* @returns T
*
* @example {a:{b:value}} -> getFieldFormatValueObject(['a', 'b']) -> {a:{b:value}}
*/
/** 获取格式化之后的单个数据 */
getFieldFormatValueObject: function getFieldFormatValueObject(paramsNameList) {
var _getFormInstance3;
var nameList = covertFormName(paramsNameList);
var value = (_getFormInstance3 = getFormInstance()) === null || _getFormInstance3 === void 0 ? void 0 : _getFormInstance3.getFieldValue(nameList);
var obj = nameList ? set({}, nameList, value) : value;
return transformKey(obj, omitNil, nameList);
},
/**
/**
*验字段后返回格式化之后的所有数据
* @param nameList (string|number)[]
* @returns T
*
* @example validateFieldsReturnFormatValue -> {a:{b:value}}
*/
validateFieldsReturnFormatValue: function () {
var _validateFieldsReturnFormatValue = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(nameList) {
var _getFormInstance4;
var values, transformedKey;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (!(!Array.isArray(nameList) && nameList)) {
_context.next = 2;
break;
}
throw new Error('nameList must be array');
case 2:
_context.next = 4;
return (_getFormInstance4 = getFormInstance()) === null || _getFormInstance4 === void 0 ? void 0 : _getFormInstance4.validateFields(nameList);
case 4:
values = _context.sent;
transformedKey = transformKey(values, omitNil);
return _context.abrupt("return", transformedKey ? transformedKey : {});
case 7:
case "end":
return _context.stop();
}
}, _callee);
}));
function validateFieldsReturnFormatValue(_x) {
return _validateFieldsReturnFormatValue.apply(this, arguments);
}
return validateFieldsReturnFormatValue;
}()
};
}, [omitNil, transformKey]);
var items = useMemo(function () {
return React.Children.toArray(children).map(function (item, index) {
if (index === 0 && /*#__PURE__*/React.isValidElement(item) && autoFocusFirstInput) {
return /*#__PURE__*/React.cloneElement(item, _objectSpread(_objectSpread({}, item.props), {}, {
autoFocus: autoFocusFirstInput
}));
}
return item;
});
}, [autoFocusFirstInput, children]);
/** 计算 props 的对象 */
var submitterProps = useMemo(function () {
return typeof submitter === 'boolean' || !submitter ? {} : submitter;
}, [submitter]);
/** 渲染提交按钮与重置按钮 */
var submitterNode = useMemo(function () {
if (submitter === false) return undefined;
return /*#__PURE__*/_jsx(Submitter, _objectSpread(_objectSpread({}, submitterProps), {}, {
onReset: function onReset() {
var _formRef$current, _submitterProps$onRes;
var finalValues = transformKey((_formRef$current = formRef.current) === null || _formRef$current === void 0 ? void 0 : _formRef$current.getFieldsValue(), omitNil);
submitterProps === null || submitterProps === void 0 || (_submitterProps$onRes = submitterProps.onReset) === null || _submitterProps$onRes === void 0 || _submitterProps$onRes.call(submitterProps, finalValues);
_onReset === null || _onReset === void 0 || _onReset(finalValues);
// 如果 syncToUrl,清空一下数据
if (syncToUrl) {
var _formRef$current2;
// 把没有的值设置为未定义可以删掉 url 的参数
var params = Object.keys(transformKey((_formRef$current2 = formRef.current) === null || _formRef$current2 === void 0 ? void 0 : _formRef$current2.getFieldsValue(), false)).reduce(function (pre, next) {
return _objectSpread(_objectSpread({}, pre), {}, _defineProperty({}, next, finalValues[next] || undefined));
}, extraUrlParams);
/** 在同步到 url 上时对参数进行转化 */
onUrlSearchChange(genParams(syncToUrl, params || {}, 'set'));
}
},
submitButtonProps: _objectSpread({
loading: loading
}, submitterProps.submitButtonProps)
}), "submitter");
}, [submitter, submitterProps, loading, transformKey, omitNil, _onReset, syncToUrl, extraUrlParams, onUrlSearchChange]);
var content = useMemo(function () {
var wrapItems = grid ? /*#__PURE__*/_jsx(RowWrapper, {
children: items
}) : items;
if (contentRender) {
return contentRender(wrapItems, submitterNode, formRef.current);
}
return wrapItems;
}, [grid, RowWrapper, items, contentRender, submitterNode]);
var preInitialValues = usePrevious(props.initialValues);
// 提示一个 initialValues ,问的人实在是太多了
useEffect(function () {
if (syncToUrl || !props.initialValues || !preInitialValues || rest.request) return;
var isEqual = isDeepEqualReact(props.initialValues, preInitialValues);
noteOnce(isEqual, "initialValues \u53EA\u5728 form \u521D\u59CB\u5316\u65F6\u751F\u6548\uFF0C\u5982\u679C\u4F60\u9700\u8981\u5F02\u6B65\u52A0\u8F7D\u63A8\u8350\u4F7F\u7528 request\uFF0C\u6216\u8005 initialValues ? <Form/> : null ");
noteOnce(isEqual, "The initialValues only take effect when the form is initialized, if you need to load asynchronously recommended request, or the initialValues ? <Form/> : null ");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.initialValues]);
// 初始化给一个默认的 form
useImperativeHandle(propsFormRef, function () {
return _objectSpread(_objectSpread({}, formRef.current), formatValues);
}, [formatValues, formRef.current]);
useEffect(function () {
var _formRef$current3, _formRef$current3$get;
var finalValues = transformKey((_formRef$current3 = formRef.current) === null || _formRef$current3 === void 0 || (_formRef$current3$get = _formRef$current3.getFieldsValue) === null || _formRef$current3$get === void 0 ? void 0 : _formRef$current3$get.call(_formRef$current3, true), omitNil);
onInit === null || onInit === void 0 || onInit(finalValues, _objectSpread(_objectSpread({}, formRef.current), formatValues));
}, []);
return /*#__PURE__*/_jsx(ProFormContext.Provider, {
value: _objectSpread(_objectSpread({}, formatValues), {}, {
formRef: formRef
}),
children: /*#__PURE__*/_jsx(ConfigProvider, {
componentSize: rest.size || componentSize,
children: /*#__PURE__*/_jsxs(GridContext.Provider, {
value: {
grid: grid,
colProps: colProps
},
children: [rest.component !== false && /*#__PURE__*/_jsx("input", {
type: "text",
style: {
display: 'none'
}
}), content]
})
})
});
}
/** 自动的formKey 防止重复 */
var requestFormCacheId = 0;
function BaseForm(props) {
var _props$extraUrlParams2 = props.extraUrlParams,
extraUrlParams = _props$extraUrlParams2 === void 0 ? {} : _props$extraUrlParams2,
syncToUrl = props.syncToUrl,
isKeyPressSubmit = props.isKeyPressSubmit,
_props$syncToUrlAsImp = props.syncToUrlAsImportant,
syncToUrlAsImportant = _props$syncToUrlAsImp === void 0 ? false : _props$syncToUrlAsImp,
_props$syncToInitialV = props.syncToInitialValues,
syncToInitialValues = _props$syncToInitialV === void 0 ? true : _props$syncToInitialV,
children = props.children,
contentRender = props.contentRender,
submitter = props.submitter,
fieldProps = props.fieldProps,
proFieldProps = props.proFieldProps,
formItemProps = props.formItemProps,
groupProps = props.groupProps,
_props$dateFormatter = props.dateFormatter,
dateFormatter = _props$dateFormatter === void 0 ? 'string' : _props$dateFormatter,
propsFormRef = props.formRef,
onInit = props.onInit,
form = props.form,
formComponentType = props.formComponentType,
onReset = props.onReset,
grid = props.grid,
rowProps = props.rowProps,
colProps = props.colProps,
_props$omitNil2 = props.omitNil,
omitNil = _props$omitNil2 === void 0 ? true : _props$omitNil2,
request = props.request,
params = props.params,
initialValues = props.initialValues,
_props$formKey = props.formKey,
formKey = _props$formKey === void 0 ? requestFormCacheId : _props$formKey,
readonly = props.readonly,
onLoadingChange = props.onLoadingChange,
propsLoading = props.loading,
propRest = _objectWithoutProperties(props, _excluded2);
var formRef = useRef({});
var _useMountMergeState = useMountMergeState(false, {
onChange: onLoadingChange,
value: propsLoading
}),
_useMountMergeState2 = _slicedToArray(_useMountMergeState, 2),
loading = _useMountMergeState2[0],
setLoading = _useMountMergeState2[1];
var _useUrlSearchParams = useUrlSearchParams({}, {
disabled: !syncToUrl
}),
_useUrlSearchParams2 = _slicedToArray(_useUrlSearchParams, 2),
urlSearch = _useUrlSearchParams2[0],
setUrlSearch = _useUrlSearchParams2[1];
var curFormKey = useRef(nanoid());
useEffect(function () {
requestFormCacheId += 0;
}, []);
var _useFetchData = useFetchData({
request: request,
params: params,
proFieldKey: formKey
}),
_useFetchData2 = _slicedToArray(_useFetchData, 1),
initialData = _useFetchData2[0];
var _useContext = useContext(ConfigProvider.ConfigContext),
getPrefixCls = _useContext.getPrefixCls;
var prefixCls = getPrefixCls('pro-form');
// css
var _useStyle = useStyle('ProForm', function (token) {
return _defineProperty({}, ".".concat(prefixCls), _defineProperty({}, "> div:not(".concat(token.proComponentsCls, "-form-light-filter)"), {
'.pro-field': {
maxWidth: '100%',
'@media screen and (max-width: 575px)': {
// 减少了 form 的 padding
maxWidth: 'calc(93vw - 48px)'
},
// 适用于短数字,短文本或者选项
'&-xs': {
width: 104
},
'&-s': {
width: 216
},
// 适用于较短字段录入、如姓名、电话、ID 等。
'&-sm': {
width: 216
},
'&-m': {
width: 328
},
// 标准宽度,适用于大部分字段长度
'&-md': {
width: 328
},
'&-l': {
width: 440
},
// 适用于较长字段录入,如长网址、标签组、文件路径等。
'&-lg': {
width: 440
},
// 适用于长文本录入,如长链接、描述、备注等,通常搭配自适应多行输入框或定高文本域使用。
'&-xl': {
width: 552
}
}
}));
}),
wrapSSR = _useStyle.wrapSSR,
hashId = _useStyle.hashId;
// 如果为 false,不需要触发设置进去
var _useState = useState(function () {
if (!syncToUrl) {
return {};
}
return genParams(syncToUrl, urlSearch, 'get');
}),
_useState2 = _slicedToArray(_useState, 2),
urlParamsMergeInitialValues = _useState2[0],
setUrlParamsMergeInitialValues = _useState2[1];
/** 保存 transformKeyRef,用于对表单key transform */
var transformKeyRef = useRef({});
var fieldsValueType = useRef({});
/** 使用 callback 的类型 */
var transformKey = useRefFunction(function (values, paramsOmitNil, parentKey) {
return transformKeySubmitValue(conversionMomentValue(values, dateFormatter, fieldsValueType.current, paramsOmitNil, parentKey), transformKeyRef.current, paramsOmitNil);
});
useEffect(function () {
if (syncToInitialValues) return;
setUrlParamsMergeInitialValues({});
}, [syncToInitialValues]);
var getGenParams = useRefFunction(function () {
return _objectSpread(_objectSpread({}, urlSearch), extraUrlParams);
});
useEffect(function () {
if (!syncToUrl) return;
setUrlSearch(genParams(syncToUrl, getGenParams(), 'set'));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [extraUrlParams, getGenParams, syncToUrl]);
var getPopupContainer = useMemo(function () {
if (typeof window === 'undefined') return undefined;
// 如果在 drawerForm 和 modalForm 里就渲染dom到父节点里
// modalForm 可能高度太小不适合
if (formComponentType && ['DrawerForm'].includes(formComponentType)) {
return function (e) {
return e.parentNode || document.body;
};
}
return undefined;
}, [formComponentType]);
var onFinish = useRefFunction( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
var _formRef$current4, _formRef$current4$get, finalValues, response, _formRef$current5, _formRef$current5$get, syncToUrlParams;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (propRest.onFinish) {
_context2.next = 2;
break;
}
return _context2.abrupt("return");
case 2:
if (!loading) {
_context2.next = 4;
break;
}
return _context2.abrupt("return");
case 4:
_context2.prev = 4;
finalValues = formRef === null || formRef === void 0 || (_formRef$current4 = formRef.current) === null || _formRef$current4 === void 0 || (_formRef$current4$get = _formRef$current4.getFieldsFormatValue) === null || _formRef$current4$get === void 0 ? void 0 : _formRef$current4$get.call(_formRef$current4);
response = propRest.onFinish(finalValues);
if (response instanceof Promise) {
setLoading(true);
}
_context2.next = 10;
return response;
case 10:
if (syncToUrl) {
// 把没有的值设置为未定义可以删掉 url 的参数
syncToUrlParams = Object.keys(formRef === null || formRef === void 0 || (_formRef$current5 = formRef.current) === null || _formRef$current5 === void 0 || (_formRef$current5$get = _formRef$current5.getFieldsFormatValue) === null || _formRef$current5$get === void 0 ? void 0 : _formRef$current5$get.call(_formRef$current5, undefined, false)).reduce(function (pre, next) {
var _finalValues$next;
return _objectSpread(_objectSpread({}, pre), {}, _defineProperty({}, next, (_finalValues$next = finalValues[next]) !== null && _finalValues$next !== void 0 ? _finalValues$next : undefined));
}, extraUrlParams); // fix #3547: 当原先在url中存在的字段被删除时,应该将 params 中的该字段设置为 undefined,以便触发url同步删除
Object.keys(urlSearch).forEach(function (key) {
if (syncToUrlParams[key] !== false && syncToUrlParams[key] !== 0 && !syncToUrlParams[key]) {
syncToUrlParams[key] = undefined;
}
});
/** 在同步到 url 上时对参数进行转化 */
setUrlSearch(genParams(syncToUrl, syncToUrlParams, 'set'));
}
setLoading(false);
_context2.next = 18;
break;
case 14:
_context2.prev = 14;
_context2.t0 = _context2["catch"](4);
console.log(_context2.t0);
setLoading(false);
case 18:
case "end":
return _context2.stop();
}
}, _callee2, null, [[4, 14]]);
})));
// 初始化给一个默认的 form
useImperativeHandle(propsFormRef, function () {
return formRef.current;
}, [!initialData]);
if (!initialData && props.request) {
return /*#__PURE__*/_jsx("div", {
style: {
paddingTop: 50,
paddingBottom: 50,
textAlign: 'center'
},
children: /*#__PURE__*/_jsx(Spin, {})
});
}
return wrapSSR( /*#__PURE__*/_jsx(EditOrReadOnlyContext.Provider, {
value: {
mode: props.readonly ? 'read' : 'edit'
},
children: /*#__PURE__*/_jsx(ProConfigProvider, {
needDeps: true,
children: /*#__PURE__*/_jsx(FieldContext.Provider, {
value: {
formRef: formRef,
fieldProps: fieldProps,
proFieldProps: proFieldProps,
formItemProps: formItemProps,
groupProps: groupProps,
formComponentType: formComponentType,
getPopupContainer: getPopupContainer,
formKey: curFormKey.current,
setFieldValueType: function setFieldValueType(name, _ref4) {
var _ref4$valueType = _ref4.valueType,
valueType = _ref4$valueType === void 0 ? 'text' : _ref4$valueType,
dateFormat = _ref4.dateFormat,
transform = _ref4.transform;
if (!Array.isArray(name)) return;
transformKeyRef.current = namePathSet(transformKeyRef.current, name, transform);
fieldsValueType.current = namePathSet(fieldsValueType.current, name, {
valueType: valueType,
dateFormat: dateFormat
});
}
},
children: /*#__PURE__*/_jsx(FormListContext.Provider, {
value: {},
children: /*#__PURE__*/_jsx(Form, _objectSpread(_objectSpread({
onKeyPress: function onKeyPress(event) {
if (!isKeyPressSubmit) return;
if (event.key === 'Enter') {
var _formRef$current6;
(_formRef$current6 = formRef.current) === null || _formRef$current6 === void 0 || _formRef$current6.submit();
}
},
autoComplete: "off",
form: form
}, omit(propRest, ['ref', 'labelWidth', 'autoFocusFirstInput'])), {}, {
ref: function ref(instance) {
if (!formRef.current) return;
formRef.current.nativeElement = instance === null || instance === void 0 ? void 0 : instance.nativeElement;
}
// 组合 urlSearch 和 initialValues
,
initialValues: syncToUrlAsImportant ? _objectSpread(_objectSpread(_objectSpread({}, initialValues), initialData), urlParamsMergeInitialValues) : _objectSpread(_objectSpread(_objectSpread({}, urlParamsMergeInitialValues), initialValues), initialData),
onValuesChange: function onValuesChange(changedValues, values) {
var _propRest$onValuesCha;
propRest === null || propRest === void 0 || (_propRest$onValuesCha = propRest.onValuesChange) === null || _propRest$onValuesCha === void 0 || _propRest$onValuesCha.call(propRest, transformKey(changedValues, !!omitNil), transformKey(values, !!omitNil));
},
className: classNames(props.className, prefixCls, hashId),
onFinish: onFinish,
children: /*#__PURE__*/_jsx(BaseFormComponents, _objectSpread(_objectSpread({
transformKey: transformKey,
autoComplete: "off",
loading: loading,
onUrlSearchChange: setUrlSearch
}, props), {}, {
formRef: formRef,
initialValues: _objectSpread(_objectSpread({}, initialValues), initialData)
}))
}))
})
})
})
}));
}
export { BaseForm };