@zat-design/sisyphus-react 4.5.8-beta.3 → 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/dist/index.esm.css +1 -1
- package/dist/less.esm.css +1 -1
- 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/ProLayout/index.js +2 -7
- package/es/ProLayout/style/index.less +16 -22
- 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
|
@@ -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
|
};
|