index.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. "use strict";
  2. "use client";
  3. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  4. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  5. Object.defineProperty(exports, "__esModule", {
  6. value: true
  7. });
  8. exports.default = void 0;
  9. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  10. var React = _interopRequireWildcard(require("react"));
  11. var _classnames = _interopRequireDefault(require("classnames"));
  12. var _rcFieldForm = require("rc-field-form");
  13. var _useState = _interopRequireDefault(require("rc-util/lib/hooks/useState"));
  14. var _ref = require("rc-util/lib/ref");
  15. var _reactNode = require("../../_util/reactNode");
  16. var _warning = require("../../_util/warning");
  17. var _configProvider = require("../../config-provider");
  18. var _useCSSVarCls = _interopRequireDefault(require("../../config-provider/hooks/useCSSVarCls"));
  19. var _context = require("../context");
  20. var _useChildren = _interopRequireDefault(require("../hooks/useChildren"));
  21. var _useFormItemStatus = _interopRequireDefault(require("../hooks/useFormItemStatus"));
  22. var _useFrameState = _interopRequireDefault(require("../hooks/useFrameState"));
  23. var _useItemRef = _interopRequireDefault(require("../hooks/useItemRef"));
  24. var _style = _interopRequireDefault(require("../style"));
  25. var _util = require("../util");
  26. var _ItemHolder = _interopRequireDefault(require("./ItemHolder"));
  27. var _StatusProvider = _interopRequireDefault(require("./StatusProvider"));
  28. const NAME_SPLIT = '__SPLIT__';
  29. const _ValidateStatuses = ['success', 'warning', 'error', 'validating', ''];
  30. // https://github.com/ant-design/ant-design/issues/46417
  31. // `getValueProps` may modify the value props name,
  32. // we should check if the control is similar.
  33. function isSimilarControl(a, b) {
  34. const keysA = Object.keys(a);
  35. const keysB = Object.keys(b);
  36. return keysA.length === keysB.length && keysA.every(key => {
  37. const propValueA = a[key];
  38. const propValueB = b[key];
  39. return propValueA === propValueB || typeof propValueA === 'function' || typeof propValueB === 'function';
  40. });
  41. }
  42. const MemoInput = /*#__PURE__*/React.memo(({
  43. children
  44. }) => children, (prev, next) => isSimilarControl(prev.control, next.control) && prev.update === next.update && prev.childProps.length === next.childProps.length && prev.childProps.every((value, index) => value === next.childProps[index]));
  45. function genEmptyMeta() {
  46. return {
  47. errors: [],
  48. warnings: [],
  49. touched: false,
  50. validating: false,
  51. name: [],
  52. validated: false
  53. };
  54. }
  55. function InternalFormItem(props) {
  56. const {
  57. name,
  58. noStyle,
  59. className,
  60. dependencies,
  61. prefixCls: customizePrefixCls,
  62. shouldUpdate,
  63. rules,
  64. children,
  65. required,
  66. label,
  67. messageVariables,
  68. trigger = 'onChange',
  69. validateTrigger,
  70. hidden,
  71. help,
  72. layout
  73. } = props;
  74. const {
  75. getPrefixCls
  76. } = React.useContext(_configProvider.ConfigContext);
  77. const {
  78. name: formName
  79. } = React.useContext(_context.FormContext);
  80. const mergedChildren = (0, _useChildren.default)(children);
  81. const isRenderProps = typeof mergedChildren === 'function';
  82. const notifyParentMetaChange = React.useContext(_context.NoStyleItemContext);
  83. const {
  84. validateTrigger: contextValidateTrigger
  85. } = React.useContext(_rcFieldForm.FieldContext);
  86. const mergedValidateTrigger = validateTrigger !== undefined ? validateTrigger : contextValidateTrigger;
  87. const hasName = !(name === undefined || name === null);
  88. const prefixCls = getPrefixCls('form', customizePrefixCls);
  89. // Style
  90. const rootCls = (0, _useCSSVarCls.default)(prefixCls);
  91. const [wrapCSSVar, hashId, cssVarCls] = (0, _style.default)(prefixCls, rootCls);
  92. // ========================= Warn =========================
  93. const warning = (0, _warning.devUseWarning)('Form.Item');
  94. if (process.env.NODE_ENV !== 'production') {
  95. process.env.NODE_ENV !== "production" ? warning(name !== null, 'usage', '`null` is passed as `name` property') : void 0;
  96. }
  97. // ========================= MISC =========================
  98. // Get `noStyle` required info
  99. const listContext = React.useContext(_rcFieldForm.ListContext);
  100. const fieldKeyPathRef = React.useRef(null);
  101. // ======================== Errors ========================
  102. // >>>>> Collect sub field errors
  103. const [subFieldErrors, setSubFieldErrors] = (0, _useFrameState.default)({});
  104. // >>>>> Current field errors
  105. const [meta, setMeta] = (0, _useState.default)(() => genEmptyMeta());
  106. const onMetaChange = nextMeta => {
  107. // This keyInfo is not correct when field is removed
  108. // Since origin keyManager no longer keep the origin key anymore
  109. // Which means we need cache origin one and reuse when removed
  110. const keyInfo = listContext === null || listContext === void 0 ? void 0 : listContext.getKey(nextMeta.name);
  111. // Destroy will reset all the meta
  112. setMeta(nextMeta.destroy ? genEmptyMeta() : nextMeta, true);
  113. // Bump to parent since noStyle
  114. if (noStyle && help !== false && notifyParentMetaChange) {
  115. let namePath = nextMeta.name;
  116. if (!nextMeta.destroy) {
  117. if (keyInfo !== undefined) {
  118. const [fieldKey, restPath] = keyInfo;
  119. namePath = [fieldKey].concat((0, _toConsumableArray2.default)(restPath));
  120. fieldKeyPathRef.current = namePath;
  121. }
  122. } else {
  123. // Use origin cache data
  124. namePath = fieldKeyPathRef.current || namePath;
  125. }
  126. notifyParentMetaChange(nextMeta, namePath);
  127. }
  128. };
  129. // >>>>> Collect noStyle Field error to the top FormItem
  130. const onSubItemMetaChange = (subMeta, uniqueKeys) => {
  131. // Only `noStyle` sub item will trigger
  132. setSubFieldErrors(prevSubFieldErrors => {
  133. const clone = Object.assign({}, prevSubFieldErrors);
  134. // name: ['user', 1] + key: [4] = ['user', 4]
  135. const mergedNamePath = [].concat((0, _toConsumableArray2.default)(subMeta.name.slice(0, -1)), (0, _toConsumableArray2.default)(uniqueKeys));
  136. const mergedNameKey = mergedNamePath.join(NAME_SPLIT);
  137. if (subMeta.destroy) {
  138. // Remove
  139. delete clone[mergedNameKey];
  140. } else {
  141. // Update
  142. clone[mergedNameKey] = subMeta;
  143. }
  144. return clone;
  145. });
  146. };
  147. // >>>>> Get merged errors
  148. const [mergedErrors, mergedWarnings] = React.useMemo(() => {
  149. const errorList = (0, _toConsumableArray2.default)(meta.errors);
  150. const warningList = (0, _toConsumableArray2.default)(meta.warnings);
  151. Object.values(subFieldErrors).forEach(subFieldError => {
  152. errorList.push.apply(errorList, (0, _toConsumableArray2.default)(subFieldError.errors || []));
  153. warningList.push.apply(warningList, (0, _toConsumableArray2.default)(subFieldError.warnings || []));
  154. });
  155. return [errorList, warningList];
  156. }, [subFieldErrors, meta.errors, meta.warnings]);
  157. // ===================== Children Ref =====================
  158. const getItemRef = (0, _useItemRef.default)();
  159. // ======================== Render ========================
  160. function renderLayout(baseChildren, fieldId, isRequired) {
  161. if (noStyle && !hidden) {
  162. return /*#__PURE__*/React.createElement(_StatusProvider.default, {
  163. prefixCls: prefixCls,
  164. hasFeedback: props.hasFeedback,
  165. validateStatus: props.validateStatus,
  166. meta: meta,
  167. errors: mergedErrors,
  168. warnings: mergedWarnings,
  169. noStyle: true,
  170. name: name
  171. }, baseChildren);
  172. }
  173. return /*#__PURE__*/React.createElement(_ItemHolder.default, Object.assign({
  174. key: "row"
  175. }, props, {
  176. className: (0, _classnames.default)(className, cssVarCls, rootCls, hashId),
  177. prefixCls: prefixCls,
  178. fieldId: fieldId,
  179. isRequired: isRequired,
  180. errors: mergedErrors,
  181. warnings: mergedWarnings,
  182. meta: meta,
  183. onSubItemMetaChange: onSubItemMetaChange,
  184. layout: layout,
  185. name: name
  186. }), baseChildren);
  187. }
  188. if (!hasName && !isRenderProps && !dependencies) {
  189. return wrapCSSVar(renderLayout(mergedChildren));
  190. }
  191. let variables = {};
  192. if (typeof label === 'string') {
  193. variables.label = label;
  194. } else if (name) {
  195. variables.label = String(name);
  196. }
  197. if (messageVariables) {
  198. variables = Object.assign(Object.assign({}, variables), messageVariables);
  199. }
  200. // >>>>> With Field
  201. return wrapCSSVar(/*#__PURE__*/React.createElement(_rcFieldForm.Field, Object.assign({}, props, {
  202. messageVariables: variables,
  203. trigger: trigger,
  204. validateTrigger: mergedValidateTrigger,
  205. onMetaChange: onMetaChange
  206. }), (control, renderMeta, context) => {
  207. const mergedName = (0, _util.toArray)(name).length && renderMeta ? renderMeta.name : [];
  208. const fieldId = (0, _util.getFieldId)(mergedName, formName);
  209. const isRequired = required !== undefined ? required : !!(rules === null || rules === void 0 ? void 0 : rules.some(rule => {
  210. if (rule && typeof rule === 'object' && rule.required && !rule.warningOnly) {
  211. return true;
  212. }
  213. if (typeof rule === 'function') {
  214. const ruleEntity = rule(context);
  215. return (ruleEntity === null || ruleEntity === void 0 ? void 0 : ruleEntity.required) && !(ruleEntity === null || ruleEntity === void 0 ? void 0 : ruleEntity.warningOnly);
  216. }
  217. return false;
  218. }));
  219. // ======================= Children =======================
  220. const mergedControl = Object.assign({}, control);
  221. let childNode = null;
  222. process.env.NODE_ENV !== "production" ? warning(!(shouldUpdate && dependencies), 'usage', "`shouldUpdate` and `dependencies` shouldn't be used together. See https://u.ant.design/form-deps.") : void 0;
  223. if (Array.isArray(mergedChildren) && hasName) {
  224. process.env.NODE_ENV !== "production" ? warning(false, 'usage', 'A `Form.Item` with a `name` prop must have a single child element. For information on how to render more complex form items, see https://u.ant.design/complex-form-item.') : void 0;
  225. childNode = mergedChildren;
  226. } else if (isRenderProps && (!(shouldUpdate || dependencies) || hasName)) {
  227. process.env.NODE_ENV !== "production" ? warning(!!(shouldUpdate || dependencies), 'usage', 'A `Form.Item` with a render function must have either `shouldUpdate` or `dependencies`.') : void 0;
  228. process.env.NODE_ENV !== "production" ? warning(!hasName, 'usage', 'A `Form.Item` with a render function cannot be a field, and thus cannot have a `name` prop.') : void 0;
  229. } else if (dependencies && !isRenderProps && !hasName) {
  230. process.env.NODE_ENV !== "production" ? warning(false, 'usage', 'Must set `name` or use a render function when `dependencies` is set.') : void 0;
  231. } else if (/*#__PURE__*/React.isValidElement(mergedChildren)) {
  232. process.env.NODE_ENV !== "production" ? warning(mergedChildren.props.defaultValue === undefined, 'usage', '`defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.') : void 0;
  233. const childProps = Object.assign(Object.assign({}, mergedChildren.props), mergedControl);
  234. if (!childProps.id) {
  235. childProps.id = fieldId;
  236. }
  237. if (help || mergedErrors.length > 0 || mergedWarnings.length > 0 || props.extra) {
  238. const describedbyArr = [];
  239. if (help || mergedErrors.length > 0) {
  240. describedbyArr.push(`${fieldId}_help`);
  241. }
  242. if (props.extra) {
  243. describedbyArr.push(`${fieldId}_extra`);
  244. }
  245. childProps['aria-describedby'] = describedbyArr.join(' ');
  246. }
  247. if (mergedErrors.length > 0) {
  248. childProps['aria-invalid'] = 'true';
  249. }
  250. if (isRequired) {
  251. childProps['aria-required'] = 'true';
  252. }
  253. if ((0, _ref.supportRef)(mergedChildren)) {
  254. childProps.ref = getItemRef(mergedName, mergedChildren);
  255. }
  256. // We should keep user origin event handler
  257. const triggers = new Set([].concat((0, _toConsumableArray2.default)((0, _util.toArray)(trigger)), (0, _toConsumableArray2.default)((0, _util.toArray)(mergedValidateTrigger))));
  258. triggers.forEach(eventName => {
  259. childProps[eventName] = (...args) => {
  260. var _a2, _c2;
  261. var _a, _b, _c;
  262. (_a = mergedControl[eventName]) === null || _a === void 0 ? void 0 : (_a2 = _a).call.apply(_a2, [mergedControl].concat(args));
  263. (_c = (_b = mergedChildren.props)[eventName]) === null || _c === void 0 ? void 0 : (_c2 = _c).call.apply(_c2, [_b].concat(args));
  264. };
  265. });
  266. // List of props that need to be watched for changes -> if changes are detected in MemoInput -> rerender
  267. const watchingChildProps = [childProps['aria-required'], childProps['aria-invalid'], childProps['aria-describedby']];
  268. childNode = /*#__PURE__*/React.createElement(MemoInput, {
  269. control: mergedControl,
  270. update: mergedChildren,
  271. childProps: watchingChildProps
  272. }, (0, _reactNode.cloneElement)(mergedChildren, childProps));
  273. } else if (isRenderProps && (shouldUpdate || dependencies) && !hasName) {
  274. childNode = mergedChildren(context);
  275. } else {
  276. process.env.NODE_ENV !== "production" ? warning(!mergedName.length || !!noStyle, 'usage', '`name` is only used for validate React element. If you are using Form.Item as layout display, please remove `name` instead.') : void 0;
  277. childNode = mergedChildren;
  278. }
  279. return renderLayout(childNode, fieldId, isRequired);
  280. }));
  281. }
  282. const FormItem = InternalFormItem;
  283. FormItem.useStatus = _useFormItemStatus.default;
  284. var _default = exports.default = FormItem;