@zat-design/sisyphus-react 4.4.3-beta.2 → 4.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,30 @@
1
+ import { FormInstance } from 'antd';
2
+ import { InternalNamePath, NamePath } from 'antd/lib/form/interface';
3
+ import { DiffOriginalParams } from '../../utils/diffOriginal';
4
+ export interface GetOriginalValueParams {
5
+ namePath: InternalNamePath;
6
+ originalName: InternalNamePath;
7
+ originalNames?: InternalNamePath[];
8
+ originalValues?: any;
9
+ rowKeyPath?: InternalNamePath;
10
+ form: FormInstance;
11
+ }
12
+ export interface Props {
13
+ name?: NamePath;
14
+ names?: NamePath[];
15
+ originalName?: NamePath;
16
+ originalNames?: NamePath[];
17
+ namesStr?: NamePath;
18
+ originalValues?: any;
19
+ form: FormInstance;
20
+ onDiff?: DiffOriginalParams['onDiff'];
21
+ [name: string]: any;
22
+ }
23
+ /** RenderField 的 props 多为表格运行期动态结构(column/config/record),保留显式 any */
24
+ export interface RenderFieldComparableProps {
25
+ text?: any;
26
+ record?: any;
27
+ index: number;
28
+ column?: any;
29
+ config?: any;
30
+ }
@@ -0,0 +1,22 @@
1
+ import { InternalNamePath, NamePath } from 'antd/lib/form/interface';
2
+ import { GetOriginalValueParams, RenderFieldComparableProps } from './propsType';
3
+ /** 列配置中不应透传到 Form.Item 或 DOM 的字段(与 ProForm Render 保持一致) */
4
+ export declare const OMIT_FORM_ITEM_AND_DOM_KEYS: string[];
5
+ /** 克隆子元素时需从 props 中剔除,避免透传到 div 等 DOM 导致 React 警告 */
6
+ export declare const OMIT_FROM_DOM_KEYS: string[];
7
+ export declare const toNamePath: (name: NamePath) => InternalNamePath;
8
+ export declare const toNamePaths: (names: NamePath[]) => InternalNamePath[];
9
+ export declare const getOriginalValue: ({ namePath, originalName, originalNames, originalValues, rowKeyPath, form, }: GetOriginalValueParams) => {
10
+ originalValue: any;
11
+ originRecord: any;
12
+ record: any;
13
+ } | {
14
+ originalValue: any;
15
+ originRecord: any;
16
+ record?: undefined;
17
+ };
18
+ /**
19
+ * memo 自定义比较函数:只有关键 props 变化时才重新渲染。
20
+ * 从 RenderField 拆出,行为与原内联实现保持一致。
21
+ */
22
+ export declare const arePropsEqual: (prevProps: RenderFieldComparableProps, nextProps: RenderFieldComparableProps) => boolean;
@@ -0,0 +1,203 @@
1
+ import _isFunction from "lodash/isFunction";
2
+ import _isEqualWith from "lodash/isEqualWith";
3
+ import _isEqual from "lodash/isEqual";
4
+ import _get from "lodash/get";
5
+ import { customEqualForFunction } from "../../../utils";
6
+ import { getNamePath } from "../../utils/tools";
7
+ /** 列配置中不应透传到 Form.Item 或 DOM 的字段(与 ProForm Render 保持一致) */
8
+ export const OMIT_FORM_ITEM_AND_DOM_KEYS = ['format', 'toISOString', 'toCSTString', 'switchValue', 'precision', 'clearNotShow', 'dependNames', 'shouldCellUpdate' // 表格内部性能优化属性,不应传递给 Form.Item
9
+ ];
10
+
11
+ /** 克隆子元素时需从 props 中剔除,避免透传到 div 等 DOM 导致 React 警告 */
12
+ export const OMIT_FROM_DOM_KEYS = ['disabled',
13
+ // div 不支持 disabled,且值可能非 string/number
14
+ 'toCSTString', 'toISOString', 'format', 'switchValue', 'precision', 'clearNotShow', 'dependNames'];
15
+ export const toNamePath = name => {
16
+ if (Array.isArray(name)) {
17
+ return name;
18
+ }
19
+ return [name];
20
+ };
21
+ export const toNamePaths = names => {
22
+ return names.map(name => toNamePath(name));
23
+ };
24
+ export const getOriginalValue = ({
25
+ namePath,
26
+ originalName,
27
+ originalNames,
28
+ originalValues,
29
+ rowKeyPath,
30
+ form
31
+ }) => {
32
+ if (!originalValues) {
33
+ return undefined;
34
+ }
35
+ let originRecord;
36
+ if (rowKeyPath) {
37
+ const rowValueNamePath = namePath.slice(0, rowKeyPath.length - 1); // 表单中变动值所在行
38
+ const rowKeyName = rowKeyPath[rowKeyPath.length - 1]; // rowKey在行内的name
39
+
40
+ const rowValue = form.getFieldValue(rowValueNamePath);
41
+ if (!rowValue) return undefined;
42
+ const keyValue = rowValue[rowKeyName]; // 获取表单中rowKey值
43
+ if (!keyValue) return undefined;
44
+ const originalValueList = _get(originalValues, originalName.slice(0, rowKeyPath.length - 2));
45
+ originRecord = originalValueList?.find(item => {
46
+ return item[rowKeyPath[rowKeyPath.length - 1]] === keyValue;
47
+ });
48
+ let originalValue;
49
+ if (originalNames?.length) {
50
+ const originalNamesValue = originalNames.map(originalName => {
51
+ return _get(originRecord, originalName.slice(rowKeyPath.length - 1));
52
+ });
53
+
54
+ // 有可能出现数组中全是undefined的情况 视为没有值
55
+ const fillUndefined = originalNamesValue.every(valItem => valItem === undefined);
56
+ originalValue = fillUndefined ? undefined : originalNamesValue;
57
+ } else {
58
+ originalValue = _get(originRecord, originalName.slice(rowKeyPath.length - 1));
59
+ }
60
+ return {
61
+ originalValue,
62
+ originRecord,
63
+ record: rowValue
64
+ };
65
+ }
66
+
67
+ // 这个方法是给editTable专用的 暂时不存在不传rowKey的情况
68
+ return {
69
+ originalValue: originalNames?.length ? originalNames.map(originalName => _get(originalValues, originalName)) : _get(originalValues, originalName),
70
+ originRecord
71
+ };
72
+ };
73
+
74
+ /**
75
+ * memo 自定义比较函数:只有关键 props 变化时才重新渲染。
76
+ * 从 RenderField 拆出,行为与原内联实现保持一致。
77
+ */
78
+ export const arePropsEqual = (prevProps, nextProps) => {
79
+ const {
80
+ text: prevText,
81
+ record: prevRecord,
82
+ index: prevIndex,
83
+ column: prevColumn,
84
+ config: prevConfig
85
+ } = prevProps;
86
+ const {
87
+ text: nextText,
88
+ record: nextRecord,
89
+ index: nextIndex,
90
+ column: nextColumn,
91
+ config: nextConfig
92
+ } = nextProps;
93
+
94
+ // 函数型动态属性(component/editRender/fieldProps/rules/required/disabled/isEditable/valueType)
95
+ // 可能依赖行内兄弟字段;行对象为同引用(原地修改)时,浅比较无法区分,需强制重渲染
96
+ const hasFunctionDependency = _isFunction(prevColumn?.component) || _isFunction(prevColumn?.editRender) || _isFunction(prevColumn?.fieldProps) || _isFunction(prevColumn?.rules) || _isFunction(prevColumn?.required) || _isFunction(prevColumn?.disabled) || _isFunction(prevColumn?.isEditable) || _isFunction(prevColumn?.valueType) || _isFunction(nextColumn?.component) || _isFunction(nextColumn?.editRender) || _isFunction(nextColumn?.fieldProps) || _isFunction(nextColumn?.rules) || _isFunction(nextColumn?.required) || _isFunction(nextColumn?.disabled) || _isFunction(nextColumn?.isEditable) || _isFunction(nextColumn?.valueType);
97
+ if (hasFunctionDependency && prevRecord === nextRecord) {
98
+ return false;
99
+ }
100
+
101
+ // 构建新的参数格式(与 ProForm 保持一致)
102
+ const prevNamePath = getNamePath(prevConfig?.name, prevConfig?.virtualKey);
103
+ const nextNamePath = getNamePath(nextConfig?.name, nextConfig?.virtualKey);
104
+ const prevReactiveParams = {
105
+ form: prevConfig?.form,
106
+ index: prevIndex,
107
+ namePath: [...prevNamePath, prevIndex]
108
+ };
109
+ const nextReactiveParams = {
110
+ form: nextConfig?.form,
111
+ index: nextIndex,
112
+ namePath: [...nextNamePath, nextIndex]
113
+ };
114
+ if (_isFunction(prevColumn?.disabled) && _isFunction(nextColumn?.disabled)) {
115
+ if (prevColumn?.disabled(prevRecord, prevReactiveParams) !== nextColumn?.disabled(nextRecord, nextReactiveParams)) {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ // fieldProps 函数化直接更新,无法比对返回值是否一致
121
+ // 优化:不直接调用函数,而是比较输入参数(record 和 reactiveParams)
122
+ // 如果输入参数相同,fieldProps 的返回值应该相同(纯函数假设)
123
+ if (_isFunction(prevColumn?.fieldProps) && _isFunction(nextColumn?.fieldProps)) {
124
+ // 比较 record 数据是否变化
125
+ if (!_isEqualWith(prevRecord, nextRecord, customEqualForFunction)) {
126
+ return false;
127
+ }
128
+ // reactiveParams 中的 form、index、namePath 已经在外层比较过了,无需重复比较
129
+ }
130
+ // fieldProps 为对象时,必须比较配置变化(如 dataSource 异步更新)
131
+ if (!_isFunction(prevColumn?.fieldProps) && !_isFunction(nextColumn?.fieldProps)) {
132
+ const isFieldPropsEqual = _isEqualWith(prevColumn?.fieldProps, nextColumn?.fieldProps, customEqualForFunction);
133
+ if (!isFieldPropsEqual) {
134
+ return false;
135
+ }
136
+ }
137
+
138
+ // 通用函数比较方法
139
+ // 优化:不直接调用函数,而是比较函数引用和输入参数
140
+ const compareFunctionResult = (prevCol, nextCol, prevValues, nextValues, _prevReactiveParams, _nextReactiveParams, functionName) => {
141
+ const prevFunc = prevCol?.[functionName];
142
+ const nextFunc = nextCol?.[functionName];
143
+ if (_isFunction(prevFunc) && _isFunction(nextFunc)) {
144
+ // 函数引用变化说明闭包可能捕获了新的外部状态(如异步加载的 list),必须重渲染
145
+ if (prevFunc !== nextFunc) return false;
146
+ // 同引用函数,比较输入参数(纯函数假设:输入相同则输出相同)
147
+ return _isEqualWith(prevValues, nextValues, customEqualForFunction);
148
+ }
149
+ return true; // 如果不是函数或只有一个是函数,认为相等
150
+ };
151
+
152
+ // 使用简化后的比较逻辑
153
+ const functionFields = ['rules', 'component', 'desensitization', 'isEditable', 'required'];
154
+ if (functionFields.some(field => !compareFunctionResult(prevColumn, nextColumn, prevRecord, nextRecord, prevReactiveParams, nextReactiveParams, field))) {
155
+ return false;
156
+ }
157
+
158
+ // 基本props比较
159
+ if (!_isEqual(prevText, nextText) || prevIndex !== nextIndex) {
160
+ return false;
161
+ }
162
+
163
+ // 记录关键字段比较(避免完整对象比较的性能开销)
164
+ if (prevRecord?.rowKey !== nextRecord?.rowKey || prevRecord?._addFlag !== nextRecord?._addFlag) {
165
+ return false;
166
+ }
167
+
168
+ // 列配置比较(只比较关键字段),required,disabled为函数时,需要重新计算
169
+ if (prevColumn?.dataIndex !== nextColumn?.dataIndex || prevColumn?.type !== nextColumn?.type || prevColumn?.name !== nextColumn?.name) {
170
+ return false;
171
+ }
172
+
173
+ // config中关键字段比较
174
+ if (prevConfig?._isEditing !== nextConfig?._isEditing || prevConfig?.mode !== nextConfig?.mode) {
175
+ return false;
176
+ }
177
+
178
+ // 当前单元格的值比较
179
+ const prevDataIndex = prevColumn?.dataIndex;
180
+ const nextDataIndex = nextColumn?.dataIndex;
181
+ if (prevDataIndex && nextDataIndex && prevDataIndex === nextDataIndex) {
182
+ if (prevRecord?.[prevDataIndex] !== nextRecord?.[nextDataIndex]) {
183
+ return false;
184
+ }
185
+ }
186
+
187
+ // 特殊处理:当使用自定义 component 函数时,比较整个 record 对象
188
+ // 因为自定义组件可能依赖 record 中的其他字段(不只是当前列的 dataIndex)
189
+ if (_isFunction(prevColumn?.component) || _isFunction(nextColumn?.component)) {
190
+ // 浅比较 record 的所有属性
191
+ const prevKeys = Object.keys(prevRecord || {});
192
+ const nextKeys = Object.keys(nextRecord || {});
193
+ if (prevKeys.length !== nextKeys.length) {
194
+ return false;
195
+ }
196
+
197
+ // 使用 some 方法代替 for 循环
198
+ if (prevKeys.some(key => prevRecord?.[key] !== nextRecord?.[key])) {
199
+ return false;
200
+ }
201
+ }
202
+ return true;
203
+ };
@@ -75,58 +75,58 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
75
75
  confirm?: boolean | import("antd").ModalFuncProps | import("../../../render/propsType").FunctionArgs<any, boolean | import("antd").ModalFuncProps>;
76
76
  show?: boolean | ReactiveFunction<any, boolean>;
77
77
  component?: React.ReactNode | ReactiveFunction<any, React.ReactNode>;
78
- toISOString?: boolean;
79
- toCSTString?: boolean;
80
- switchValue?: [any, any];
81
- clearNotShow?: boolean;
82
- trim?: boolean;
83
- upperCase?: boolean;
84
- normalize?: (value: any, prevValue: any, allValues: import("@rc-component/form/lib/interface").Store) => any;
78
+ className?: string;
79
+ hidden?: boolean;
80
+ id?: string;
81
+ style?: React.CSSProperties;
82
+ children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
83
+ onReset?: () => void;
84
+ prefixCls?: string;
85
+ isView?: boolean;
86
+ desensitization?: [number, number] | ReactiveFunction<any, [number, number]>;
87
+ rootClassName?: string;
88
+ status?: "" | "warning" | "error" | "success" | "validating";
89
+ vertical?: boolean;
85
90
  getValueProps?: ((value: any) => Record<string, unknown>) & ((value: any) => Record<string, unknown>);
86
- shouldUpdate?: import("@rc-component/form/lib/Field").ShouldUpdate<any>;
87
91
  colon?: boolean;
88
92
  htmlFor?: string;
89
93
  labelAlign?: import("antd/es/form/interface").FormLabelAlign;
90
94
  labelCol?: import("antd").ColProps;
91
- vertical?: boolean;
92
- children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
93
95
  getValueFromEvent?: (...args: import("@rc-component/form/lib/interface").EventArgs) => any;
96
+ normalize?: (value: any, prevValue: any, allValues: import("@rc-component/form/lib/interface").Store) => any;
97
+ shouldUpdate?: import("@rc-component/form/lib/Field").ShouldUpdate<any>;
94
98
  trigger?: string;
95
99
  validateTrigger?: string | false | string[];
96
100
  validateDebounce?: number;
97
101
  valuePropName?: string;
98
102
  messageVariables?: Record<string, string>;
99
103
  initialValue?: any;
100
- onReset?: () => void;
101
104
  onMetaChange?: (meta: import("@rc-component/form/lib/Field").MetaEvent) => void;
102
105
  preserve?: boolean;
103
106
  isListField?: boolean;
104
107
  isList?: boolean;
105
- prefixCls?: string;
106
108
  noStyle?: boolean;
107
- style?: React.CSSProperties;
108
- className?: string;
109
- rootClassName?: string;
110
- id?: string;
111
109
  hasFeedback?: boolean | {
112
110
  icons: import("antd/es/form/FormItem").FeedbackIcons;
113
111
  };
114
- validateStatus?: "" | "success" | "warning" | "error" | "validating";
115
- hidden?: boolean;
112
+ validateStatus?: "" | "warning" | "error" | "success" | "validating";
116
113
  layout?: import("antd/es/form/Form").FormItemLayout;
117
114
  wrapperCol?: import("antd").ColProps;
118
- status?: "" | "success" | "warning" | "error" | "validating";
119
115
  help?: React.ReactNode;
120
116
  fieldId?: string;
121
117
  valueType?: import("../../../render/propsType").ProFormValueType;
122
- isView?: boolean;
118
+ toISOString?: boolean;
119
+ toCSTString?: boolean;
120
+ switchValue?: [any, any];
121
+ clearNotShow?: boolean;
122
+ trim?: boolean;
123
+ upperCase?: boolean;
123
124
  viewRender?: (value: any, record: any, { form, index, namePath, }: {
124
125
  [key: string]: any;
125
126
  form: FormInstance<any>;
126
127
  index?: number;
127
128
  }) => string | React.ReactElement<any, any>;
128
129
  viewType?: import("../../../render/propsType").ViewType;
129
- desensitization?: [number, number] | ReactiveFunction<any, [number, number]>;
130
130
  name: any;
131
131
  dependencies: any[];
132
132
  tooltip: string | {
@@ -141,7 +141,7 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
141
141
  * 创建组件属性
142
142
  */
143
143
  export declare const createComponentProps: (column: FlexibleGroupColumnType, formItemProps: any) => {
144
- componentProps: import("lodash").Omit<any, "format" | "toISOString" | "toCSTString" | "switchValue" | "precision" | "clearNotShow" | "dependNames" | "valueType">;
144
+ componentProps: import("lodash").Omit<any, "precision" | "valueType" | "toISOString" | "toCSTString" | "switchValue" | "format" | "clearNotShow" | "dependNames">;
145
145
  formItemTransform: {
146
146
  getValueProps: any;
147
147
  normalize: any;
@@ -10,7 +10,7 @@ import locale from "../../../locale";
10
10
  import { useProConfig } from "../../../ProConfigProvider";
11
11
  import Container from "../../../ProForm/components/Container";
12
12
  import AdaptiveTooltip from "../AdaptiveTooltip";
13
- import { getFlatTreeData } from "../../utils";
13
+ import { getFlatTreeData, restoreCodeNameLabel } from "../../utils";
14
14
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
15
15
  const {
16
16
  SHOW_PARENT
@@ -629,7 +629,8 @@ export const ProTreeSelect = (props, ref) => {
629
629
  if (props?.labelInValue) {
630
630
  result = getLabelByValue(_selectList, newVal);
631
631
  }
632
- const options = findTreeNode(_selectList, extra?.triggerValue);
632
+ // showCodeName 仅影响展示,回调返回的 option 需还原原始 label
633
+ const options = restoreCodeNameLabel(findTreeNode(_selectList, extra?.triggerValue), showCodeName);
633
634
  onChange && onChange(result, options, extra);
634
635
  // 重置搜索
635
636
  showSearch && searchTreeEvent('');
@@ -35,6 +35,15 @@ export declare function filterCheckedNodes(data: any, checkedKeys: any, searchSt
35
35
  * @returns
36
36
  */
37
37
  export declare function getChildrenKeys(node: ProTreeDataType, childrenKeys: string[], fieldNames: ProTreeFieldNamesType, type: 'treeClose' | 'treeCheck'): void;
38
+ /**
39
+ * 还原 showCodeName 合并到 label 上的 `${value}-` 前缀
40
+ * showCodeName 仅影响展示,回调返回的 option 应保持原始 label
41
+ * 注意:此处 option 已是标准格式(label, value)
42
+ * @param option 单个或数组形式的选项(标准格式)
43
+ * @param showCodeName 是否开启了 code-name 展示
44
+ * @returns 还原 label 后的新对象/数组(不可变)
45
+ */
46
+ export declare function restoreCodeNameLabel<T extends Record<string, any>>(option: T | T[], showCodeName?: boolean): T | T[];
38
47
  /**
39
48
  * 如果默认全开展那么返回所有key,否则返回空[]
40
49
  * @param isExpand 是否全展开
@@ -160,6 +160,37 @@ export function getChildrenKeys(node, childrenKeys, fieldNames, type) {
160
160
  }
161
161
  }
162
162
 
163
+ /**
164
+ * 还原 showCodeName 合并到 label 上的 `${value}-` 前缀
165
+ * showCodeName 仅影响展示,回调返回的 option 应保持原始 label
166
+ * 注意:此处 option 已是标准格式(label, value)
167
+ * @param option 单个或数组形式的选项(标准格式)
168
+ * @param showCodeName 是否开启了 code-name 展示
169
+ * @returns 还原 label 后的新对象/数组(不可变)
170
+ */
171
+ export function restoreCodeNameLabel(option, showCodeName) {
172
+ if (!showCodeName || !option) {
173
+ return option;
174
+ }
175
+ const restore = node => {
176
+ const {
177
+ label,
178
+ value
179
+ } = node;
180
+ if (typeof label === 'string') {
181
+ const prefix = `${value}-`;
182
+ if (label.startsWith(prefix)) {
183
+ return {
184
+ ...node,
185
+ label: label.slice(prefix.length)
186
+ };
187
+ }
188
+ }
189
+ return node;
190
+ };
191
+ return Array.isArray(option) ? option.map(restore) : restore(option);
192
+ }
193
+
163
194
  /**
164
195
  * 如果默认全开展那么返回所有key,否则返回空[]
165
196
  * @param isExpand 是否全展开
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zat-design/sisyphus-react",
3
- "version": "4.4.3-beta.2",
3
+ "version": "4.4.3",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "es",
@@ -163,7 +163,6 @@
163
163
  "husky": "^9.0.0",
164
164
  "jest-canvas-mock": "^2.5.2",
165
165
  "lint-staged": "^10.0.0",
166
- "mini-css-extract-plugin": "^2.9.4",
167
166
  "minimatch": "^9.0.5",
168
167
  "mockjs": "^1.0.0",
169
168
  "patch-package": "^8.0.1",