@zat-design/sisyphus-react 4.6.4 → 4.6.5-beta.1

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.
@@ -1,50 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import {
3
- createContext,
4
- forwardRef,
5
- useContext,
6
- useEffect,
7
- useImperativeHandle,
8
- useMemo
9
- } from "react";
2
+ import { createContext, forwardRef, useContext, useImperativeHandle, useMemo } from "react";
10
3
  import { ProDrawer, ProModal } from "./components";
11
4
  import ProForm from "../ProForm";
12
5
  import { resolveDrawerSize } from "./utils";
13
6
  import locale from "../locale";
14
7
  const ProDrawerFormContext = createContext(null);
15
- const scrollLockClassName = "pro-drawer-form-scroll-lock";
16
- let openDrawerCount = 0;
17
- let lockedScrollLeft = 0;
18
- let lockedScrollTop = 0;
19
- const lockRootScroll = () => {
20
- if (typeof document === "undefined") {
21
- return void 0;
22
- }
23
- if (openDrawerCount === 0) {
24
- const scrollingElement = document.scrollingElement ?? document.documentElement;
25
- lockedScrollLeft = scrollingElement.scrollLeft;
26
- lockedScrollTop = scrollingElement.scrollTop;
27
- document.body.style.setProperty("--pro-drawer-form-scroll-top", `-${lockedScrollTop}px`);
28
- document.body.style.setProperty("--pro-drawer-form-scroll-left", `-${lockedScrollLeft}px`);
29
- document.documentElement.classList.add(scrollLockClassName);
30
- document.body.classList.add(scrollLockClassName);
31
- }
32
- openDrawerCount += 1;
33
- return () => {
34
- openDrawerCount = Math.max(0, openDrawerCount - 1);
35
- if (openDrawerCount === 0) {
36
- document.documentElement.classList.remove(scrollLockClassName);
37
- document.body.classList.remove(scrollLockClassName);
38
- document.body.style.removeProperty("--pro-drawer-form-scroll-top");
39
- document.body.style.removeProperty("--pro-drawer-form-scroll-left");
40
- if (lockedScrollLeft !== 0 || lockedScrollTop !== 0) {
41
- window.scrollTo(lockedScrollLeft, lockedScrollTop);
42
- }
43
- lockedScrollLeft = 0;
44
- lockedScrollTop = 0;
45
- }
46
- };
47
- };
48
8
  const useProDrawerFormContext = () => useContext(ProDrawerFormContext);
