@zat-design/sisyphus-react 4.5.8-beta.4 → 4.5.8-beta.5
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.
- package/es/ProEditTable/components/RcTable/BaseTable.js +7 -6
- package/es/ProEditTable/components/RcTable/DraggableTable.js +4 -4
- package/es/ProEditTable/components/RenderField/index.js +22 -21
- package/es/ProEditTable/components/RenderField/tools.d.ts +7 -0
- package/es/ProEditTable/components/RenderField/tools.js +29 -2
- package/es/ProEditTable/index.js +44 -38
- package/es/ProEditTable/propsType.d.ts +6 -0
- package/es/ProEditTable/utils/index.js +3 -2
- package/es/ProLayout/components/ProHeader/index.js +1 -0
- package/es/ProStep/components/Anchor/index.js +4 -3
- package/es/ProStep/components/Item/index.js +8 -5
- package/es/ProStep/components/Step/index.d.ts +5 -1
- package/es/ProStep/components/Step/index.js +5 -3
- package/es/ProStep/constants.d.ts +1 -0
- package/es/ProStep/constants.js +1 -0
- package/es/ProStep/index.js +102 -6
- package/es/ProStep/propsType.d.ts +12 -6
- package/es/ProStep/utils/index.d.ts +5 -5
- package/es/ProStep/utils/index.js +35 -11
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@ const BaseTable = ({
|
|
|
27
27
|
isHideCheckBox,
|
|
28
28
|
rowDraggable,
|
|
29
29
|
pagination,
|
|
30
|
+
paginationValidationEnabled,
|
|
30
31
|
scroll,
|
|
31
32
|
summary,
|
|
32
33
|
page,
|
|
@@ -37,7 +38,7 @@ const BaseTable = ({
|
|
|
37
38
|
const [errorLength] = useEditTableError({
|
|
38
39
|
containerNode: tableRef.current,
|
|
39
40
|
className: 'ant-form-item-explain-error',
|
|
40
|
-
isEnabled:
|
|
41
|
+
isEnabled: paginationValidationEnabled
|
|
41
42
|
});
|
|
42
43
|
const getScroll = useCallback(() => {
|
|
43
44
|
if (!scroll) return null;
|
|
@@ -87,17 +88,17 @@ const BaseTable = ({
|
|
|
87
88
|
});
|
|
88
89
|
},
|
|
89
90
|
itemRender: (index, type, originalElement) => {
|
|
90
|
-
return type === 'page' && page.pageNum === index && errorLength ? /*#__PURE__*/_jsxs("div", {
|
|
91
|
+
return paginationValidationEnabled && type === 'page' && page.pageNum === index && errorLength ? /*#__PURE__*/_jsxs("div", {
|
|
91
92
|
className: "pro-edit-table-pagination-item-badge",
|
|
92
93
|
children: [/*#__PURE__*/_jsx(Badge, {
|
|
93
94
|
count: errorLength
|
|
94
95
|
}), originalElement]
|
|
95
96
|
}) : originalElement;
|
|
96
97
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
...(typeof pagination === 'object' ? pagination : {}),
|
|
99
|
+
current: (typeof pagination === 'object' ? pagination.current : undefined) ?? page.pageNum,
|
|
100
|
+
pageSize: (typeof pagination === 'object' ? pagination.pageSize : undefined) ?? page.pageSize,
|
|
101
|
+
onChange: handlePageChange
|
|
101
102
|
} : false,
|
|
102
103
|
scroll: getScroll()
|
|
103
104
|
};
|
|
@@ -165,8 +165,6 @@ const DraggableTable = ({
|
|
|
165
165
|
...resetProps,
|
|
166
166
|
rowKey: tableRowKey,
|
|
167
167
|
pagination: pagination ? {
|
|
168
|
-
current: page.pageNum,
|
|
169
|
-
pageSize: page.pageSize,
|
|
170
168
|
showSizeChanger: false,
|
|
171
169
|
showQuickJumper: true,
|
|
172
170
|
total: value?.length,
|
|
@@ -176,8 +174,10 @@ const DraggableTable = ({
|
|
|
176
174
|
total
|
|
177
175
|
});
|
|
178
176
|
},
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
...(typeof pagination === 'object' ? pagination : {}),
|
|
178
|
+
current: (typeof pagination === 'object' ? pagination.current : undefined) ?? page.pageNum,
|
|
179
|
+
pageSize: (typeof pagination === 'object' ? pagination.pageSize : undefined) ?? page.pageSize,
|
|
180
|
+
onChange: handlePageChange
|
|
181
181
|
} : false,
|
|
182
182
|
scroll: getScroll(),
|
|
183
183
|
summary
|
|
@@ -25,7 +25,7 @@ import ConfirmWrapper from "../../../ProForm/components/render/ConfirmWrapper";
|
|
|
25
25
|
import { getDefaultProps } from "../../utils/getDefaultProps";
|
|
26
26
|
import ListChangedWrapper from "./ListChangedWrapper";
|
|
27
27
|
import useShouldUpdateForTable from "../../utils/useShouldUpdateForTable";
|
|
28
|
-
import { OMIT_FORM_ITEM_AND_DOM_KEYS, arePropsEqual } from "./tools";
|
|
28
|
+
import { OMIT_FORM_ITEM_AND_DOM_KEYS, arePropsEqual, hasRowFunctionDependency, mergeOnFieldChangeRow } from "./tools";
|
|
29
29
|
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
30
30
|
const RenderField = ({
|
|
31
31
|
text: value,
|
|
@@ -237,21 +237,7 @@ const RenderField = ({
|
|
|
237
237
|
// 因为这些函数依赖行数据,当行数据变化时需要重新计算
|
|
238
238
|
// 扩展到所有模式(single/multiple/cell),统一行为
|
|
239
239
|
// 注意:需要检查原始的 component/editRender,而不是处理后的 lastComponent
|
|
240
|
-
const hasFunctionDependency =
|
|
241
|
-
// disabled 是函数
|
|
242
|
-
_isFunction(fieldProps) ||
|
|
243
|
-
// fieldProps 是函数
|
|
244
|
-
_isFunction(required) ||
|
|
245
|
-
// required 是函数
|
|
246
|
-
_isFunction(rules) ||
|
|
247
|
-
// rules 是函数
|
|
248
|
-
_isFunction(column?.isEditable) ||
|
|
249
|
-
// isEditable 是函数
|
|
250
|
-
_isFunction(component) ||
|
|
251
|
-
// component 是函数
|
|
252
|
-
_isFunction(editRender) ||
|
|
253
|
-
// editRender 是函数
|
|
254
|
-
_isFunction(viewRender); // viewRender 是函数
|
|
240
|
+
const hasFunctionDependency = hasRowFunctionDependency(column);
|
|
255
241
|
|
|
256
242
|
// 移除 isSingleMode 限制,让所有模式都支持响应式更新
|
|
257
243
|
// 性能优化已通过 useShouldUpdateForTable hook 的缓存和防抖机制实现
|
|
@@ -349,8 +335,8 @@ const RenderField = ({
|
|
|
349
335
|
if (isView) {
|
|
350
336
|
// 存在viewRender覆盖默认值
|
|
351
337
|
if (typeof viewRender === 'function') {
|
|
352
|
-
|
|
353
|
-
const View = viewRender(
|
|
338
|
+
const latestCurrentValue = dataIndex ? rowData?.[dataIndex] : value;
|
|
339
|
+
const View = viewRender(latestCurrentValue, rowData || {}, options);
|
|
354
340
|
TargetComponent = /*#__PURE__*/_jsx(Container, {
|
|
355
341
|
viewEmpty: viewEmpty,
|
|
356
342
|
children: View
|
|
@@ -438,7 +424,20 @@ const RenderField = ({
|
|
|
438
424
|
TargetComponent?.props?.onFieldChange && (await TargetComponent.props.onFieldChange(...callArgs));
|
|
439
425
|
onFieldChange && (await onFieldChange(...callArgs));
|
|
440
426
|
|
|
441
|
-
//
|
|
427
|
+
// 原地修改 row 会改变 store 内的对象,但不会通知 Form 和只读单元格重新渲染。
|
|
428
|
+
// 只通知相对回调前真正变化的子字段,避免整行回写覆盖回调内显式 setFieldValue 的新值。
|
|
429
|
+
const latestStoreRow = form.getFieldValue(rowPath, true) || {};
|
|
430
|
+
const nextStoreRow = mergeOnFieldChangeRow(orgRow, row, latestStoreRow);
|
|
431
|
+
if (nextStoreRow !== latestStoreRow) {
|
|
432
|
+
// ProEditTable 注册在整个列表路径上,子行写入不会通知该 Form.Item。
|
|
433
|
+
// 以最新列表为底只替换当前行,确保其他行与显式 store 写入不被覆盖。
|
|
434
|
+
const latestList = form.getFieldValue(namePath, true) || [];
|
|
435
|
+
const nextList = [...latestList];
|
|
436
|
+
nextList[index] = nextStoreRow;
|
|
437
|
+
form.setFieldValue(namePath, nextList);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 延后读取通知后的最新 store,统一处理联动校验与行刷新。
|
|
442
441
|
setTimeout(() => {
|
|
443
442
|
const rowAfter = form.getFieldValue(rowPath, true) ?? row;
|
|
444
443
|
if (validateTrigger && validateTrigger.includes('onChange')) {
|
|
@@ -597,7 +596,9 @@ const RenderField = ({
|
|
|
597
596
|
source: 'ProEditTable'
|
|
598
597
|
}
|
|
599
598
|
}), [cellName, lastFieldProps, TargetComponent?.props, namePath, index, lastDisabled, handleChange, handleBlur, confirm, lastDesensitization, names, originalName, viewEmpty, lastValueType, isView, otherProps?.desensitizationKey]);
|
|
600
|
-
componentProps = _omit(componentProps, ['onFieldChange', 'namePath', 'index',
|
|
599
|
+
componentProps = _omit(componentProps, ['onFieldChange', 'namePath', 'index',
|
|
600
|
+
// precision 是 InputNumber 的有效 fieldProps,仅在真正渲染原生 DOM 时过滤
|
|
601
|
+
...OMIT_FORM_ITEM_AND_DOM_KEYS.filter(key => key !== 'precision')]);
|
|
601
602
|
if (['Switch', 'SwitchCheckbox'].includes(type)) {
|
|
602
603
|
lastFormItemProps.valuePropName = 'checked';
|
|
603
604
|
}
|
|
@@ -751,7 +752,7 @@ const RenderField = ({
|
|
|
751
752
|
// 查看模式
|
|
752
753
|
if (latestIsView) {
|
|
753
754
|
if (typeof viewRender === 'function') {
|
|
754
|
-
const latestCurrentValue = dataIndex ? latestRowData?.[dataIndex] :
|
|
755
|
+
const latestCurrentValue = dataIndex ? latestRowData?.[dataIndex] : value;
|
|
755
756
|
const View = viewRender(latestCurrentValue, latestRowData || {}, options);
|
|
756
757
|
latestTargetComponent = /*#__PURE__*/_jsx(Container, {
|
|
757
758
|
viewEmpty: viewEmpty,
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { InternalNamePath, NamePath } from 'antd/lib/form/interface';
|
|
2
2
|
import { GetOriginalValueParams, RenderFieldComparableProps } from './propsType';
|
|
3
|
+
/** 判断列是否包含可能依赖整行数据的函数型配置。 */
|
|
4
|
+
export declare const hasRowFunctionDependency: (column: Record<string, any> | null | undefined) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 将 onFieldChange 中原地修改的字段合并到最新 Form Store 行。
|
|
7
|
+
* Store 若已将同一字段显式写成其他值,则保留 Store 值。
|
|
8
|
+
*/
|
|
9
|
+
export declare const mergeOnFieldChangeRow: (beforeRow: Record<string, any> | null | undefined, mutatedRow: Record<string, any> | null | undefined, latestStoreRow: Record<string, any> | null | undefined) => Record<string, any>;
|
|
3
10
|
/** 列配置中不应透传到 Form.Item 或 DOM 的字段(与 ProForm Render 保持一致) */
|
|
4
11
|
export declare const OMIT_FORM_ITEM_AND_DOM_KEYS: string[];
|
|
5
12
|
/** 克隆子元素时需从 props 中剔除,避免透传到 div 等 DOM 导致 React 警告 */
|
|
@@ -4,6 +4,33 @@ import _isEqual from "lodash/isEqual";
|
|
|
4
4
|
import _get from "lodash/get";
|
|
5
5
|
import { customEqualForFunction } from "../../../utils";
|
|
6
6
|
import { getNamePath, isRecordShallowEqual } from "../../utils/tools";
|
|
7
|
+
const ROW_FUNCTION_DEPENDENCY_KEYS = ['component', 'editRender', 'fieldProps', 'rules', 'required', 'disabled', 'isEditable', 'valueType', 'viewRender'];
|
|
8
|
+
|
|
9
|
+
/** 判断列是否包含可能依赖整行数据的函数型配置。 */
|
|
10
|
+
export const hasRowFunctionDependency = column => ROW_FUNCTION_DEPENDENCY_KEYS.some(key => _isFunction(column?.[key]));
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 将 onFieldChange 中原地修改的字段合并到最新 Form Store 行。
|
|
14
|
+
* Store 若已将同一字段显式写成其他值,则保留 Store 值。
|
|
15
|
+
*/
|
|
16
|
+
export const mergeOnFieldChangeRow = (beforeRow, mutatedRow, latestStoreRow) => {
|
|
17
|
+
const before = beforeRow || {};
|
|
18
|
+
const mutated = mutatedRow || {};
|
|
19
|
+
const latest = latestStoreRow || {};
|
|
20
|
+
const changedKeys = Array.from(new Set([...Object.keys(before), ...Object.keys(mutated)])).filter(key => !_isEqual(before[key], mutated[key]));
|
|
21
|
+
let nextRow = latest;
|
|
22
|
+
changedKeys.forEach(key => {
|
|
23
|
+
const storeChangedExplicitly = !_isEqual(latest[key], before[key]) && !_isEqual(latest[key], mutated[key]);
|
|
24
|
+
if (!storeChangedExplicitly) {
|
|
25
|
+
nextRow = {
|
|
26
|
+
...nextRow,
|
|
27
|
+
[key]: mutated[key]
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return nextRow;
|
|
32
|
+
};
|
|
33
|
+
|
|
7
34
|
/** 列配置中不应透传到 Form.Item 或 DOM 的字段(与 ProForm Render 保持一致) */
|
|
8
35
|
export const OMIT_FORM_ITEM_AND_DOM_KEYS = ['format', 'toISOString', 'toCSTString', 'switchValue', 'precision', 'clearNotShow', 'dependNames', 'shouldCellUpdate' // 表格内部性能优化属性,不应传递给 Form.Item
|
|
9
36
|
];
|
|
@@ -91,9 +118,9 @@ export const arePropsEqual = (prevProps, nextProps) => {
|
|
|
91
118
|
config: nextConfig
|
|
92
119
|
} = nextProps;
|
|
93
120
|
|
|
94
|
-
// 函数型动态属性(component/editRender/fieldProps/rules/required/disabled/isEditable/valueType)
|
|
121
|
+
// 函数型动态属性(component/editRender/fieldProps/rules/required/disabled/isEditable/valueType/viewRender)
|
|
95
122
|
// 可能依赖行内兄弟字段;行对象为同引用(原地修改)时,浅比较无法区分,需强制重渲染
|
|
96
|
-
const hasFunctionDependency =
|
|
123
|
+
const hasFunctionDependency = hasRowFunctionDependency(prevColumn) || hasRowFunctionDependency(nextColumn);
|
|
97
124
|
if (hasFunctionDependency && prevRecord === nextRecord) {
|
|
98
125
|
return false;
|
|
99
126
|
}
|
package/es/ProEditTable/index.js
CHANGED
|
@@ -25,6 +25,7 @@ const ProEditTable = ({
|
|
|
25
25
|
className,
|
|
26
26
|
columns,
|
|
27
27
|
mode = 'multiple',
|
|
28
|
+
paginationMode = 'normal',
|
|
28
29
|
stripe = true,
|
|
29
30
|
draggable = false,
|
|
30
31
|
disabled = false,
|
|
@@ -118,6 +119,14 @@ const ProEditTable = ({
|
|
|
118
119
|
selectedRows,
|
|
119
120
|
page
|
|
120
121
|
} = state;
|
|
122
|
+
const paginationEnabled = Boolean(pagination);
|
|
123
|
+
const paginationValidationEnabled = paginationEnabled && paginationMode === 'validate';
|
|
124
|
+
const paginationConfig = typeof pagination === 'object' ? pagination : undefined;
|
|
125
|
+
const resolvedPage = useMemo(() => ({
|
|
126
|
+
pageNum: paginationConfig?.current ?? page.pageNum,
|
|
127
|
+
pageSize: paginationConfig?.pageSize ?? page.pageSize
|
|
128
|
+
}), [page.pageNum, page.pageSize, paginationConfig?.current, paginationConfig?.pageSize]);
|
|
129
|
+
const mergedSelectedRowKeys = rowSelection?.selectedRowKeys ?? selectedRowKeys;
|
|
121
130
|
const virtualRowName = getNamePath(_isArray(name) ? name : [name], virtualKey);
|
|
122
131
|
|
|
123
132
|
// 样式处理
|
|
@@ -166,31 +175,26 @@ const ProEditTable = ({
|
|
|
166
175
|
|
|
167
176
|
// 分页变更
|
|
168
177
|
const handlePageChange = useCallback(async (current, pageSize) => {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
page: {
|
|
174
|
-
pageNum: current,
|
|
175
|
-
pageSize
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
178
|
+
if (!paginationEnabled) return;
|
|
179
|
+
const isPageSizeChange = pageSize !== resolvedPage.pageSize;
|
|
180
|
+
if (paginationValidationEnabled && !isPageSizeChange) {
|
|
181
|
+
try {
|
|
180
182
|
await form.validateFields([name], {
|
|
181
183
|
recursive: true
|
|
182
184
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
pageSize: pageSize ?? page.pageSize
|
|
187
|
-
}
|
|
188
|
-
});
|
|
185
|
+
} catch (error) {
|
|
186
|
+
handleScrollToError();
|
|
187
|
+
return;
|
|
189
188
|
}
|
|
190
|
-
} catch (error) {
|
|
191
|
-
handleScrollToError();
|
|
192
189
|
}
|
|
193
|
-
|
|
190
|
+
setState({
|
|
191
|
+
page: {
|
|
192
|
+
pageNum: current,
|
|
193
|
+
pageSize: pageSize ?? resolvedPage.pageSize
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
paginationConfig?.onChange?.(current, pageSize);
|
|
197
|
+
}, [form, name, paginationConfig?.onChange, paginationEnabled, paginationValidationEnabled, resolvedPage.pageSize]);
|
|
194
198
|
const config = useMemo(() => ({
|
|
195
199
|
form,
|
|
196
200
|
mode,
|
|
@@ -205,7 +209,7 @@ const ProEditTable = ({
|
|
|
205
209
|
actionProps,
|
|
206
210
|
toolbarProps,
|
|
207
211
|
setState,
|
|
208
|
-
selectedRowKeys,
|
|
212
|
+
selectedRowKeys: mergedSelectedRowKeys,
|
|
209
213
|
selectedRows,
|
|
210
214
|
onlyOneLineMsg,
|
|
211
215
|
deletePoConfirmMsg,
|
|
@@ -220,7 +224,7 @@ const ProEditTable = ({
|
|
|
220
224
|
tableRef,
|
|
221
225
|
max,
|
|
222
226
|
tableLength: value?.length,
|
|
223
|
-
page,
|
|
227
|
+
page: resolvedPage,
|
|
224
228
|
originalValues,
|
|
225
229
|
errorStore: errorStoreRef.current,
|
|
226
230
|
prefixCls,
|
|
@@ -236,7 +240,7 @@ const ProEditTable = ({
|
|
|
236
240
|
...resetProps
|
|
237
241
|
}), [actionDirection, actionProps, actionWidth, columns, deletePoConfirmMsg, diffConfig, editingKeys, emptyBtnText, form,
|
|
238
242
|
// forceUpdate 不应该作为依赖项,因为它是触发刷新的信号,而非用于比较的数据
|
|
239
|
-
getIsNew, handlePageChange, insertType, isView, max, mode, mulDeletePoConfirmMsg, name, namePath, onlyOneLineMsg, originalValues, prefixCls, requiredAlign, resetProps, rowDisabled,
|
|
243
|
+
getIsNew, handlePageChange, insertType, isView, max, mode, mulDeletePoConfirmMsg, name, namePath, onlyOneLineMsg, originalValues, prefixCls, requiredAlign, resetProps, rowDisabled, mergedSelectedRowKeys, selectedRows, shouldUpdateDebounce, tableRef, toolbarProps, value?.length, viewEmpty, virtualKey, resolvedPage]);
|
|
240
244
|
|
|
241
245
|
// 编辑行设置下样式
|
|
242
246
|
const _rowClassName = record => {
|
|
@@ -267,19 +271,12 @@ const ProEditTable = ({
|
|
|
267
271
|
}, [toolbarProps]);
|
|
268
272
|
|
|
269
273
|
// 是否隐藏勾选框
|
|
270
|
-
const isHideCheckBox = isForbiddenBtn('mulDelete');
|
|
274
|
+
const isHideCheckBox = !rowSelection && isForbiddenBtn('mulDelete');
|
|
271
275
|
|
|
272
276
|
// 复选框
|
|
273
277
|
const _rowSelection = {
|
|
274
278
|
fixed: true,
|
|
275
|
-
selectedRowKeys,
|
|
276
279
|
columnWidth: 48,
|
|
277
|
-
onChange: (selectedRowKeys, selectedRows) => {
|
|
278
|
-
setState({
|
|
279
|
-
selectedRowKeys,
|
|
280
|
-
selectedRows
|
|
281
|
-
});
|
|
282
|
-
},
|
|
283
280
|
getCheckboxProps: record => {
|
|
284
281
|
if (rowDisabled) {
|
|
285
282
|
const _disabled = rowDisabled(record);
|
|
@@ -290,7 +287,15 @@ const ProEditTable = ({
|
|
|
290
287
|
return {};
|
|
291
288
|
},
|
|
292
289
|
hideSelectAll: isHideCheckBox,
|
|
293
|
-
...rowSelection
|
|
290
|
+
...rowSelection,
|
|
291
|
+
selectedRowKeys: mergedSelectedRowKeys,
|
|
292
|
+
onChange: (nextSelectedRowKeys, nextSelectedRows, info) => {
|
|
293
|
+
setState({
|
|
294
|
+
selectedRowKeys: nextSelectedRowKeys,
|
|
295
|
+
selectedRows: nextSelectedRows
|
|
296
|
+
});
|
|
297
|
+
rowSelection?.onChange?.(nextSelectedRowKeys, nextSelectedRows, info);
|
|
298
|
+
}
|
|
294
299
|
};
|
|
295
300
|
|
|
296
301
|
// 空列表状态
|
|
@@ -411,13 +416,14 @@ const ProEditTable = ({
|
|
|
411
416
|
isHideCheckBox,
|
|
412
417
|
rowDraggable,
|
|
413
418
|
pagination,
|
|
419
|
+
paginationValidationEnabled,
|
|
414
420
|
scroll,
|
|
415
421
|
summary: _summary,
|
|
416
|
-
page,
|
|
422
|
+
page: resolvedPage,
|
|
417
423
|
formatMessage,
|
|
418
424
|
locale,
|
|
419
425
|
handlePageChange
|
|
420
|
-
}), [_className, _columns, _rowClassName, disabled, editingKeys, formatMessage, handlePageChange, headerRender, isHideCheckBox, locale,
|
|
426
|
+
}), [_className, _columns, _rowClassName, disabled, editingKeys, formatMessage, handlePageChange, headerRender, isHideCheckBox, locale, pagination, paginationValidationEnabled, renderRowSelection, rowDraggable, rowKey, tableRowKey, scroll, _summary, tableRef, enrichedValue, resolvedPage, virtualKey]);
|
|
421
427
|
|
|
422
428
|
// 拖拽排序后,enrichedValue 中含 _dragIndex/_rowIndex(内部字段),需清除后再传给外部 onChange
|
|
423
429
|
const handleDragChange = useCallback(newValue => {
|
|
@@ -446,20 +452,20 @@ const ProEditTable = ({
|
|
|
446
452
|
ref: affixRef,
|
|
447
453
|
..._toolbarSticky,
|
|
448
454
|
children: /*#__PURE__*/_jsx("div", {
|
|
449
|
-
className: `pro-edit-table-toolbar${
|
|
455
|
+
className: `pro-edit-table-toolbar${paginationEnabled ? ' pro-edit-table-toolbar-fixed' : ''}`,
|
|
450
456
|
children: /*#__PURE__*/_jsx(RenderToolbar, {
|
|
451
457
|
...config
|
|
452
458
|
})
|
|
453
459
|
})
|
|
454
460
|
}) : /*#__PURE__*/_jsx("div", {
|
|
455
|
-
className: `pro-edit-table-toolbar${
|
|
461
|
+
className: `pro-edit-table-toolbar${paginationEnabled ? ' pro-edit-table-toolbar-fixed' : ''}`,
|
|
456
462
|
children: /*#__PURE__*/_jsx(RenderToolbar, {
|
|
457
463
|
...config
|
|
458
464
|
})
|
|
459
465
|
}) : null, footerRender ? /*#__PURE__*/_jsx("div", {
|
|
460
466
|
className: "pro-edit-table-footer",
|
|
461
467
|
children: footerRender
|
|
462
|
-
}) : null,
|
|
468
|
+
}) : null, paginationValidationEnabled ? /*#__PURE__*/_jsx("div", {
|
|
463
469
|
id: `pro-edit-table-pagination-${Array.isArray(config.name) ? config.name.filter(Boolean).join('-') : config.name || 'default'}`,
|
|
464
470
|
onClick: () => {
|
|
465
471
|
onPageCheck({
|
|
@@ -467,7 +473,7 @@ const ProEditTable = ({
|
|
|
467
473
|
name,
|
|
468
474
|
value,
|
|
469
475
|
columns,
|
|
470
|
-
page,
|
|
476
|
+
page: resolvedPage,
|
|
471
477
|
pagination,
|
|
472
478
|
isView,
|
|
473
479
|
disabled,
|
|
@@ -232,6 +232,7 @@ export type ProEditTableRefType = ProEditTableRefProps;
|
|
|
232
232
|
*/
|
|
233
233
|
export type ProEditTableMode = 'single' | 'multiple';
|
|
234
234
|
export type ProEditTableModeType = ProEditTableMode;
|
|
235
|
+
export type ProEditTablePaginationMode = 'normal' | 'validate';
|
|
235
236
|
/**
|
|
236
237
|
* 表格插入类型
|
|
237
238
|
*/
|
|
@@ -268,6 +269,11 @@ export interface ProEditTableProps<T = any> extends Omit<TableProps<T>, 'onChang
|
|
|
268
269
|
* @default multiple
|
|
269
270
|
*/
|
|
270
271
|
mode?: ProEditTableMode;
|
|
272
|
+
/**
|
|
273
|
+
* 分页行为模式。normal 仅使用 antd 分页,validate 会在切页前校验当前表格
|
|
274
|
+
* @default normal
|
|
275
|
+
*/
|
|
276
|
+
paginationMode?: ProEditTablePaginationMode;
|
|
271
277
|
/**
|
|
272
278
|
* 必填对齐方式, 默认右对齐
|
|
273
279
|
* @default right
|
|
@@ -12,6 +12,7 @@ import { customValidate, getNamePath, splitNames, handleScrollToError, cloneDeep
|
|
|
12
12
|
import { filterInternalFields } from "../../ProForm/utils";
|
|
13
13
|
import ProTooltip from "../../ProTooltip";
|
|
14
14
|
import { RenderField, ActionButton } from "../components";
|
|
15
|
+
import { hasRowFunctionDependency } from "../components/RenderField/tools";
|
|
15
16
|
import locale from "../../locale";
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -345,7 +346,7 @@ export const transformColumns = (columns = [], config, caches) => {
|
|
|
345
346
|
const hasComponent = _isFunction(item.component);
|
|
346
347
|
// 函数型动态属性会依赖整行数据(可能是当前列之外的兄弟字段),
|
|
347
348
|
// 这类列在行内任意字段变化时都需重渲染,不能只比对本列 dataIndex
|
|
348
|
-
const hasFunctionDependency =
|
|
349
|
+
const hasFunctionDependency = hasRowFunctionDependency(item);
|
|
349
350
|
const columnCacheKey = `${Array.isArray(name) ? name.join('.') : String(name)}::${String(columnName)}`;
|
|
350
351
|
|
|
351
352
|
// Fix 问题1:用原始列引用(克隆前)比对 dataSource
|
|
@@ -399,7 +400,7 @@ export const transformColumns = (columns = [], config, caches) => {
|
|
|
399
400
|
return true;
|
|
400
401
|
}
|
|
401
402
|
}
|
|
402
|
-
// 函数型动态属性(component/fieldProps/rules/required/disabled/isEditable/valueType)
|
|
403
|
+
// 函数型动态属性(component/fieldProps/rules/required/disabled/isEditable/valueType/viewRender)
|
|
403
404
|
// 可能依赖行内其他字段(兄弟字段),需比较整行;
|
|
404
405
|
// 同引用原地修改时 isEqual 恒为 true,无法感知,必须强制重渲染
|
|
405
406
|
if (hasFunctionDependency) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import cn from 'classnames';
|
|
2
2
|
import { Badge } from 'antd';
|
|
3
|
-
import { handleScroll } from "../../utils";
|
|
3
|
+
import { handleScroll as defaultHandleScroll } from "../../utils";
|
|
4
4
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
5
|
const AnchorSvg = ({
|
|
6
6
|
color
|
|
@@ -42,7 +42,8 @@ export const MenuItem = props => {
|
|
|
42
42
|
errorNum,
|
|
43
43
|
currentNum,
|
|
44
44
|
targetOffset,
|
|
45
|
-
scrollToError = true
|
|
45
|
+
scrollToError = true,
|
|
46
|
+
onAnchorClick = defaultHandleScroll
|
|
46
47
|
} = props;
|
|
47
48
|
const renderMenuIcon = () => {
|
|
48
49
|
if (isCurrentStep) {
|
|
@@ -81,7 +82,7 @@ export const MenuItem = props => {
|
|
|
81
82
|
current: isCurrentStep && onOff
|
|
82
83
|
}),
|
|
83
84
|
onClick: () => {
|
|
84
|
-
|
|
85
|
+
onAnchorClick(code, {
|
|
85
86
|
targetOffset,
|
|
86
87
|
scrollToError
|
|
87
88
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _isBoolean from "lodash/isBoolean";
|
|
2
2
|
// @ts-nocheck
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
4
|
import LazyLoad, { forceCheck } from "../LazyLoad";
|
|
5
5
|
import { useStep } from "../../index";
|
|
6
6
|
import ProCollapse from "../../../ProLayout/components/ProCollapse";
|
|
@@ -25,9 +25,9 @@ const ProStepItem = ({
|
|
|
25
25
|
const {
|
|
26
26
|
register,
|
|
27
27
|
collapse,
|
|
28
|
-
lazyLoad: globalLazyLoad
|
|
29
|
-
targetOffset
|
|
28
|
+
lazyLoad: globalLazyLoad
|
|
30
29
|
} = useStep();
|
|
30
|
+
const itemRef = useRef(null);
|
|
31
31
|
const lazyLoad = stepLazyLoad ?? globalLazyLoad;
|
|
32
32
|
useEffect(() => {
|
|
33
33
|
// Schedule registration to avoid re-render issues
|
|
@@ -37,6 +37,7 @@ const ProStepItem = ({
|
|
|
37
37
|
title,
|
|
38
38
|
order,
|
|
39
39
|
lazyLoad,
|
|
40
|
+
element: itemRef.current,
|
|
40
41
|
...restProps
|
|
41
42
|
});
|
|
42
43
|
}, 0);
|
|
@@ -59,10 +60,11 @@ const ProStepItem = ({
|
|
|
59
60
|
// If there's no `register` function or if collapsing is enabled, wrap in ProCollapse
|
|
60
61
|
if (!register || collapse && collapseItem && title) {
|
|
61
62
|
return /*#__PURE__*/_jsx("div", {
|
|
63
|
+
ref: itemRef,
|
|
62
64
|
className: "pro-step-item",
|
|
63
65
|
id: id,
|
|
64
66
|
style: {
|
|
65
|
-
scrollMarginTop:
|
|
67
|
+
scrollMarginTop: 'var(--pro-step-anchor-offset)'
|
|
66
68
|
},
|
|
67
69
|
children: /*#__PURE__*/_jsx(ProCollapse, {
|
|
68
70
|
title: title,
|
|
@@ -85,10 +87,11 @@ const ProStepItem = ({
|
|
|
85
87
|
|
|
86
88
|
// Otherwise, just render children
|
|
87
89
|
return /*#__PURE__*/_jsx("div", {
|
|
90
|
+
ref: itemRef,
|
|
88
91
|
className: "pro-step-item",
|
|
89
92
|
id: id,
|
|
90
93
|
style: {
|
|
91
|
-
scrollMarginTop:
|
|
94
|
+
scrollMarginTop: 'var(--pro-step-anchor-offset)'
|
|
92
95
|
},
|
|
93
96
|
children: renderChildren()
|
|
94
97
|
});
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ProStepType } from '../../propsType';
|
|
3
|
-
export declare const Step: ({ fixedTop, dataSource, activeKey, errorCollection, style, targetOffset, scrollToError, }: import("../../propsType").ProStepPropsType & {
|
|
3
|
+
export declare const Step: ({ fixedTop, dataSource, activeKey, errorCollection, style, targetOffset, scrollToError, onAnchorClick, }: import("../../propsType").ProStepPropsType & {
|
|
4
4
|
errorCollection: object;
|
|
5
|
+
onAnchorClick?: (id: string, options?: {
|
|
6
|
+
targetOffset?: string | number;
|
|
7
|
+
scrollToError?: boolean;
|
|
8
|
+
}) => void;
|
|
5
9
|
}) => React.JSX.Element;
|
|
6
10
|
export default Step;
|
|
@@ -4,8 +4,8 @@ import ProIcon from "../../../ProIcon/index";
|
|
|
4
4
|
import catalogSvg from "../../../assets/catalog.svg";
|
|
5
5
|
import Anchor from "../Anchor";
|
|
6
6
|
import locale from "../../../locale";
|
|
7
|
+
import { DEFAULT_FIXED_TOP } from "../../constants";
|
|
7
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
-
const DEFAULT_FIXED_TOP = 'var(--pro-layout-content-sticky-top, 64px)';
|
|
9
9
|
const toCssLength = value => typeof value === 'number' ? `${value}px` : value;
|
|
10
10
|
export const Step = ({
|
|
11
11
|
fixedTop = DEFAULT_FIXED_TOP,
|
|
@@ -14,7 +14,8 @@ export const Step = ({
|
|
|
14
14
|
errorCollection,
|
|
15
15
|
style,
|
|
16
16
|
targetOffset,
|
|
17
|
-
scrollToError
|
|
17
|
+
scrollToError,
|
|
18
|
+
onAnchorClick
|
|
18
19
|
}) => {
|
|
19
20
|
const [onOff, setOnOff] = useState(false);
|
|
20
21
|
const fixedTopCss = toCssLength(fixedTop);
|
|
@@ -36,9 +37,10 @@ export const Step = ({
|
|
|
36
37
|
item.currentNum = index + 1;
|
|
37
38
|
item.errorNum = errorNum;
|
|
38
39
|
item.targetOffset = targetOffset;
|
|
40
|
+
item.onAnchorClick = onAnchorClick;
|
|
39
41
|
});
|
|
40
42
|
return nextDataSource;
|
|
41
|
-
}, [dataSource, activeKey, errorCollection]);
|
|
43
|
+
}, [dataSource, activeKey, errorCollection, onAnchorClick, targetOffset]);
|
|
42
44
|
const handleMouseEnter = () => {
|
|
43
45
|
setOnOff(true);
|
|
44
46
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DEFAULT_FIXED_TOP = "var(--pro-layout-content-sticky-top, 64px)";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DEFAULT_FIXED_TOP = 'var(--pro-layout-content-sticky-top, 64px)';
|
package/es/ProStep/index.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import _debounce from "lodash/debounce";
|
|
2
|
-
import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { useSetState, useLocalStorageState } from 'ahooks';
|
|
4
4
|
import { handleScroll, handleScrollError } from "./utils";
|
|
5
5
|
import Step from "./components/Step";
|
|
6
6
|
import Item from "./components/Item";
|
|
7
7
|
import Listener from "./components/Listener";
|
|
8
|
+
import { DEFAULT_FIXED_TOP } from "./constants";
|
|
8
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
const DEFAULT_ANCHOR_GAP = '16px';
|
|
11
|
+
const ANCHOR_SCROLL_DELAY = 50;
|
|
12
|
+
const STICKY_HEADER_SELECTOR = '[data-pro-step-sticky-header="true"]';
|
|
13
|
+
const toCssLength = value => typeof value === 'number' ? `${value}px` : value;
|
|
14
|
+
|
|
9
15
|
// 创建上下文并提供类型
|
|
10
16
|
export const ProStepContext = /*#__PURE__*/createContext(null);
|
|
11
17
|
export const useStep = () => {
|
|
@@ -23,13 +29,24 @@ const ProStep = ({
|
|
|
23
29
|
});
|
|
24
30
|
// 注册子节点id与title映射的集合
|
|
25
31
|
const registerMap = useRef({});
|
|
32
|
+
const wrapperRef = useRef(null);
|
|
33
|
+
const stickyHeaderRef = useRef(null);
|
|
34
|
+
const autoAnchorEnabledRef = useRef(false);
|
|
35
|
+
const scrollTaskRef = useRef(null);
|
|
26
36
|
const [, setLocalData] = useLocalStorageState('cache-pro-step');
|
|
27
37
|
const ids = Object.keys(registerMap.current);
|
|
28
38
|
const {
|
|
29
39
|
collapse = false,
|
|
30
40
|
lazyLoad = false,
|
|
31
|
-
targetOffset
|
|
41
|
+
targetOffset,
|
|
42
|
+
fixedTop
|
|
32
43
|
} = resetProps;
|
|
44
|
+
const hasExplicitTargetOffset = targetOffset !== undefined && targetOffset !== null;
|
|
45
|
+
const anchorBase = fixedTop === undefined || fixedTop === null ? DEFAULT_FIXED_TOP : toCssLength(fixedTop);
|
|
46
|
+
const autoAnchorOffset = `calc(${anchorBase} + var(--pro-step-sticky-header-height, 0px) + ${DEFAULT_ANCHOR_GAP})`;
|
|
47
|
+
const wrapperStyle = hasExplicitTargetOffset ? {
|
|
48
|
+
'--pro-step-anchor-offset': toCssLength(targetOffset)
|
|
49
|
+
} : undefined;
|
|
33
50
|
const dataSource = useMemo(() => {
|
|
34
51
|
if (resetProps?.dataSource) {
|
|
35
52
|
return resetProps?.dataSource;
|
|
@@ -56,12 +73,14 @@ const ProStep = ({
|
|
|
56
73
|
order,
|
|
57
74
|
disabled,
|
|
58
75
|
lazyLoad,
|
|
76
|
+
element,
|
|
59
77
|
...rest
|
|
60
78
|
}) => {
|
|
61
79
|
const record = {};
|
|
62
80
|
record.id = id;
|
|
63
81
|
record.title = title;
|
|
64
82
|
record.order = order;
|
|
83
|
+
record.element = element;
|
|
65
84
|
if (!registerMap.current[id]) {
|
|
66
85
|
debounceReRender();
|
|
67
86
|
}
|
|
@@ -100,6 +119,80 @@ const ProStep = ({
|
|
|
100
119
|
});
|
|
101
120
|
}
|
|
102
121
|
};
|
|
122
|
+
const measureStickyHeader = useCallback((detect = false) => {
|
|
123
|
+
if (hasExplicitTargetOffset) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (!detect && !autoAnchorEnabledRef.current) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
const wrapper = wrapperRef.current;
|
|
130
|
+
if (!wrapper) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
const currentHeader = stickyHeaderRef.current;
|
|
134
|
+
const header = currentHeader && currentHeader.parentElement === wrapper ? currentHeader : Array.from(wrapper.children).find(element => element.matches(STICKY_HEADER_SELECTOR));
|
|
135
|
+
if (!header) {
|
|
136
|
+
autoAnchorEnabledRef.current = false;
|
|
137
|
+
stickyHeaderRef.current = null;
|
|
138
|
+
wrapper.style.removeProperty('--pro-step-sticky-header-height');
|
|
139
|
+
wrapper.style.removeProperty('--pro-step-anchor-offset');
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
autoAnchorEnabledRef.current = true;
|
|
143
|
+
stickyHeaderRef.current = header;
|
|
144
|
+
wrapper.style.setProperty('--pro-step-sticky-header-height', `${header.getBoundingClientRect().height}px`);
|
|
145
|
+
wrapper.style.setProperty('--pro-step-anchor-offset', autoAnchorOffset);
|
|
146
|
+
return true;
|
|
147
|
+
}, [autoAnchorOffset, hasExplicitTargetOffset]);
|
|
148
|
+
useLayoutEffect(() => {
|
|
149
|
+
autoAnchorEnabledRef.current = false;
|
|
150
|
+
if (hasExplicitTargetOffset || !measureStickyHeader(true)) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const header = stickyHeaderRef.current;
|
|
154
|
+
if (!header || typeof ResizeObserver === 'undefined') {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
const observer = new ResizeObserver(() => {
|
|
158
|
+
measureStickyHeader();
|
|
159
|
+
});
|
|
160
|
+
observer.observe(header);
|
|
161
|
+
return () => {
|
|
162
|
+
observer.disconnect();
|
|
163
|
+
autoAnchorEnabledRef.current = false;
|
|
164
|
+
stickyHeaderRef.current = null;
|
|
165
|
+
};
|
|
166
|
+
}, [hasExplicitTargetOffset, measureStickyHeader]);
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
return () => {
|
|
169
|
+
if (scrollTaskRef.current !== null) {
|
|
170
|
+
window.clearTimeout(scrollTaskRef.current);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}, []);
|
|
174
|
+
const scrollToStep = useCallback((id, options) => {
|
|
175
|
+
if (autoAnchorEnabledRef.current) {
|
|
176
|
+
measureStickyHeader();
|
|
177
|
+
}
|
|
178
|
+
const root = wrapperRef.current;
|
|
179
|
+
if (!root) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const registeredElement = registerMap.current[id]?.element;
|
|
183
|
+
const target = registeredElement && root.contains(registeredElement) ? registeredElement : Array.from(root.querySelectorAll('.pro-step-item')).find(item => item.id === id);
|
|
184
|
+
if (scrollTaskRef.current !== null) {
|
|
185
|
+
window.clearTimeout(scrollTaskRef.current);
|
|
186
|
+
}
|
|
187
|
+
scrollTaskRef.current = window.setTimeout(() => {
|
|
188
|
+
scrollTaskRef.current = null;
|
|
189
|
+
handleScroll(id, {
|
|
190
|
+
...options,
|
|
191
|
+
root,
|
|
192
|
+
target
|
|
193
|
+
});
|
|
194
|
+
}, ANCHOR_SCROLL_DELAY);
|
|
195
|
+
}, [measureStickyHeader]);
|
|
103
196
|
const notify = async params => {
|
|
104
197
|
const {
|
|
105
198
|
excludes
|
|
@@ -121,7 +214,7 @@ const ProStep = ({
|
|
|
121
214
|
setState({
|
|
122
215
|
errorCollection: nextErrorCollection
|
|
123
216
|
});
|
|
124
|
-
handleScrollError();
|
|
217
|
+
handleScrollError(undefined, wrapperRef.current || document);
|
|
125
218
|
return res;
|
|
126
219
|
};
|
|
127
220
|
const triggerTo = async keys => {
|
|
@@ -139,7 +232,7 @@ const ProStep = ({
|
|
|
139
232
|
setState({
|
|
140
233
|
errorCollection: nextErrorCollection
|
|
141
234
|
});
|
|
142
|
-
handleScrollError();
|
|
235
|
+
handleScrollError(undefined, wrapperRef.current || document);
|
|
143
236
|
return result;
|
|
144
237
|
};
|
|
145
238
|
return /*#__PURE__*/_jsx(ProStepContext.Provider, {
|
|
@@ -149,19 +242,22 @@ const ProStep = ({
|
|
|
149
242
|
register,
|
|
150
243
|
notify,
|
|
151
244
|
triggerTo,
|
|
152
|
-
handleScroll,
|
|
245
|
+
handleScroll: scrollToStep,
|
|
153
246
|
lazyLoad,
|
|
154
247
|
targetOffset,
|
|
155
248
|
unNotify,
|
|
156
249
|
source: 'ProStep'
|
|
157
250
|
},
|
|
158
251
|
children: /*#__PURE__*/_jsxs("div", {
|
|
252
|
+
ref: wrapperRef,
|
|
159
253
|
className: "pro-step-wrapper",
|
|
160
254
|
id: "pro-step",
|
|
255
|
+
style: wrapperStyle,
|
|
161
256
|
children: [children, /*#__PURE__*/_jsx(Step, {
|
|
162
257
|
...resetProps,
|
|
163
258
|
dataSource: dataSource,
|
|
164
|
-
errorCollection: errorCollection
|
|
259
|
+
errorCollection: errorCollection,
|
|
260
|
+
onAnchorClick: scrollToStep
|
|
165
261
|
})]
|
|
166
262
|
})
|
|
167
263
|
});
|
|
@@ -45,8 +45,8 @@ export interface ProStepPropsType {
|
|
|
45
45
|
children?: ReactNode;
|
|
46
46
|
/** 组件自定义样式 */
|
|
47
47
|
style?: CSSProperties;
|
|
48
|
-
/**
|
|
49
|
-
targetOffset?: number;
|
|
48
|
+
/** 完整滚动偏移量,显式设置时覆盖 ProHeader 自动偏移 */
|
|
49
|
+
targetOffset?: string | number;
|
|
50
50
|
/** 是否使用折叠标题 */
|
|
51
51
|
collapse?: boolean;
|
|
52
52
|
/** 是否自动滚动到第一个报错的步骤 */
|
|
@@ -102,8 +102,8 @@ export interface ProStepContextType {
|
|
|
102
102
|
handleScroll: (id: string, options?: ScrollOptions) => void;
|
|
103
103
|
/** 懒加载配置 */
|
|
104
104
|
lazyLoad?: boolean | any;
|
|
105
|
-
/**
|
|
106
|
-
targetOffset?: number;
|
|
105
|
+
/** 完整滚动偏移量 */
|
|
106
|
+
targetOffset?: string | number;
|
|
107
107
|
/** 取消注册函数 */
|
|
108
108
|
unNotify: (keys: string | string[]) => void;
|
|
109
109
|
/** 来源 */
|
|
@@ -126,6 +126,8 @@ export interface RegisterParams {
|
|
|
126
126
|
order: number;
|
|
127
127
|
/** 是否禁用 */
|
|
128
128
|
disabled?: boolean;
|
|
129
|
+
/** 当前步骤项 DOM,仅供 ProStep 实例内定位使用 */
|
|
130
|
+
element?: HTMLElement | null;
|
|
129
131
|
/** 懒加载配置 */
|
|
130
132
|
lazyLoad?: boolean | any;
|
|
131
133
|
/** 允许其他任意属性 */
|
|
@@ -144,6 +146,8 @@ export interface RegisterMapItem {
|
|
|
144
146
|
order: number;
|
|
145
147
|
/** 提交事件 */
|
|
146
148
|
subEvent?: () => Promise<any>;
|
|
149
|
+
/** 当前步骤项 DOM,仅供 ProStep 实例内定位使用 */
|
|
150
|
+
element?: HTMLElement | null;
|
|
147
151
|
/** 允许其他任意属性 */
|
|
148
152
|
[key: string]: any;
|
|
149
153
|
}
|
|
@@ -161,7 +165,7 @@ export interface NotifyParams {
|
|
|
161
165
|
*/
|
|
162
166
|
export interface ScrollOptions {
|
|
163
167
|
/** 目标偏移量 */
|
|
164
|
-
targetOffset?: number;
|
|
168
|
+
targetOffset?: string | number;
|
|
165
169
|
/** 是否滚动到错误位置 */
|
|
166
170
|
scrollToError?: boolean;
|
|
167
171
|
}
|
|
@@ -213,9 +217,11 @@ export interface MenuItemProps {
|
|
|
213
217
|
/** 当前数量 */
|
|
214
218
|
currentNum?: number;
|
|
215
219
|
/** 目标偏移量 */
|
|
216
|
-
targetOffset?: number;
|
|
220
|
+
targetOffset?: string | number;
|
|
217
221
|
/** 是否滚动到错误位置 */
|
|
218
222
|
scrollToError?: boolean;
|
|
223
|
+
/** 当前 ProStep 实例的锚点处理器 */
|
|
224
|
+
onAnchorClick?: (id: string, options?: ScrollOptions) => void;
|
|
219
225
|
}
|
|
220
226
|
/**
|
|
221
227
|
* ProStep 组件基础类型
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { LoadedMapType } from '../propsType';
|
|
2
|
+
import type { LoadedMapType, ScrollOptions } from '../propsType';
|
|
3
3
|
/**
|
|
4
4
|
* 滚动到错误位置, 延迟200ms解决ProForm错误还未生成
|
|
5
5
|
*/
|
|
6
|
-
export declare const handleScrollError: (dom?: HTMLElement) => void;
|
|
6
|
+
export declare const handleScrollError: (dom?: HTMLElement, root?: ParentNode) => void;
|
|
7
7
|
/**
|
|
8
8
|
* 处理滚动到指定元素位置, 如发现有错误, 则优先滚动到错误位置
|
|
9
9
|
* @param id 目标元素的ID
|
|
10
10
|
* @param options 滚动选项
|
|
11
11
|
*/
|
|
12
|
-
export declare const handleScroll: (id: string, options?: {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export declare const handleScroll: (id: string, options?: ScrollOptions & {
|
|
13
|
+
root?: ParentNode;
|
|
14
|
+
target?: HTMLElement | null;
|
|
15
15
|
}) => void;
|
|
16
16
|
/**
|
|
17
17
|
* 获取加载模块数据信息
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import _pick from "lodash/pick";
|
|
2
|
-
import _debounce from "lodash/debounce";
|
|
3
2
|
import scrollIntoView from 'scroll-into-view-if-needed';
|
|
3
|
+
const toCssLength = value => typeof value === 'number' ? `${value}px` : value;
|
|
4
|
+
|
|
4
5
|
/**
|
|
5
6
|
* 滚动到错误位置, 延迟200ms解决ProForm错误还未生成
|
|
6
7
|
*/
|
|
7
|
-
export const handleScrollError = dom => {
|
|
8
|
+
export const handleScrollError = (dom, root = document) => {
|
|
8
9
|
setTimeout(() => {
|
|
9
|
-
const errorDom = dom ||
|
|
10
|
+
const errorDom = dom || root.querySelector('[class*="form-item-has-error"]');
|
|
10
11
|
if (errorDom) {
|
|
11
12
|
scrollIntoView(errorDom, {
|
|
12
13
|
behavior: 'smooth',
|
|
@@ -24,10 +25,12 @@ export const handleScrollError = dom => {
|
|
|
24
25
|
*/
|
|
25
26
|
export const handleScroll = (id, options) => {
|
|
26
27
|
const {
|
|
27
|
-
targetOffset
|
|
28
|
-
scrollToError
|
|
28
|
+
targetOffset,
|
|
29
|
+
scrollToError,
|
|
30
|
+
root = document,
|
|
31
|
+
target
|
|
29
32
|
} = options || {};
|
|
30
|
-
const dom =
|
|
33
|
+
const dom = target || Array.from(root.querySelectorAll('.pro-step-item')).find(item => item.id === id);
|
|
31
34
|
if (dom) {
|
|
32
35
|
// 查找指定id下的错误表单项
|
|
33
36
|
const errorDom = dom.querySelector('[class*="form-item-has-error"]');
|
|
@@ -35,14 +38,35 @@ export const handleScroll = (id, options) => {
|
|
|
35
38
|
// 如果发现错误表单项,执行handleScrollError函数
|
|
36
39
|
handleScrollError(errorDom);
|
|
37
40
|
} else {
|
|
38
|
-
//
|
|
39
|
-
|
|
41
|
+
// 目录点击必须重新对齐到 sticky 区域下方,不能因“当前可见”而跳过。
|
|
42
|
+
const previousScrollMarginTop = dom.style.scrollMarginTop;
|
|
43
|
+
if (targetOffset !== undefined && targetOffset !== null) {
|
|
44
|
+
dom.style.scrollMarginTop = toCssLength(targetOffset);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
40
47
|
scrollIntoView(dom, {
|
|
41
|
-
behavior
|
|
48
|
+
// compute-scroll-into-view 已计算 scroll-margin;custom behavior 避免外层库再次扣减。
|
|
49
|
+
behavior: actions => {
|
|
50
|
+
actions.forEach(({
|
|
51
|
+
el,
|
|
52
|
+
top,
|
|
53
|
+
left
|
|
54
|
+
}) => {
|
|
55
|
+
el.scroll({
|
|
56
|
+
top,
|
|
57
|
+
left,
|
|
58
|
+
behavior: 'smooth'
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
},
|
|
42
62
|
block: 'start',
|
|
43
|
-
scrollMode: '
|
|
63
|
+
scrollMode: 'always'
|
|
44
64
|
});
|
|
45
|
-
}
|
|
65
|
+
} finally {
|
|
66
|
+
if (targetOffset !== undefined && targetOffset !== null) {
|
|
67
|
+
dom.style.scrollMarginTop = previousScrollMarginTop;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
46
70
|
}
|
|
47
71
|
}
|
|
48
72
|
};
|