@canlooks/can-ui 0.0.53 → 0.0.55

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.
@@ -24,7 +24,13 @@ export type LoadRowsReturn<R extends RowType> = {
24
24
  total: number;
25
25
  };
26
26
  type EachRowType<R extends RowType, T> = T | ((row: R) => T);
27
- export interface CurdBaseProps<R extends RowType, F extends FormValue> extends DataGridBaseProps<R> {
27
+ export type CurdRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
28
+ openCreateDialog(initialValue?: F): Promise<F> | undefined;
29
+ selectSingle(): Promise<R> | undefined;
30
+ selectMultiple(selected?: Id[]): Promise<Id[]> | undefined;
31
+ };
32
+ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends Omit<DataGridBaseProps<R>, 'ref'> {
33
+ ref?: Ref<CurdRef<R, F>>;
28
34
  /** 默认属性会传递给DataGrid组件,外层包裹元素的属性使用wrapperProps */
29
35
  wrapperProps?: DivProps;
30
36
  wrapperRef?: Ref<HTMLDivElement>;
@@ -82,14 +88,14 @@ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends D
82
88
  onUpdate?(formValue: F, row: R): any;
83
89
  onDelete?(row: R): any;
84
90
  /** 行数据转换为表单值的方法,若不指定,行数据会直接填入表单 */
85
- postData?(row: R): F | Promise<F>;
91
+ rowToForm?(row: R): F | Promise<F>;
86
92
  dialogProps?: CurdDialogProps<R, F>;
87
93
  formProps?: FormProps<F>;
88
94
  formRef?: Ref<FormRef<F>>;
89
95
  }
90
- interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
96
+ interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
91
97
  }
92
- interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
98
+ interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
93
99
  }
94
100
  export type CurdProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> = CurdSingleProps<R, F, V> | CurdMultipleProps<R, F, V>;