49
9
  const ProDrawerForm = forwardRef((props, ref) => {
50
10
  var _a, _b, _c, _d, _e, _f;
@@ -67,12 +27,6 @@ const ProDrawerForm = forwardRef((props, ref) => {
67
27
  } = props;
68
28
  const nextIsView = isView || disabled;
69
29
  const nextOkText = okText ?? (mode === "Drawer" ? (_d = (_c = locale) == null ? void 0 : _c.ProDrawerForm) == null ? void 0 : _d.save : (_f = (_e = locale) == null ? void 0 : _e.ProDrawerForm) == null ? void 0 : _f.confirm);
70
- useEffect(() => {
71
- if (!open || mode !== "Drawer") {
72
- return void 0;
73
- }
74
- return lockRootScroll();
75
- }, [mode, open]);
76
30
  const { width: deprecatedWidth, ...restPropsWithoutWidth } = restProps;
77
31
  const width = resolveDrawerSize(size, deprecatedWidth);
78
32
  const [form] = ProForm.useForm(originalForm);
@@ -1,17 +1,5 @@
1
1
  @import '../../style/variables.less';
2
2
 
3
- html.pro-drawer-form-scroll-lock {
4
- overflow: hidden !important;
5
- }
6
-
7
- body.pro-drawer-form-scroll-lock {
8
- position: fixed !important;
9
- top: var(--pro-drawer-form-scroll-top, 0);
10
- left: var(--pro-drawer-form-scroll-left, 0);
11
- width: 100%;
12
- overflow: hidden !important;
13
- }
14
-
15
3
  .pro-drawer {
16
4
  .original-value-tooltip {
17
5
  position: fixed;
@@ -35,7 +35,8 @@ import {
35
35
  OMIT_FORM_ITEM_AND_DOM_KEYS,
36
36
  arePropsEqual,
37
37
  hasRowFunctionDependency,
38
- mergeOnFieldChangeRow
38
+ mergeOnFieldChangeRow,
39
+ stabilizeDatePickerValueProps
39
40
  } from "./tools";
40
41
  const RenderField = ({ text: value, record, index, column, config }) => {
41
42
  var _a, _b, _c;
@@ -573,6 +574,7 @@ const RenderField = ({ text: value, record, index, column, config }) => {
573
574
  if (["Select", "ProSelect", "ProEnum"].includes(type)) {
574
575
  componentProps.scrollFollowParent = false;
575
576
  }
577
+ const datePickerValueRef = useRef(void 0);
576
578
  const finalFormItemProps = useMemo(() => {
577
579
  const defaultTransformProps = defaultTransform();
578
580
  const namesTransformProps = namesTransform();
@@ -588,7 +590,7 @@ const RenderField = ({ text: value, record, index, column, config }) => {
588
590
  }
589
591
  return transformNormalize(value2, prevValue, allValues, isDiffMode);
590
592
  } : userNormalize || transformNormalize;
591
- const finalGetValueProps = transformGetValueProps && userGetValueProps ? (value2, ...args) => {
593
+ const mergedGetValueProps = transformGetValueProps && userGetValueProps ? (value2, ...args) => {
592
594
  const transformValueProps = transformGetValueProps(value2, ...args) || {};
593
595
  const nextValue = Object.prototype.hasOwnProperty.call(transformValueProps, "value") ? transformValueProps.value : value2;
594
596
  const userValueProps = userGetValueProps(nextValue, ...args) || {};
@@ -597,6 +599,10 @@ const RenderField = ({ text: value, record, index, column, config }) => {
597
599
  ...userValueProps
598
600
  };
599
601
  } : userGetValueProps || transformGetValueProps;
602
+ const finalGetValueProps = type === "DatePicker" && transformGetValueProps && mergedGetValueProps ? (...args) => {
603
+ const valueProps = mergedGetValueProps(...args);
604
+ return valueProps ? stabilizeDatePickerValueProps(datePickerValueRef, valueProps) : valueProps;
605
+ } : mergedGetValueProps;
600
606
  return {
601
607
  ...lastFormItemProps,
602
608
  ...defaultTransformProps,
@@ -1,5 +1,9 @@
1
1
  import { InternalNamePath, NamePath } from 'antd/lib/form/interface';
2
2
  import { GetOriginalValueParams, RenderFieldComparableProps } from './propsType';
3
+ /** 避免等值日期在表格重渲染时产生新引用,导致 DatePicker 面板状态被重置。 */
4
+ export declare const stabilizeDatePickerValueProps: (valueRef: {
5
+ current: any;
6
+ }, valueProps: Record<string, any>) => Record<string, any>;
3
7
  /** 判断列是否包含可能依赖整行数据的函数型配置。 */
4
8
  export declare const hasRowFunctionDependency: (column: Record<string, any> | null | undefined) => boolean;
5
9
  /**
@@ -2,6 +2,7 @@ import get from "lodash/get";
2
2
  import isEqual from "lodash/isEqual";
3
3
  import isEqualWith from "lodash/isEqualWith";
4
4
  import isFunction from "lodash/isFunction";
5
+ import dayjs from "dayjs";
5
6
  import { customEqualForFunction } from "../../../utils";
6
7
  import { getNamePath, isRecordShallowEqual } from "../../utils/tools";
7
8
  const ROW_FUNCTION_DEPENDENCY_KEYS = [
@@ -15,6 +16,18 @@ const ROW_FUNCTION_DEPENDENCY_KEYS = [
15
16
  "valueType",
16
17
  "viewRender"
17
18
  ];
19
+ const stabilizeDatePickerValueProps = (valueRef, valueProps) => {
20
+ const previousValue = valueRef.current;
21
+ const nextValue = valueProps.value;
22
+ if (dayjs.isDayjs(previousValue) && dayjs.isDayjs(nextValue) && previousValue.valueOf() === nextValue.valueOf() && previousValue.utcOffset() === nextValue.utcOffset() && previousValue.locale() === nextValue.locale()) {
23
+ return {
24
+ ...valueProps,
25
+ value: previousValue
26
+ };
27
+ }
28
+ valueRef.current = nextValue;
29
+ return valueProps;
30
+ };
18
31
  const hasRowFunctionDependency = (column) => ROW_FUNCTION_DEPENDENCY_KEYS.some((key) => isFunction(column == null ? void 0 : column[key]));
19
32
  const mergeOnFieldChangeRow = (beforeRow, mutatedRow, latestStoreRow) => {
20
33
  const before = beforeRow || {};
@@ -220,6 +233,7 @@ export {
220
233
  getOriginalValue,
221
234
  hasRowFunctionDependency,
222
235
  mergeOnFieldChangeRow,
236
+ stabilizeDatePickerValueProps,
223
237
  toNamePath,
224
238
  toNamePaths
225
239
  };
@@ -239,6 +239,14 @@
239
239
  }
240
240
  }
241
241
 
242
+ .@{ant-prefix}-table-tbody
243
+ .is-editing:not(.@{ant-prefix}-table-measure-row):not(.@{ant-prefix}-table-row-extra)
244
+ .@{ant-prefix}-form-item-control {
245
+ min-height: calc(
246
+ var(--zaui-height-size-lg; 32px) * var(--zaui-size; 1)
247
+ ) !important;
248
+ }
249
+
242
250
  .@{ant-prefix}-table-tbody
243
251
  .is-editing:not(.@{ant-prefix}-table-measure-row):not(.@{ant-prefix}-table-row-extra)
244
252
  .@{ant-prefix}-form-item.@{ant-prefix}-form-item-has-error {
@@ -2,16 +2,16 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useContext } from "react";
3
3
  import { Popover, Tooltip } from "antd";
4
4
  import classnames from "classnames";
5
- import { Link as RouterLink } from "react-router-dom";
5
+ import { Link as RouterLink, useLocation } from "react-router-dom";
6
6
  import ProIcon from "../../../../../ProIcon";
7
7
  import SideMenu from "../SideMenu";
8
8
  import { LayoutContext } from "../../../../index";
9
- import { getUrlParams, getPathNameKey, findMenuItemByKey } from "../../../../utils";
9
+ import { findMenuItemByKey, resolveMenuKeyIdPath } from "../../../../utils";
10
10
  const Link = RouterLink;
11
11
  const FoldMenu = (props) => {
12
12
  const { style, dataSource, onMenuClick } = props;
13
13
  const { menus, iconfontUrl, notice, collapsed, headerHeight } = dataSource;
14
- const pathNamePrefix = `/${window.location.pathname.split("/")[1]}`;
14
+ const location = useLocation();
15
15
  const noticeCls = classnames({
16
16
  "pro-layout-menu-tooltip": true,
17
17
  "pro-layout-menu-tooltip-has-notice": notice,
@@ -22,17 +22,16 @@ const FoldMenu = (props) => {
22
22
  onSelected: () => {
23
23
  }
24
24
  };
25
+ const currentKeyIdPath = resolveMenuKeyIdPath({
26
+ menus,
27
+ pathname: location.pathname,
28
+ search: location.search,
29
+ selectedPath
30
+ });
25
31
  return /* @__PURE__ */ jsx("div", { className: "pro-layout-menu-fold", style: { ...style }, children: /* @__PURE__ */ jsx("ul", { className: "pro-layout-menu-fold-list", style: { ...style }, children: menus.filter((item) => !item.hideInMenu).map((item, index) => {
26
32
  var _a;
27
33
  const { id, url, name, icon, imgUrl, imgActiveUrl, children } = item;
28
34
  const toPath = item.redirectUrl || item.url;
29
- const selectedMenu = getUrlParams("activeMenu");
30
- const pathToMatch = selectedPath || selectedMenu || window.location.pathname;
31
- const currentKeyIdPath = getPathNameKey({
32
- menus,
33
- pathName: pathToMatch
34
- // 优先匹配上下文路径
35
- }) || [];
36
35
  const cls = classnames({
37
36
  active: currentKeyIdPath.includes(id)
38
37
  });
@@ -42,7 +41,7 @@ const FoldMenu = (props) => {
42
41
  "img",
43
42
  {
44
43
  className: "pro-layout-icon",
45
- src: pathNamePrefix === url ? imgActiveUrl || imgUrl : imgUrl,
44
+ src: currentKeyIdPath.includes(id) ? imgActiveUrl || imgUrl : imgUrl,
46
45
  alt: "icon"
47
46
  }
48
47
  ) : /* @__PURE__ */ jsx(
@@ -4,15 +4,14 @@ import { Menu } from "antd";
4
4
  import { useDeepCompareEffect, useSetState } from "ahooks";
5
5
  import { CaretDownOutlined } from "@ant-design/icons";
6
6
  import classnames from "classnames";
7
- import { Link as RouterLink } from "react-router-dom";
7
+ import { Link as RouterLink, useLocation } from "react-router-dom";
8
8
  import cloneDeep from "lodash/cloneDeep";
9
9
  import { LayoutContext } from "../../../../index";
10
- import { getIdsByPathName, findMenuItemByKey } from "../../../../utils";
10
+ import { findMenuItemByKey, resolveMenuKeyIdPath } from "../../../../utils";
11
11
  import { canOpenAsTab } from "../../../TabsManager/utils";
12
12
  import ProIcon from "../../../../../ProIcon";
13
13
  const Link = RouterLink;
14
14
  const OpenMenu = (props) => {
15
- var _a;
16
15
  const { className, dataSource, style, onMenuClick, textVisible = true } = props;
17
16
  const { menus, sideMenu } = dataSource || {};
18
17
  const linkRef = useRef(null);
@@ -21,7 +20,7 @@ const OpenMenu = (props) => {
21
20
  openKeys: [],
22
21
  router: ""
23
22
  });
24
- const query = new URLSearchParams(window.location.search);
23
+ const location = useLocation();
25
24
  const layoutContext = useContext(LayoutContext);
26
25
  const layoutSelectedPath = layoutContext == null ? void 0 : layoutContext.selectedPath;
27
26
  const layoutOnSelected = layoutContext == null ? void 0 : layoutContext.onSelected;
@@ -31,8 +30,12 @@ const OpenMenu = (props) => {
31
30
  "pro-layout-menu-text-hidden": textVisible === false,
32
31
  [`${className}`]: className
33
32
  });
34
- const preferredPath = query.get("activeMenu") || (layoutSelectedPath === "##EMPTY##" ? null : layoutSelectedPath) || window.location.pathname;
35
- const selectKeyIdPath = preferredPath ? ((_a = getIdsByPathName(menus, preferredPath)) == null ? void 0 : _a.map((item) => String(item))) || [] : [];
33
+ const selectKeyIdPath = resolveMenuKeyIdPath({
34
+ menus,
35
+ pathname: location.pathname,
36
+ search: location.search,
37
+ selectedPath: layoutSelectedPath
38
+ }).map((item) => String(item));
36
39
  const selectedRootKey = selectKeyIdPath[0];
37
40
  const itemsTransform = useMemo(() => {
38
41
  const result = cloneDeep(menus);
@@ -41,8 +44,8 @@ const OpenMenu = (props) => {
41
44
  }
42
45
  const menuDeep = (data) => {
43
46
  data.forEach((item) => {
44
- var _a2, _b, _c;
45
- const isFirstMenu = ((_a2 = item.keyIdPath) == null ? void 0 : _a2.length) === 1 || sideMenu && ((_b = item.keyIdPath) == null ? void 0 : _b.length) === 2;
47
+ var _a, _b, _c;
48
+ const isFirstMenu = ((_a = item.keyIdPath) == null ? void 0 : _a.length) === 1 || sideMenu && ((_b = item.keyIdPath) == null ? void 0 : _b.length) === 2;
46
49
  item.label = /* @__PURE__ */ jsxs(
47
50
  "div",
48
51
  {
@@ -140,7 +143,7 @@ const OpenMenu = (props) => {
140
143
  }
141
144
  if (menuItem && canOpenAsTab(menuItem) && shouldActivate) {
142
145
  setState({
143
- selectedKeys: keyPath,
146
+ selectedKeys: menuKeyPath,
144
147
  router: menuRouter
145
148
  });
146
149
  layoutOnSelected == null ? void 0 : layoutOnSelected({
@@ -6,6 +6,16 @@ import type { MenusType } from '../propTypes';
6
6
  * @return result
7
7
  */
8
8
  export declare const getIdsByPathName: (menus: any[], activeMenu?: string) => number[];
9
+ interface ResolveMenuKeyIdPathOptions {
10
+ menus: any[];
11
+ pathname: string;
12
+ search?: string;
13
+ selectedPath?: string;
14
+ }
15
+ /**
16
+ * 统一解析菜单激活路径:显式 activeMenu 优先,其次匹配真实路由,最后回退上次选择。
17
+ */
18
+ export declare const resolveMenuKeyIdPath: ({ menus, pathname, search, selectedPath, }: ResolveMenuKeyIdPathOptions) => number[];
9
19
  /**
10
20
  * 转换菜单数据源评价keyUrlPath与keyIdPath
11
21
  * @param menuData 菜单数据源
@@ -41,3 +51,4 @@ export declare const getPathNameKey: ({ menus, pathName }: {
41
51
  * @returns 找到的菜单项数据或null
42
52
  */
43
53
  export declare const findMenuItemByKey: (menus: any[], key: string) => any;
54
+ export {};
@@ -1,12 +1,21 @@
1
1
  import isPlainObject from "lodash/isPlainObject";
2
2
  const updateBestMatch = (pathName, itemUrl, itemRedirectUrl, keyIdPath, bestMatch) => {
3
- if (itemUrl && pathName.includes(itemUrl)) {
3
+ const isSameOrNestedPath = (candidate) => {
4
+ if (!candidate)
5
+ return false;
6
+ const normalizedCandidate = candidate.length > 1 ? candidate.replace(/\/+$/, "") : candidate;
7
+ if (pathName === normalizedCandidate)
8
+ return true;
9
+ const boundary = pathName.charAt(normalizedCandidate.length);
10
+ return pathName.startsWith(normalizedCandidate) && ["/", "?", "#"].includes(boundary);
11
+ };
12
+ if (isSameOrNestedPath(itemUrl)) {
4
13
  const urlLength = itemUrl.length;
5
14
  if (!bestMatch || urlLength > bestMatch.urlLength) {
6
15
  return { keyIdPath, urlLength };
7
16
  }
8
17
  }
9
- if (itemRedirectUrl && pathName.includes(itemRedirectUrl)) {
18
+ if (isSameOrNestedPath(itemRedirectUrl)) {
10
19
  const urlLength = itemRedirectUrl.length;
11
20
  if (!bestMatch || urlLength > bestMatch.urlLength) {
12
21
  return { keyIdPath, urlLength };
@@ -14,6 +23,27 @@ const updateBestMatch = (pathName, itemUrl, itemRedirectUrl, keyIdPath, bestMatc
14
23
  }
15
24
  return bestMatch;
16
25
  };
26
+ const getExactMenuKeyIdPath = (menus, pathname) => {
27
+ const normalizePathname = (value) => {
28
+ if (!value)
29
+ return "";
30
+ const path = value.split(/[?#]/)[0];
31
+ return path.length > 1 ? path.replace(/\/+$/, "") : path;
32
+ };
33
+ const targetPathname = normalizePathname(pathname);
34
+ for (const item of menus || []) {
35
+ const routes = [item == null ? void 0 : item.redirectUrl, item == null ? void 0 : item.router, item == null ? void 0 : item.url].map(normalizePathname);
36
+ if (targetPathname && routes.includes(targetPathname)) {
37
+ return item.keyIdPath || [];
38
+ }
39
+ if (Array.isArray(item == null ? void 0 : item.children) && item.children.length) {
40
+ const childPath = getExactMenuKeyIdPath(item.children, pathname);
41
+ if (childPath.length)
42
+ return childPath;
43
+ }
44
+ }
45
+ return [];
46
+ };
17
47
  const getIdsByPathName = (menus, activeMenu) => {
18
48
  const _pathName = activeMenu || window.location.pathname;
19
49
  let result;
@@ -42,6 +72,26 @@ const getIdsByPathName = (menus, activeMenu) => {
42
72
  menuDeep(menus);
43
73
  return result || (bestMatch == null ? void 0 : bestMatch.keyIdPath) || [];
44
74
  };
75
+ const resolveMenuKeyIdPath = ({
76
+ menus,
77
+ pathname,
78
+ search = "",
79
+ selectedPath
80
+ }) => {
81
+ if (selectedPath === "##EMPTY##")
82
+ return [];
83
+ const activeMenu = new URLSearchParams(search).get("activeMenu");
84
+ const activeMenuPath = activeMenu ? getIdsByPathName(menus, activeMenu) : [];
85
+ if (activeMenuPath.length)
86
+ return activeMenuPath;
87
+ const exactRoutePath = getExactMenuKeyIdPath(menus, pathname);
88
+ if (exactRoutePath.length)
89
+ return exactRoutePath;
90
+ const nestedRoutePath = getIdsByPathName(menus, pathname);
91
+ if (nestedRoutePath.length)
92
+ return nestedRoutePath;
93
+ return selectedPath ? getIdsByPathName(menus, selectedPath) : [];
94
+ };
45
95
  const transformMenu = (menuData, pathPrefix) => {
46
96
  const data = [...menuData];
47
97
  const menuDeep = (menuDeepItem) => {
@@ -163,6 +213,7 @@ export {
163
213
  getIdsByPathName,
164
214
  getPathNameKey,
165
215
  getUrlParams,
216
+ resolveMenuKeyIdPath,
166
217
  transformMenu,
167
218
  transformMenus
168
219
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zat-design/sisyphus-react",
3
- "version": "4.6.4",
3
+ "version": "4.6.5-beta.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -106,6 +106,14 @@
106
106
  "engines": {
107
107
  "node": ">=20.0.0"
108
108
  },
109
+ "resolutions": {
110
+ "@umijs/bundler-utils@3.5.43": "3.5.43"
111
+ },
112
+ "overrides": {
113
+ "@umijs/bundler-webpack@3.5.43": {
114
+ "@umijs/bundler-utils": "3.5.43"
115
+ }
116
+ },
109
117
  "browserslist": [
110
118
  "last 2 versions",
111
119
  "Firefox ESR",