@zat-design/sisyphus-react 4.5.8 → 4.5.9-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.
@@ -26,7 +26,7 @@ import { getDefaultProps } from "../../utils/getDefaultProps";
26
26
  import ListChangedWrapper from "./ListChangedWrapper";
27
27
  import useShouldUpdateForTable from "../../utils/useShouldUpdateForTable";
28
28
  import { OMIT_FORM_ITEM_AND_DOM_KEYS, arePropsEqual, hasRowFunctionDependency, mergeOnFieldChangeRow } from "./tools";
29
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
29
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
30
30
  const RenderField = ({
31
31
  text: value,
32
32
  record,
@@ -90,6 +90,8 @@ const RenderField = ({
90
90
 
91
91
  // type类型 首字母转大写
92
92
  type = type?.replace?.(type[0], type[0].toUpperCase()) || 'Input';
93
+ const fallbackType = type;
94
+ const hasCustomComponent = 'component' in column || 'editRender' in column;
93
95
 
94
96
  // 自定义组件时 防止默认值影像后续判断
95
97
  if ('component' in column) {
@@ -176,7 +178,7 @@ const RenderField = ({
176
178
 
177
179
  // component 处理 - 优先使用 hook 返回的值
178
180
  if (_isFunction(lastComponent)) {
179
- lastComponent = dynamicProps.component ?? lastComponent(rowData, reactiveParams);
181
+ lastComponent = dynamicProps.componentResolved ? dynamicProps.component : lastComponent(rowData, reactiveParams);
180
182
  }
181
183
 
182
184
  // 更新 lastEditRender 为处理后的 lastComponent
@@ -198,6 +200,23 @@ const RenderField = ({
198
200
 
199
201
  // 多态:可能是内置组件类型、自定义 component,或已渲染的 ReactElement(lastEditRender),保留显式 any
200
202
  let TargetComponent;
203
+ const fallbackTargetComponent = typeof fallbackType === 'string' ? componentMap[fallbackType] : undefined;
204
+ const invalidComponentWarnedRef = useRef(false);
205
+ const resolveEditTargetComponent = candidate => {
206
+ if ( /*#__PURE__*/React.isValidElement(candidate)) {
207
+ invalidComponentWarnedRef.current = false;
208
+ return candidate;
209
+ }
210
+ if (hasCustomComponent && !invalidComponentWarnedRef.current && process.env.NODE_ENV !== 'production') {
211
+ const columnName = dataIndex ?? column?.name ?? title ?? originTitle ?? 'unknown';
212
+ console.warn('[ProEditTable] component 必须返回合法的 ReactElement,已回退到内置组件。', {
213
+ column: Array.isArray(columnName) ? columnName.join('.') : String(columnName),
214
+ received: candidate
215
+ });
216
+ invalidComponentWarnedRef.current = true;
217
+ }
218
+ return fallbackTargetComponent;
219
+ };
201
220
 
202
221
  // 将Hooks调用移到组件顶层
203
222
  const proConfig = useProConfig();
@@ -320,20 +339,9 @@ const RenderField = ({
320
339
  ...valueTypeTransform()
321
340
  }, form, names, namesStr, type);
322
341
  }, [names, baseName, index, dataIndex, lastFormItemProps, type]);
323
- if (!lastEditRender && typeof type === 'string') {
324
- // componentMap 为内置组件命名空间,按字符串 type 动态取用,保留显式 any 索引
325
- TargetComponent = componentMap[type] ?? /*#__PURE__*/_jsx(_Fragment, {});
326
- }
327
- if (isEditable && isEditing) {
328
- // lastEditRender 已经是处理后的值(通过 dynamicProps.component 或直接计算)
329
- // 如果原本是函数,此时 lastEditRender 已经是执行后的 ReactNode
330
- // 如果原本是 ReactElement,lastEditRender 就是 ReactElement
331
- if ( /*#__PURE__*/React.isValidElement(lastEditRender)) {
332
- TargetComponent = lastEditRender;
333
- } else if (lastEditRender) {
334
- // 其他情况(可能是字符串或其他类型的 ReactNode)
335
- TargetComponent = lastEditRender;
336
- }
342
+ TargetComponent = fallbackTargetComponent;
343
+ if (isEditable && isEditing && hasCustomComponent) {
344
+ TargetComponent = resolveEditTargetComponent(lastEditRender);
337
345
  }
338
346
 
339
347
  // 查看模式
@@ -729,10 +737,7 @@ const RenderField = ({
729
737
  onChange: handleChange,
730
738
  onBlur: handleBlur
731
739
  };
732
- let latestTargetComponent = TargetComponent;
733
- if (!canReuseCurrentState && !latestComponent && typeof type === 'string') {
734
- latestTargetComponent = componentMap[type] ?? /*#__PURE__*/_jsx(_Fragment, {});
735
- }
740
+ let latestTargetComponent = canReuseCurrentState ? TargetComponent : fallbackTargetComponent;
736
741
 
737
742
  // 然后处理自定义 component
738
743
  const latestIsView = !latestIsEditable || record?.['is-view'] || config.isView || virtualKey && !isEditing || getDisabled({
@@ -744,12 +749,8 @@ const RenderField = ({
744
749
  params: latestRowParams,
745
750
  rowDisabled: rowDisabled || 'empty'
746
751
  });
747
- if (!canReuseCurrentState && latestIsEditable && isEditing) {
748
- if ( /*#__PURE__*/React.isValidElement(latestComponent)) {
749
- latestTargetComponent = latestComponent;
750
- } else if (latestComponent) {
751
- latestTargetComponent = latestComponent;
752
- }
752
+ if (!canReuseCurrentState && latestIsEditable && isEditing && hasCustomComponent) {
753
+ latestTargetComponent = resolveEditTargetComponent(latestComponent);
753
754
  }
754
755
 
755
756
  // 查看模式
@@ -936,7 +937,7 @@ const RenderField = ({
936
937
  }) : /*#__PURE__*/_jsx(Container, {
937
938
  viewEmpty: viewEmpty
938
939
  });
939
- if (type === 'FormList') {
940
+ if (type === 'FormList' && !hasCustomComponent && TargetComponent) {
940
941
  FormItem = /*#__PURE__*/_jsx(Form.List, {
941
942
  name: formNamePath ? cellName.slice(formNamePath?.length - 1) : cellName,
942
943
  ..._omit(activeFinalFormItemProps, ['render', 'key', 'width', 'hiddenNames', 'name']),
@@ -1,5 +1,5 @@
1
1
  import { AffixProps, ModalFuncProps } from 'antd';
2
- import { Key, ReactNode } from 'react';
2
+ import { Key, ReactElement, ReactNode } from 'react';
3
3
  import { DragEndEvent } from '@dnd-kit/core';
4
4
  import type { ButtonProps } from 'antd/es/button';
5
5
  import type { TooltipProps } from 'antd/es/tooltip';
@@ -134,7 +134,7 @@ export type viewRenderFn<T = any> = (text?: any, record?: T, options?: OptionsPr
134
134
  * 组件渲染函数类型(与 ReactiveFunction 保持一致)
135
135
  * @template T 记录类型
136
136
  */
137
- export type ComponentRenderFn<T = any> = ReactiveFunction<T, string | number | ReactNode | void>;
137
+ export type ComponentRenderFn<T = any> = ReactiveFunction<T, ReactElement>;
138
138
  /**
139
139
  * 表格列属性接口
140
140
  * @template Values 值类型
@@ -157,8 +157,8 @@ export interface ProColumnsProps<Values = any, T = any> extends Omit<FormItemPro
157
157
  tooltip?: string | ({
158
158
  icon?: string | ReactNode;
159
159
  } & TooltipProps);
160
- /** 组件 */
161
- component?: string | number | ReactNode | ComponentRenderFn<T>;
160
+ /** 自定义组件,或返回合法 ReactElement 的响应式渲染函数 */
161
+ component?: ReactElement | ComponentRenderFn<T>;
162
162
  /** 视图渲染 */
163
163
  viewRender?: string | number | ReactNode | viewRenderFn<T>;
164
164
  /** 隐藏的字段名 */
@@ -11,6 +11,8 @@ interface Result {
11
11
  desensitization: any;
12
12
  valueType: any;
13
13
  component: any;
14
+ /** 动态 component 是否已经执行过,用于区分“返回 undefined”和“尚未计算”。 */
15
+ componentResolved: boolean;
14
16
  /** 当前缓存结果对应的行浅快照,供 RenderField 判断是否可安全复用。 */
15
17
  rowSnapshot: Record<string, any> | undefined;
16
18
  }
@@ -19,6 +19,7 @@ const useShouldUpdateForTable = props => {
19
19
  const desensitizationRef = useRef(undefined);
20
20
  const valueTypeRef = useRef(undefined);
21
21
  const componentRef = useRef(undefined);
22
+ const componentResolvedRef = useRef(false);
22
23
  const resolvedRowSnapshotRef = useRef(undefined);
23
24
  const [, reRender] = useState({});
24
25
  const debouncedUpdateRef = useRef(null);
@@ -101,6 +102,7 @@ const useShouldUpdateForTable = props => {
101
102
  const componentOrEditRender = column.component || column.editRender;
102
103
  if (_isFunction(componentOrEditRender)) {
103
104
  const newComponent = componentOrEditRender(values, reactiveParams);
105
+ componentResolvedRef.current = true;
104
106
  // 对于 ReactNode 类型的返回值,使用深度比较
105
107
  if (!_isEqualWith(componentRef.current, newComponent, customEqualForFunction)) {
106
108
  componentRef.current = newComponent;
@@ -170,7 +172,8 @@ const useShouldUpdateForTable = props => {
170
172
  fieldProps: fieldPropsRef.current ?? column.fieldProps,
171
173
  desensitization: desensitizationRef.current ?? column.desensitization,
172
174
  valueType: valueTypeRef.current ?? column.valueType,
173
- component: componentRef.current ?? (column.component || column.editRender),
175
+ component: componentResolvedRef.current ? componentRef.current : column.component || column.editRender,
176
+ componentResolved: componentResolvedRef.current,
174
177
  rowSnapshot: resolvedRowSnapshotRef.current
175
178
  };
176
179
  };
@@ -81,9 +81,11 @@ export function useRequestList(service, options, useRequestOptions) {
81
81
  });
82
82
  }, [onPageChange]);
83
83
  const onSearch = useCallback(values => {
84
+ if (page.pageNum !== 1) {
85
+ // 查询或重置都从第一页开始,保留当前每页条数
86
+ onChange(1, page.pageSize);
87
+ }
84
88
  if (!_isEqual(searchValues, values)) {
85
- // 保留当前页码和每页条数
86
- onChange(page.pageNum, page.pageSize);
87
89
  setSearchValues(values);
88
90
  }
89
91
  }, [onChange, searchValues, page]);
@@ -171,12 +171,11 @@
171
171
  padding: 4px 0 5px !important;
172
172
  margin-right: 8px !important;
173
173
  margin-left: 0;
174
- background: #e7e8ee;
174
+ background: #F5F5F5;
175
175
  transition: none;
176
176
  border-color: #e7e8ee;
177
177
  &.@{ant-prefix}-tabs-tab-active {
178
178
  background: #ffffff;
179
- border-top: 2px solid var(--zaui-brand, #006aff);
180
179
  }
181
180
  }
182
181
  .ant-tabs-nav {
@@ -1,12 +1,13 @@
1
1
  import { EditOutlined } from '@ant-design/icons';
2
+ import classNames from 'classnames';
2
3
  import React from 'react';
3
- import styles from "./index.less";
4
4
  import { jsx as _jsx } from "react/jsx-runtime";
5
5
  const EditIcon = ({
6
6
  onClick
7
7
  }) => {
8
+ const cls = classNames('pro-table-editable-cell-edit-icon');
8
9
  return /*#__PURE__*/_jsx("span", {
9
- className: styles['editable-cell-edit-icon'],
10
+ className: cls,
10
11
  onClick: onClick,
11
12
  children: /*#__PURE__*/_jsx(EditOutlined, {})
12
13
  });
@@ -1,9 +1,9 @@
1
1
  import _isEqual from "lodash/isEqual";
2
2
  import React, { useState, useRef } from 'react';
3
3
  import { Form } from 'antd';
4
+ import classNames from 'classnames';
4
5
  import * as componentMap from "../../../ProForm/components";
5
6
  import EditIcon from "./EditIcon";
6
- import styles from "./index.less";
7
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const InternalCell = ({
9
9
  value,
@@ -29,6 +29,7 @@ const InternalCell = ({
29
29
  ...restFieldProps
30
30
  } = fieldProps;
31
31
  const Component = componentMap[type] ?? componentMap.Input;
32
+ const wrapperClassName = classNames('pro-table-editable-cell-wrapper');
32
33
  const handleEditIconClick = () => {
33
34
  snapshotRef.current = value;
34
35
  form.setFieldValue(fieldName, value);
@@ -57,7 +58,7 @@ const InternalCell = ({
57
58
  };
58
59
  if (!editing) {
59
60
  return /*#__PURE__*/_jsxs("span", {
60
- className: styles['editable-cell-wrapper'],
61
+ className: wrapperClassName,
61
62
  children: [/*#__PURE__*/_jsx("span", {
62
63
  children: displayContent ?? '-'
63
64
  }), /*#__PURE__*/_jsx(EditIcon, {
@@ -624,6 +624,32 @@
624
624
  }
625
625
  }
626
626
  }
627
+
628
+ .pro-table-editable-cell-wrapper {
629
+ display: flex;
630
+ align-items: center;
631
+ width: 100%;
632
+ justify-content: space-between;
633
+ gap: 4px;
634
+ white-space: nowrap;
635
+ }
636
+
637
+ .pro-table-editable-cell-edit-icon {
638
+ display: inline-flex;
639
+ align-items: center;
640
+ color: #d8d8d8;
641
+ cursor: pointer;
642
+ visibility: hidden;
643
+ flex-shrink: 0;
644
+
645
+ &:hover {
646
+ color: var(--zaui-brand, #006aff);
647
+ }
648
+ }
649
+
650
+ td:hover .pro-table-editable-cell-edit-icon {
651
+ visibility: visible;
652
+ }
627
653
  }
628
654
 
629
655
  .@{ant-prefix}-dropdown-placement-bottomLeft {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zat-design/sisyphus-react",
3
- "version": "4.5.8",
3
+ "version": "4.5.9-beta.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -1,24 +0,0 @@
1
- .editable-cell-wrapper {
2
- display: flex;
3
- align-items: center;
4
- width: 100%;
5
- justify-content: space-between;
6
- gap: 4px;
7
- }
8
-
9
- .editable-cell-edit-icon {
10
- display: inline-flex;
11
- align-items: center;
12
- cursor: pointer;
13
- visibility: hidden;
14
- color: rgba(0, 0, 0, 0.65);
15
- flex-shrink: 0;
16
-
17
- &:hover {
18
- color: var(--zaui-brand, #006aff);
19
- }
20
- }
21
-
22
- td:hover .editable-cell-edit-icon {
23
- visibility: visible;
24
- }