95
101
  export declare const Curd: {
@@ -23,7 +23,22 @@ const faPenToSquare_1 = require("@fortawesome/free-regular-svg-icons/faPenToSqua
23
23
  const faPlus_1 = require("@fortawesome/free-solid-svg-icons/faPlus");
24
24
  const faRotateRight_1 = require("@fortawesome/free-solid-svg-icons/faRotateRight");
25
25
  exports.Curd = (0, react_1.memo)((props) => {
26
- const { wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, postData, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
26
+ const { ref, wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, rowToForm, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
27
+ /**
28
+ * -------------------------------------------------------------
29
+ * ref
30
+ */
31
+ (0, react_1.useImperativeHandle)(ref, () => ({
32
+ openCreateDialog(initialValue) {
33
+ return curdDialogRef.current?.open(void 0, initialValue);
34
+ },
35
+ selectSingle() {
36
+ return curdDialogRef.current?.selectSingle();
37
+ },
38
+ selectMultiple(selected) {
39
+ return curdDialogRef.current?.selectMultiple(selected);
40
+ }
41
+ }));
27
42
  /**
28
43
  * -------------------------------------------------------------
29
44
  * 筛选部分
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dialogStyle = exports.style = exports.classes = void 0;
4
4
  const react_1 = require("@emotion/react");
5
5
  const utils_1 = require("../../utils");
6
+ const button_style_1 = require("../button/button.style");
6
7
  exports.classes = (0, utils_1.defineInnerClasses)('curd', [
7
8
  'filter',
8
9
  'filterGridContainer',
@@ -94,5 +95,9 @@ exports.dialogStyle = (0, utils_1.defineCss)(({ spacing }) => (0, react_1.css) `
94
95
  display: flex;
95
96
  align-items: center;
96
97
  gap: ${spacing[8]}px;
98
+
99
+ .${button_style_1.classes.root} {
100
+ font-size: 1rem;
101
+ }
97
102
  }
98
103
  `);
@@ -3,8 +3,11 @@ import { DialogProps } from '../dialog';
3
3
  import { RowType } from '../dataGrid';
4
4
  import { FormValue } from '../form';
5
5
  import { CurdBaseProps } from './curd';
6
+ import { Id } from '../../types';
6
7
  export type CurdDialogRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
7
- open(activeRow?: R): Promise<F>;
8
+ open(activeRow?: R, initialFormValue?: F): Promise<F>;
9
+ selectSingle(): Promise<R>;
10
+ selectMultiple(selected?: Id[]): Promise<Id[]>;
8
11
  };
9
12
  export interface CurdDialogProps<R extends RowType, F extends FormValue = FormValue> extends Omit<DialogProps, 'ref'> {
10
13
  ref?: Ref<CurdDialogRef<R, F>>;
@@ -14,35 +14,49 @@ const curd_style_1 = require("./curd.style");
14
14
  const pickerDialog_1 = require("../pickerDialog");
15
15
  const __1 = require("../..");
16
16
  const faCopy_1 = require("@fortawesome/free-regular-svg-icons/faCopy");
17
- exports.CurdDialog = (0, react_2.memo)(({ ref, onFinish,
18
- // 继承来的属性
19
- curdProps, ...props }) => {
20
- const { columns, postData, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
17
+ exports.CurdDialog = (0, react_2.memo)(({ ref, onFinish, curdProps, ...props }) => {
18
+ const { columns, rowToForm, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
21
19
  /**
22
20
  * ----------------------------------------------------------------
23
21
  * ref与promise部分
24
22
  */
25
23
  const innerFormRef = (0, react_2.useRef)(null);
26
- const resolvers = (0, react_2.useRef)(void 0);
24
+ const openResolvers = (0, react_2.useRef)(void 0);
27
25
  const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
28
26
  const closeHandler = (reason) => {
29
27
  if (reason === 'confirmed') {
30
28
  return;
31
29
  }
32
30
  props.onClose?.(reason);
33
- resolvers.current?.reject({
31
+ openResolvers.current?.reject({
34
32
  type: 'canceled',
35
33
  value: innerFormRef.current.getFormValue()
36
34
  });
37
35
  setInnerOpen(false);
38
36
  };
37
+ const [selectMode, setSelectMode] = (0, react_2.useState)('single');
38
+ const selectResolvers = (0, react_2.useRef)(void 0);
39
39
  (0, react_2.useImperativeHandle)(ref, () => ({
40
- open(row) {
40
+ open(row, initialFormValue) {
41
41
  innerFormRef.current?.resetForm();
42
- setInnerOpen(true);
42
+ suppressTransform.current = !!initialFormValue;
43
+ initialFormValue && innerFormRef.current?.setFormValue(initialFormValue);
43
44
  setActiveRow(row);
44
- const { promise } = resolvers.current = Promise.withResolvers();
45
+ setInnerOpen(true);
46
+ const { promise } = openResolvers.current = Promise.withResolvers();
47
+ return promise;
48
+ },
49
+ selectSingle() {
50
+ isCopying.current = false;
51
+ setSelectMode('single');
52
+ pickerDialogRef.current.open().then();
53
+ const { promise } = selectResolvers.current = Promise.withResolvers();
45
54
  return promise;
55
+ },
56
+ selectMultiple(selected) {
57
+ isCopying.current = false;
58
+ setSelectMode('multiple');
59
+ return pickerDialogRef.current.open(selected);
46
60
  }
47
61
  }));
48
62
  /**
@@ -50,13 +64,14 @@ curdProps, ...props }) => {
50
64
  * 表单项
51
65
  */
52
66
  const [activeRow, setActiveRow] = (0, react_2.useState)();
67
+ const suppressTransform = (0, react_2.useRef)(false);
53
68
  const [transforming, setFormValue] = (0, utils_1.useLoading)(async (row) => {
54
- const formValue = postData && row ? await postData(row) : row;
69
+ const formValue = rowToForm && row ? await rowToForm(row) : row;
55
70
  formValue && innerFormRef.current?.setFormValue(formValue);
56
71
  });
57
72
  (0, react_2.useEffect)(() => {
58
- innerOpen.current && setFormValue(activeRow);
59
- }, [innerOpen.current]); // 依赖innerOpen而不依赖activeRow的原因是,有可能连续两次打开的activeRow是相同的
73
+ innerOpen.current && !suppressTransform.current && setFormValue(activeRow);
74
+ }, [innerOpen.current, activeRow]);
60
75
  const renderedFormItems = (0, react_2.useMemo)(() => {
61
76
  return (0, utils_1.columnsToFormItem)(columns, activeRow)?.map(col => {
62
77
  if ((0, react_2.isValidElement)(col)) {
@@ -75,7 +90,7 @@ curdProps, ...props }) => {
75
90
  };
76
91
  const [innerLoading, finishHandler] = (0, utils_1.useLoading)(async (value) => {
77
92
  formProps?.onFinish?.(value);
78
- resolvers.current?.resolve(value);
93
+ openResolvers.current?.resolve(value);
79
94
  await onFinish?.(value);
80
95
  setInnerOpen(false);
81
96
  }, props.confirmLoading);
@@ -83,20 +98,32 @@ curdProps, ...props }) => {
83
98
  * ----------------------------------------------------------------
84
99
  * 复制
85
100
  */
101
+ const isCopying = (0, react_2.useRef)(false);
86
102
  const pickerDialogRef = (0, react_2.useRef)(null);
87
- const copiedHandler = (checked, value, row) => {
88
- const title = !(0, utils_1.isUnset)(titleKey) ? row[titleKey] : void 0;
89
- typeof title === 'string'
90
- ? setFormValue({
91
- ...row,
92
- [titleKey]: `${title} - 副本`
93
- })
94
- : setFormValue(row);
103
+ const onCopyButtonClick = () => {
104
+ isCopying.current = true;
105
+ setSelectMode('single');
106
+ pickerDialogRef.current.open().then();
107
+ };
108
+ const toggleHandler = (checked, value, row) => {
109
+ if (isCopying.current) {
110
+ const title = !(0, utils_1.isUnset)(titleKey) ? row[titleKey] : void 0;
111
+ typeof title === 'string'
112
+ ? setFormValue({
113
+ ...row,
114
+ [titleKey]: `${title} - 副本`
115
+ })
116
+ : setFormValue(row);
117
+ }
118
+ else {
119
+ // 处理selectSingle
120
+ selectResolvers.current?.resolve(row);
121
+ }
95
122
  };
96
123
  const rowTitle = activeRow && !(0, utils_1.isUnset)(titleKey) ? activeRow[titleKey] : void 0;
97
124
  return ((0, jsx_runtime_1.jsxs)(dialog_1.Dialog, { css: curd_style_1.dialogStyle, width: 600, title: activeRow
98
125
  ? `${updateName}${dataName}${rowTitle ? ' - ' + rowTitle : ''}`
99
126
  : (0, jsx_runtime_1.jsxs)("div", { className: curd_style_1.classes.dialogTitle, children: [(0, jsx_runtime_1.jsxs)("span", { children: [createName, dataName] }), copyable &&
100
- (0, jsx_runtime_1.jsxs)(button_1.Button, { variant: "plain", prefix: (0, jsx_runtime_1.jsx)(__1.Icon, { icon: faCopy_1.faCopy }), onClick: () => pickerDialogRef.current.open(), children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [(0, jsx_runtime_1.jsx)(loading_1.Loading, { open: transforming.current, children: (0, jsx_runtime_1.jsx)(form_1.Form, { labelWidth: "20%", ...formProps, ref: (0, utils_1.cloneRef)(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
101
- (0, jsx_runtime_1.jsx)(pickerDialog_1.PickerDialog, { ref: pickerDialogRef, onToggle: copiedHandler, children: (0, jsx_runtime_1.jsx)(curd_1.Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
127
+ (0, jsx_runtime_1.jsxs)(button_1.Button, { variant: "plain", prefix: (0, jsx_runtime_1.jsx)(__1.Icon, { icon: faCopy_1.faCopy }), onClick: onCopyButtonClick, children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [(0, jsx_runtime_1.jsx)(loading_1.Loading, { open: transforming.current, children: (0, jsx_runtime_1.jsx)(form_1.Form, { labelWidth: "20%", ...formProps, ref: (0, utils_1.cloneRef)(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
128
+ (0, jsx_runtime_1.jsx)(pickerDialog_1.PickerDialog, { ref: pickerDialogRef, multiple: selectMode === 'multiple', onToggle: toggleHandler, children: (0, jsx_runtime_1.jsx)(curd_1.Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
102
129
  });
@@ -16,13 +16,6 @@ exports.PickerDialog = (({ ref, dialogRef, multiple, children, showSelectedList
16
16
  // 以下属性从SelectionContextBaseProps继承
17
17
  options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation = 'dependent', integration = 'shallowest', disabled, clearable = !!multiple, onToggle, ...props }) => {
18
18
  const resolvers = (0, react_1.useRef)(void 0);
19
- const [innerValue, _setInnerValue] = (0, react_1.useState)(multiple ? [] : null);
20
- const setInnerValue = (value) => {
21
- _setInnerValue(value);
22
- // 单选模式,值每次改变都触发确认
23
- !multiple && confirmHandler(value);
24
- };
25
- const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
26
19
  (0, react_1.useImperativeHandle)(ref, () => ({
27
20
  open(value) {
28
21
  _setInnerValue(value ?? null);
@@ -31,6 +24,13 @@ options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation =
31
24
  return promise;
32
25
  }
33
26
  }));
27
+ const [innerValue, _setInnerValue] = (0, react_1.useState)(multiple ? [] : null);
28
+ const setInnerValue = (value) => {
29
+ _setInnerValue(value);
30
+ // 单选模式,值每次改变都触发确认
31
+ !multiple && confirmHandler(value);
32
+ };
33
+ const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(props.defaultOpen, props.open);
34
34
  const onCloseHandler = (reason) => {
35
35
  if (reason === 'confirmed') {
36
36
  return;
@@ -10,24 +10,24 @@ import { Id } from '../../types';
10
10
  export declare function CURD<R extends RowType, F extends FormValue = FormValue>(props?: CurdBaseProps<R, F>): <T extends ComponentClass>(target: T) => T;
11
11
  export declare namespace CURD {
12
12
  var Column: typeof import("./curd").Column;
13
- var Reqeust: typeof import("./curd").Reqeust;
13
+ var LoadRows: typeof import("./curd").LoadRows;
14
14
  var OnReload: typeof import("./curd").OnReload;
15
15
  var OnFilter: typeof import("./curd").OnFilter;
16
16
  var OnCreate: typeof import("./curd").OnCreate;
17
17
  var OnUpdate: typeof import("./curd").OnUpdate;
18
18
  var OnDelete: typeof import("./curd").OnDelete;
19
- var PostData: typeof import("./curd").PostData;
19
+ var RowToForm: typeof import("./curd").RowToForm;
20
20
  }
21
21
  export declare function DATA_GRID<R extends RowType, V extends Id = Id>(props?: DataGridProps<R, V>): <T extends ComponentClass>(target: T) => T;
22
22
  export declare namespace DATA_GRID {
23
23
  var Column: typeof import("./curd").Column;
24
- var Reqeust: typeof import("./curd").Reqeust;
24
+ var LoadRows: typeof import("./curd").LoadRows;
25
25
  var OnReload: typeof import("./curd").OnReload;
26
26
  var OnFilter: typeof import("./curd").OnFilter;
27
27
  var OnCreate: typeof import("./curd").OnCreate;
28
28
  var OnUpdate: typeof import("./curd").OnUpdate;
29
29
  var OnDelete: typeof import("./curd").OnDelete;
30
- var PostData: typeof import("./curd").PostData;
30
+ var RowToForm: typeof import("./curd").RowToForm;
31
31
  }
32
32
  type ColumnDecorator = (prototype: Object, property: string, descriptor?: TypedPropertyDescriptor<any>) => void;
33
33
  export declare function Column(title: ReactNode): ColumnDecorator;
@@ -51,8 +51,8 @@ export declare function Form(prototype: Object, property: string, descriptor?: T
51
51
  * 方法修饰器
52
52
  */
53
53
  type MethodDecorator = (prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>) => void;
54
- export declare function Reqeust(): MethodDecorator;
55
- export declare function Reqeust(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
54
+ export declare function LoadRows(): MethodDecorator;
55
+ export declare function LoadRows(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
56
56
  export declare function OnReload(): MethodDecorator;
57
57
  export declare function OnReload(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
58
58
  export declare function OnFilter(): MethodDecorator;
@@ -63,6 +63,6 @@ export declare function OnUpdate(): MethodDecorator;
63
63
  export declare function OnUpdate(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
64
64
  export declare function OnDelete(): MethodDecorator;
65
65
  export declare function OnDelete(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
66
- export declare function PostData(): MethodDecorator;
67
- export declare function PostData(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
66
+ export declare function RowToForm(): MethodDecorator;
67
+ export declare function RowToForm(prototype: Object, property: string, descriptor: TypedPropertyDescriptor<any>): void;
68
68
  export {};
@@ -7,13 +7,13 @@ exports.Hide = Hide;
7
7
  exports.Sort = Sort;
8
8
  exports.Filter = Filter;
9
9
  exports.Form = Form;
10
- exports.Reqeust = Reqeust;
10
+ exports.LoadRows = LoadRows;
11
11
  exports.OnReload = OnReload;
12
12
  exports.OnFilter = OnFilter;
13
13
  exports.OnCreate = OnCreate;
14
14
  exports.OnUpdate = OnUpdate;
15
15
  exports.OnDelete = OnDelete;
16
- exports.PostData = PostData;
16
+ exports.RowToForm = RowToForm;
17
17
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
18
18
  const curd_1 = require("../../components/curd");
19
19
  const dataGrid_1 = require("../../components/dataGrid");
@@ -119,8 +119,8 @@ function setColumnConfigValue(key, value = true) {
119
119
  };
120
120
  }
121
121
  const prototype_methods = new WeakMap();
122
- CURD.Reqeust = DATA_GRID.Reqeust = Reqeust;
123
- function Reqeust(a, b, c) {
122
+ CURD.LoadRows = DATA_GRID.LoadRows = LoadRows;
123
+ function LoadRows(a, b, c) {
124
124
  return typeof c === 'undefined'
125
125
  ? setMethods('loadRows')
126
126
  : setMethods('loadRows')(a, b, c);
@@ -155,11 +155,11 @@ function OnDelete(a, b, c) {
155
155
  ? setMethods('onDelete')
156
156
  : setMethods('onDelete')(a, b, c);
157
157
  }
158
- CURD.PostData = DATA_GRID.PostData = PostData;
159
- function PostData(a, b, c) {
158
+ CURD.RowToForm = DATA_GRID.RowToForm = RowToForm;
159
+ function RowToForm(a, b, c) {
160
160
  return typeof c === 'undefined'
161
- ? setMethods('postData')
162
- : setMethods('postData')(a, b, c);
161
+ ? setMethods('rowToForm')
162
+ : setMethods('rowToForm')(a, b, c);
163
163
  }
164
164
  /**
165
165
  * 通用设置prototype_methods的方法
@@ -24,7 +24,13 @@ export type LoadRowsReturn<R extends RowType> = {
24
24
  total: number;
25
25
  };
26
26
  type EachRowType<R extends RowType, T> = T | ((row: R) => T);
27
- export interface CurdBaseProps<R extends RowType, F extends FormValue> extends DataGridBaseProps<R> {
27
+ export type CurdRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
28
+ openCreateDialog(initialValue?: F): Promise<F> | undefined;
29
+ selectSingle(): Promise<R> | undefined;
30
+ selectMultiple(selected?: Id[]): Promise<Id[]> | undefined;
31
+ };
32
+ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends Omit<DataGridBaseProps<R>, 'ref'> {
33
+ ref?: Ref<CurdRef<R, F>>;
28
34
  /** 默认属性会传递给DataGrid组件,外层包裹元素的属性使用wrapperProps */
29
35
  wrapperProps?: DivProps;
30
36
  wrapperRef?: Ref<HTMLDivElement>;
@@ -82,14 +88,14 @@ export interface CurdBaseProps<R extends RowType, F extends FormValue> extends D
82
88
  onUpdate?(formValue: F, row: R): any;
83
89
  onDelete?(row: R): any;
84
90
  /** 行数据转换为表单值的方法,若不指定,行数据会直接填入表单 */
85
- postData?(row: R): F | Promise<F>;
91
+ rowToForm?(row: R): F | Promise<F>;
86
92
  dialogProps?: CurdDialogProps<R, F>;
87
93
  formProps?: FormProps<F>;
88
94
  formRef?: Ref<FormRef<F>>;
89
95
  }
90
- interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
96
+ interface CurdSingleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridSingleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
91
97
  }
92
- interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'columns'>, CurdBaseProps<R, F> {
98
+ interface CurdMultipleProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> extends Omit<DataGridMultipleProps<R, V>, 'ref' | 'columns'>, CurdBaseProps<R, F> {
93
99
  }
94
100
  export type CurdProps<R extends RowType, F extends FormValue = FormValue, V extends Id = Id> = CurdSingleProps<R, F, V> | CurdMultipleProps<R, F, V>;
95
101
  export declare const Curd: {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
2
- import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { memo, useCallback, useEffect, useMemo, useRef, useImperativeHandle } from 'react';
3
3
  import { DataGrid } from '../dataGrid';
4
4
  import { CurdFilter } from './curdFilter';
5
5
  import { classes, style } from './curd.style';
@@ -20,7 +20,22 @@ import { faPenToSquare } from '@fortawesome/free-regular-svg-icons/faPenToSquare
20
20
  import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus';
21
21
  import { faRotateRight } from '@fortawesome/free-solid-svg-icons/faRotateRight';
22
22
  export const Curd = memo((props) => {
23
- const { wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, postData, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
23
+ const { ref, wrapperProps, wrapperRef, variant = 'standard', loadRows, columns, toolbarLeft, toolbarRight, reloadable = true, onReload, resizable = true, columnConfigurable = true, filterProps, filterRef, initialFilterValue, onFilter, renderFilter, copyable, creatable = true, updatable = true, deletable = true, createButtonProps, updateButtonProps, deleteButtonProps, deleteConfirmProps, controlColumnTitle = '操作', renderExtraControl, titleKey, dataName = '', createName = '添加', updateName = '编辑', deleteName = '删除', onCreate, onUpdate, onDelete, rowToForm, dialogProps, formProps, formRef, onChange, ...dataGridProps } = props;
24
+ /**
25
+ * -------------------------------------------------------------
26
+ * ref
27
+ */
28
+ useImperativeHandle(ref, () => ({
29
+ openCreateDialog(initialValue) {
30
+ return curdDialogRef.current?.open(void 0, initialValue);
31
+ },
32
+ selectSingle() {
33
+ return curdDialogRef.current?.selectSingle();
34
+ },
35
+ selectMultiple(selected) {
36
+ return curdDialogRef.current?.selectMultiple(selected);
37
+ }
38
+ }));
24
39
  /**
25
40
  * -------------------------------------------------------------
26
41
  * 筛选部分
@@ -1,5 +1,6 @@
1
1
  import { css } from '@emotion/react';
2
2
  import { defineInnerClasses, defineCss } from '../../utils';
3
+ import { classes as buttonClasses } from '../button/button.style';
3
4
  export const classes = defineInnerClasses('curd', [
4
5
  'filter',
5
6
  'filterGridContainer',
@@ -91,5 +92,9 @@ export const dialogStyle = defineCss(({ spacing }) => css `
91
92
  display: flex;
92
93
  align-items: center;
93
94
  gap: ${spacing[8]}px;
95
+
96
+ .${buttonClasses.root} {
97
+ font-size: 1rem;
98
+ }
94
99
  }
95
100
  `);
@@ -3,8 +3,11 @@ import { DialogProps } from '../dialog';
3
3
  import { RowType } from '../dataGrid';
4
4
  import { FormValue } from '../form';
5
5
  import { CurdBaseProps } from './curd';
6
+ import { Id } from '../../types';
6
7
  export type CurdDialogRef<R extends RowType = RowType, F extends FormValue = FormValue> = {
7
- open(activeRow?: R): Promise<F>;
8
+ open(activeRow?: R, initialFormValue?: F): Promise<F>;
9
+ selectSingle(): Promise<R>;
10
+ selectMultiple(selected?: Id[]): Promise<Id[]>;
8
11
  };
9
12
  export interface CurdDialogProps<R extends RowType, F extends FormValue = FormValue> extends Omit<DialogProps, 'ref'> {
10
13
  ref?: Ref<CurdDialogRef<R, F>>;
@@ -11,35 +11,49 @@ import { classes, dialogStyle } from './curd.style';
11
11
  import { PickerDialog } from '../pickerDialog';
12
12
  import { Icon } from '../..';
13
13
  import { faCopy } from '@fortawesome/free-regular-svg-icons/faCopy';
14
- export const CurdDialog = memo(({ ref, onFinish,
15
- // 继承来的属性
16
- curdProps, ...props }) => {
17
- const { columns, postData, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
14
+ export const CurdDialog = memo(({ ref, onFinish, curdProps, ...props }) => {
15
+ const { columns, rowToForm, copyable, titleKey, formProps, formRef, dataName = '', createName = '添加', updateName = '编辑' } = curdProps;
18
16
  /**
19
17
  * ----------------------------------------------------------------
20
18
  * ref与promise部分
21
19
  */
22
20
  const innerFormRef = useRef(null);
23
- const resolvers = useRef(void 0);
21
+ const openResolvers = useRef(void 0);
24
22
  const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
25
23
  const closeHandler = (reason) => {
26
24
  if (reason === 'confirmed') {
27
25
  return;
28
26
  }
29
27
  props.onClose?.(reason);
30
- resolvers.current?.reject({
28
+ openResolvers.current?.reject({
31
29
  type: 'canceled',
32
30
  value: innerFormRef.current.getFormValue()
33
31
  });
34
32
  setInnerOpen(false);
35
33
  };
34
+ const [selectMode, setSelectMode] = useState('single');
35
+ const selectResolvers = useRef(void 0);
36
36
  useImperativeHandle(ref, () => ({
37
- open(row) {
37
+ open(row, initialFormValue) {
38
38
  innerFormRef.current?.resetForm();
39
- setInnerOpen(true);
39
+ suppressTransform.current = !!initialFormValue;
40
+ initialFormValue && innerFormRef.current?.setFormValue(initialFormValue);
40
41
  setActiveRow(row);
41
- const { promise } = resolvers.current = Promise.withResolvers();
42
+ setInnerOpen(true);
43
+ const { promise } = openResolvers.current = Promise.withResolvers();
44
+ return promise;
45
+ },
46
+ selectSingle() {
47
+ isCopying.current = false;
48
+ setSelectMode('single');
49
+ pickerDialogRef.current.open().then();
50
+ const { promise } = selectResolvers.current = Promise.withResolvers();
42
51
  return promise;
52
+ },
53
+ selectMultiple(selected) {
54
+ isCopying.current = false;
55
+ setSelectMode('multiple');
56
+ return pickerDialogRef.current.open(selected);
43
57
  }
44
58
  }));
45
59
  /**
@@ -47,13 +61,14 @@ curdProps, ...props }) => {
47
61
  * 表单项
48
62
  */
49
63
  const [activeRow, setActiveRow] = useState();
64
+ const suppressTransform = useRef(false);
50
65
  const [transforming, setFormValue] = useLoading(async (row) => {
51
- const formValue = postData && row ? await postData(row) : row;
66
+ const formValue = rowToForm && row ? await rowToForm(row) : row;
52
67
  formValue && innerFormRef.current?.setFormValue(formValue);
53
68
  });
54
69
  useEffect(() => {
55
- innerOpen.current && setFormValue(activeRow);
56
- }, [innerOpen.current]); // 依赖innerOpen而不依赖activeRow的原因是,有可能连续两次打开的activeRow是相同的
70
+ innerOpen.current && !suppressTransform.current && setFormValue(activeRow);
71
+ }, [innerOpen.current, activeRow]);
57
72
  const renderedFormItems = useMemo(() => {
58
73
  return columnsToFormItem(columns, activeRow)?.map(col => {
59
74
  if (isValidElement(col)) {
@@ -72,7 +87,7 @@ curdProps, ...props }) => {
72
87
  };
73
88
  const [innerLoading, finishHandler] = useLoading(async (value) => {
74
89
  formProps?.onFinish?.(value);
75
- resolvers.current?.resolve(value);
90
+ openResolvers.current?.resolve(value);
76
91
  await onFinish?.(value);
77
92
  setInnerOpen(false);
78
93
  }, props.confirmLoading);
@@ -80,20 +95,32 @@ curdProps, ...props }) => {
80
95
  * ----------------------------------------------------------------
81
96
  * 复制
82
97
  */
98
+ const isCopying = useRef(false);
83
99
  const pickerDialogRef = useRef(null);
84
- const copiedHandler = (checked, value, row) => {
85
- const title = !isUnset(titleKey) ? row[titleKey] : void 0;
86
- typeof title === 'string'
87
- ? setFormValue({
88
- ...row,
89
- [titleKey]: `${title} - 副本`
90
- })
91
- : setFormValue(row);
100
+ const onCopyButtonClick = () => {
101
+ isCopying.current = true;
102
+ setSelectMode('single');
103
+ pickerDialogRef.current.open().then();
104
+ };
105
+ const toggleHandler = (checked, value, row) => {
106
+ if (isCopying.current) {
107
+ const title = !isUnset(titleKey) ? row[titleKey] : void 0;
108
+ typeof title === 'string'
109
+ ? setFormValue({
110
+ ...row,
111
+ [titleKey]: `${title} - 副本`
112
+ })
113
+ : setFormValue(row);
114
+ }
115
+ else {
116
+ // 处理selectSingle
117
+ selectResolvers.current?.resolve(row);
118
+ }
92
119
  };
93
120
  const rowTitle = activeRow && !isUnset(titleKey) ? activeRow[titleKey] : void 0;
94
121
  return (_jsxs(Dialog, { css: dialogStyle, width: 600, title: activeRow
95
122
  ? `${updateName}${dataName}${rowTitle ? ' - ' + rowTitle : ''}`
96
123
  : _jsxs("div", { className: classes.dialogTitle, children: [_jsxs("span", { children: [createName, dataName] }), copyable &&
97
- _jsxs(Button, { variant: "plain", prefix: _jsx(Icon, { icon: faCopy }), onClick: () => pickerDialogRef.current.open(), children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [_jsx(Loading, { open: transforming.current, children: _jsx(Form, { labelWidth: "20%", ...formProps, ref: cloneRef(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
98
- _jsx(PickerDialog, { ref: pickerDialogRef, onToggle: copiedHandler, children: _jsx(Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
124
+ _jsxs(Button, { variant: "plain", prefix: _jsx(Icon, { icon: faCopy }), onClick: onCopyButtonClick, children: ["\u4ECE\u5DF2\u6709", dataName || '数据', "\u590D\u5236"] })] }), ...props, open: innerOpen.current, onClose: closeHandler, onConfirm: confirmHandler, confirmLoading: innerLoading.current, children: [_jsx(Loading, { open: transforming.current, children: _jsx(Form, { labelWidth: "20%", ...formProps, ref: cloneRef(formRef, innerFormRef), onFinish: finishHandler, children: renderedFormItems }) }), copyable &&
125
+ _jsx(PickerDialog, { ref: pickerDialogRef, multiple: selectMode === 'multiple', onToggle: toggleHandler, children: _jsx(Curd, { ...curdProps, variant: "embeded", copyable: false, creatable: false, updatable: false, deletable: false }) })] }));
99
126
  });
@@ -13,13 +13,6 @@ export const PickerDialog = (({ ref, dialogRef, multiple, children, showSelected
13
13
  // 以下属性从SelectionContextBaseProps继承
14
14
  options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation = 'dependent', integration = 'shallowest', disabled, clearable = !!multiple, onToggle, ...props }) => {
15
15
  const resolvers = useRef(void 0);
16
- const [innerValue, _setInnerValue] = useState(multiple ? [] : null);
17
- const setInnerValue = (value) => {
18
- _setInnerValue(value);
19
- // 单选模式,值每次改变都触发确认
20
- !multiple && confirmHandler(value);
21
- };
22
- const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
23
16
  useImperativeHandle(ref, () => ({
24
17
  open(value) {
25
18
  _setInnerValue(value ?? null);
@@ -28,6 +21,13 @@ options = rows ?? nodes, primaryKey = 'id', childrenKey = 'children', relation =
28
21
  return promise;
29
22
  }
30
23
  }));
24
+ const [innerValue, _setInnerValue] = useState(multiple ? [] : null);
25
+ const setInnerValue = (value) => {
26
+ _setInnerValue(value);
27
+ // 单选模式,值每次改变都触发确认
28
+ !multiple && confirmHandler(value);
29
+ };
30
+ const [innerOpen, setInnerOpen] = useControlled(props.defaultOpen, props.open);
31
31
  const onCloseHandler = (reason) => {
32
32
  if (reason === 'confirmed') {
33
33
  return;